diff --git a/po/pamac.pot b/po/pamac.pot index 220a60c..92a28a1 100644 --- a/po/pamac.pot +++ b/po/pamac.pot @@ -76,6 +76,16 @@ msgstr "" msgid "%s: requires %s" msgstr "" +#: ../src/daemon.vala +#, c-format +msgid "%s: installing %s (%s) breaks dependency '%s'" +msgstr "" + +#: ../src/daemon.vala +#, c-format +msgid "%s: removing %s breaks dependency '%s'" +msgstr "" + #: ../src/daemon.vala #, c-format msgid "%s and %s are in conflict" @@ -119,6 +129,10 @@ msgstr "" msgid "A Gtk3 frontend for libalpm" msgstr "" +#: ../src/transaction.vala +msgid "Copy" +msgstr "" + #: ../src/transaction.vala msgid "Refreshing mirrors list" msgstr "" @@ -169,7 +183,8 @@ msgid "Total download size" msgstr "" #: ../src/transaction.vala -msgid "Building packages" +#, c-format +msgid "Building %s" msgstr "" #: ../src/transaction.vala @@ -349,11 +364,11 @@ msgstr "" msgid "Your system is up-to-date" msgstr "" -#: ../src/tray.vala +#: ../src/tray.vala ../src/updater_window.vala msgid "Update Manager" msgstr "" -#: ../src/tray.vala +#: ../src/tray.vala ../src/manager_window.vala msgid "Package Manager" msgstr "" @@ -536,6 +551,10 @@ msgstr "" msgid "How often to check for updates, value in hours" msgstr "" +#: ../src/preferences_dialog.vala ../resources/preferences_dialog.ui +msgid "Number of versions of each package to keep in the cache" +msgstr "" + #: ../src/preferences_dialog.vala msgid "Worldwide" msgstr "" @@ -593,10 +612,6 @@ msgstr "" msgid "Search" msgstr "" -#: ../resources/manager_window.ui -msgid "Search in AUR" -msgstr "" - #: ../resources/manager_window.ui ../resources/updater_window.ui msgid "State" msgstr "" @@ -711,14 +726,6 @@ msgstr "" msgid "Check for updates from AUR" msgstr "" -#: ../resources/preferences_dialog.ui -msgid "Do not ask for confirmation when building packages" -msgstr "" - -#: ../resources/preferences_dialog.ui -msgid "Number of versions of each package to keep in the cache" -msgstr "" - #: ../resources/preferences_dialog.ui msgid "Remove only the versions of uninstalled packages" msgstr "" diff --git a/resources/preferences_dialog.ui b/resources/preferences_dialog.ui index 19eabc4..bf50579 100644 --- a/resources/preferences_dialog.ui +++ b/resources/preferences_dialog.ui @@ -638,24 +638,6 @@ All AUR users should be familiar with the build process. 3 - - - Do not ask for confirmation when building packages - True - True - False - start - 24 - 24 - True - True - - - False - True - 4 - - aur diff --git a/src/common.vala b/src/common.vala index 3dc81ce..dbdb99c 100644 --- a/src/common.vala +++ b/src/common.vala @@ -32,6 +32,9 @@ namespace Pamac { public UpdateInfos[] to_downgrade; public UpdateInfos[] to_reinstall; public UpdateInfos[] to_remove; + public UpdateInfos[] to_build; + public UpdateInfos[] aur_conflicts_to_remove; + public string[] aur_pkgbases_to_build; } public struct Updates { diff --git a/src/daemon.vala b/src/daemon.vala index d4afa41..66dbda0 100644 --- a/src/daemon.vala +++ b/src/daemon.vala @@ -105,7 +105,15 @@ namespace Pamac { private string[] to_install; private string[] to_remove; private string[] to_load; + private string[] to_build; + private UpdateInfos[] to_build_infos; + private GLib.List aur_pkgbases_to_build; + private GenericSet aur_desc_list; + private GenericSet already_checked_aur_dep; + private HashTable to_install_as_dep; + private string aurdb_path; private string[] temporary_ignorepkgs; + private UpdateInfos[] aur_conflicts_to_remove; private ThreadPool thread_pool; private Mutex databases_lock_mutex; private Json.Array aur_updates_results; @@ -116,7 +124,6 @@ namespace Pamac { private ErrorInfos current_error; public Timer timer; public Cancellable cancellable; - private GLib.List aur_dep_list; public signal void emit_event (uint primary_event, uint secondary_event, string[] details); public signal void emit_providers (string depend, string[] providers); @@ -131,8 +138,7 @@ namespace Pamac { public signal void trans_commit_finished (bool success); public signal void get_authorization_finished (bool authorized); public signal void write_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon, - bool enable_aur, bool search_aur, bool check_aur_updates, - bool no_confirm_build); + bool enable_aur, bool search_aur, bool check_aur_updates); public signal void write_alpm_config_finished (bool checkspace); public signal void write_mirrors_config_finished (string choosen_country, string choosen_generation_method); public signal void generate_mirrors_list_data (string line); @@ -141,6 +147,11 @@ namespace Pamac { public Daemon () { alpm_config = new AlpmConfig ("/etc/pacman.conf"); databases_lock_mutex = Mutex (); + aur_pkgbases_to_build = new GLib.List (); + aur_desc_list = new GenericSet (str_hash, str_equal); + already_checked_aur_dep = new GenericSet (str_hash, str_equal); + to_install_as_dep = new HashTable (str_hash, str_equal); + aurdb_path = "/tmp/pamac-aur"; aur_updates_results = new Json.Array (); aur_search_results = new HashTable (str_hash, str_equal); aur_infos = new HashTable (str_hash, str_equal); @@ -290,8 +301,7 @@ namespace Pamac { pamac_config.reload (); } write_pamac_config_finished (pamac_config.recurse, pamac_config.refresh_period, pamac_config.no_update_hide_icon, - pamac_config.enable_aur, pamac_config.search_aur, pamac_config.check_aur_updates, - pamac_config.no_confirm_build); + pamac_config.enable_aur, pamac_config.search_aur, pamac_config.check_aur_updates); }); } @@ -847,85 +857,171 @@ namespace Pamac { return details; } - public async string[] get_aur_build_list (string pkgname) { - string[] results = {}; - aur_dep_list = new GLib.List (); - bool success = yield set_aur_dep_list (pkgname); - if (success) { - foreach (unowned string name in aur_dep_list) { - results += name; - } + private async void compute_aur_build_list (string[] aur_list) { + try { + Process.spawn_command_line_sync ("mkdir -p %s".printf (aurdb_path)); + } catch (SpawnError e) { + stderr.printf ("SpawnError: %s\n", e.message); } - return results; + aur_desc_list.remove_all (); + already_checked_aur_dep.remove_all (); + yield check_aur_dep_list (aur_list); } - private async bool set_aur_dep_list (string pkgname) { - bool success = false; - Json.Array results = yield AUR.multiinfo ({pkgname}); - Json.Object json_object = results.get_object_element (0); - if (json_object != null) { - success = true; - // add aur pkg to global list or move it to the end of the list; - unowned GLib.List element = aur_dep_list.find_custom (pkgname, strcmp); - if (element == null) { - aur_dep_list.append (pkgname); - } else { - aur_dep_list.delete_link (element); - aur_dep_list.append (pkgname); - } - unowned Json.Node? node = json_object.get_member ("MakeDepends"); - if (node != null) { - GLib.List list = node.get_array ().get_elements (); - foreach (unowned Json.Node? _node in list) { - unowned string depstring = _node.get_string (); - if (Alpm.find_satisfier (alpm_handle.localdb.pkgcache, depstring) == null) { - if (find_dbs_satisfier (depstring) == null) { - success = yield set_aur_dep_list (depstring); - } - } - if (!success) { - break; - } - } - } - if (success) { - node = json_object.get_member ("Depends"); - if (node != null) { - GLib.List list = node.get_array ().get_elements (); - foreach (unowned Json.Node? _node in list) { - unowned string depstring = _node.get_string (); - if (Alpm.find_satisfier (alpm_handle.localdb.pkgcache, depstring) == null) { - if (find_dbs_satisfier (depstring) == null) { - success = yield set_aur_dep_list (depstring); - } - } - if (!success) { - break; - } - } - } - } - if (success) { - node = json_object.get_member ("CheckDepends"); - if (node != null) { - GLib.List list = node.get_array ().get_elements (); - foreach (unowned Json.Node? _node in list) { - unowned string depstring = _node.get_string (); - if (Alpm.find_satisfier (alpm_handle.localdb.pkgcache, depstring) == null) { - if (find_dbs_satisfier (depstring) == null) { - success = yield set_aur_dep_list (depstring); - } - } - if (!success) { - break; - } - } - } - } + private string splitdep (string depstring) { + // split depmod and version from name + string result; + string[] splitted = depstring.split (">", 2); + if (splitted.length > 1) { + result = splitted[0]; } else { - stdout.printf ("can't find %s in AUR\n", pkgname); + splitted = depstring.split ("<", 2); + if (splitted.length > 1) { + result = splitted[0]; + } else { + splitted = depstring.split ("=", 2); + if (splitted.length > 1) { + result = splitted[0]; + } else { + result = depstring; + } + } + } + return result; + } + + private async void check_aur_dep_list (string[] pkgnames) { + string[] dep_types = {"Depends", "MakeDepends", "CheckDepends"}; + string[] dep_to_check = {}; + Json.Array results = yield AUR.multiinfo (pkgnames); + results.foreach_element ((array, index, node) => { + unowned Json.Object? pkg_info = node.get_object (); + // create fake db desc file + if (pkg_info != null) { + string name = pkg_info.get_string_member ("Name"); + string version = pkg_info.get_string_member ("Version"); + string pkgdir = "%s-%s".printf (name, version); + string pkgdir_path = "%s/%s".printf (aurdb_path, pkgdir); + aur_desc_list.add (pkgdir); + already_checked_aur_dep.add (name); + try { + var file = GLib.File.new_for_path (pkgdir_path); + bool write_desc_file = false; + if (!file.query_exists ()) { + file.make_directory (); + write_desc_file = true; + } + // compute depends, makedepends and checkdepends in DEPENDS + var depends = new StringBuilder (); + foreach (unowned string dep_type in dep_types) { + unowned Json.Node? dep_node = pkg_info.get_member (dep_type); + if (dep_node != null) { + dep_node.get_array ().foreach_element ((array, index, node) => { + if (write_desc_file) { + depends.append (node.get_string ()); + depends.append ("\n"); + } + // check deps + unowned string dep_string = node.get_string (); + string dep_name = splitdep (dep_string); + unowned Alpm.Package? pkg = null; + // search for the name first to avoid provides trouble + pkg = alpm_handle.localdb.get_pkg (dep_name); + if (pkg == null) { + pkg = get_syncpkg (dep_name); + } + if (pkg == null) { + if (!(dep_name in already_checked_aur_dep)) { + dep_to_check += (owned) dep_name; + } + } + }); + } + } + if (write_desc_file) { + file = GLib.File.new_for_path ("%s/desc".printf (pkgdir_path)); + // creating a DataOutputStream to the file + var dos = new DataOutputStream (file.create (FileCreateFlags.REPLACE_DESTINATION)); + // fake filename + dos.put_string ("%FILENAME%\n" + "%s-%s-any.pkg.tar.xz\n\n".printf (name, version)); + // name + dos.put_string ("%NAME%\n%s\n\n".printf (name)); + // version + dos.put_string ("%VERSION%\n%s\n\n".printf (version)); + //base + dos.put_string ("%BASE%\n%s\n\n".printf (pkg_info.get_string_member ("PackageBase"))); + // desc can be null + if (!pkg_info.get_null_member ("Description")) { + dos.put_string ("%DESC%\n%s\n\n".printf (pkg_info.get_string_member ("Description"))); + } + // version + dos.put_string ("%VERSION%\n%s\n\n".printf (pkg_info.get_string_member ("Version"))); + // fake arch + dos.put_string ("%ARCH%\nany\n\n"); + // depends + if (depends.len > 0) { + dos.put_string ("%DEPENDS%\n%s\n".printf (depends.str)); + } + // conflicts + unowned Json.Node? info_node = pkg_info.get_member ("Conflicts"); + if (info_node != null) { + try { + dos.put_string ("%CONFLICTS%\n"); + info_node.get_array ().foreach_element ((array, index, _node) => { + try { + dos.put_string ("%s\n".printf (_node.get_string ())); + } catch (GLib.Error e) { + GLib.stderr.printf("%s\n", e.message); + } + }); + dos.put_string ("\n"); + } catch (GLib.Error e) { + GLib.stderr.printf("%s\n", e.message); + } + } + // provides + info_node = pkg_info.get_member ("Provides"); + if (info_node != null) { + try { + dos.put_string ("%PROVIDES%\n"); + info_node.get_array ().foreach_element ((array, index, _node) => { + try { + dos.put_string ("%s\n".printf (_node.get_string ())); + } catch (GLib.Error e) { + GLib.stderr.printf("%s\n", e.message); + } + }); + dos.put_string ("\n"); + } catch (GLib.Error e) { + GLib.stderr.printf("%s\n", e.message); + } + } + // replaces + info_node = pkg_info.get_member ("Replaces"); + if (info_node != null) { + try { + dos.put_string ("%REPLACES%\n"); + info_node.get_array ().foreach_element ((array, index, _node) => { + try { + dos.put_string ("%s\n".printf (_node.get_string ())); + } catch (GLib.Error e) { + GLib.stderr.printf("%s\n", e.message); + } + }); + dos.put_string ("\n"); + } catch (GLib.Error e) { + GLib.stderr.printf("%s\n", e.message); + } + } + } + } catch (GLib.Error e) { + GLib.stderr.printf("%s\n", e.message); + } + } + }); + if (dep_to_check.length > 0) { + yield check_aur_dep_list (dep_to_check); } - return success; } public string[] get_repos_names () { @@ -1362,27 +1458,27 @@ namespace Pamac { private void sysupgrade_prepare () { current_error = ErrorInfos (); - if (!trans_init (0)) { - if (cancellable.is_cancelled ()) { - trans_prepare_finished (true); + bool success = trans_init (0); + if (success) { + add_ignorepkgs (); + if (alpm_handle.trans_sysupgrade ((enable_downgrade) ? 1 : 0) == -1) { + Alpm.Errno errno = alpm_handle.errno (); + current_error.errno = (uint) errno; + current_error.message = _("Failed to prepare transaction"); + if (errno != 0) { + current_error.details = { Alpm.strerror (errno) }; + } + trans_release (); + success = false; } else { - trans_prepare_finished (false); + success = trans_prepare_real (); } - return; - } - add_ignorepkgs (); - if (alpm_handle.trans_sysupgrade ((enable_downgrade) ? 1 : 0) == -1) { - Alpm.Errno errno = alpm_handle.errno (); - current_error.errno = (uint) errno; - current_error.message = _("Failed to prepare transaction"); - if (errno != 0) { - current_error.details = { Alpm.strerror (errno) }; + } else { + if (cancellable.is_cancelled ()) { + success = true; } - trans_release (); - trans_prepare_finished (false); - return; } - trans_prepare_real (); + trans_prepare_finished (success); } public void start_sysupgrade_prepare_ (bool enable_downgrade_, string[] temporary_ignorepkgs_) { @@ -1515,7 +1611,8 @@ namespace Pamac { return true; } - private void trans_prepare_real () { + private bool trans_prepare_real () { + bool success = true; current_error = ErrorInfos (); string[] details = {}; Alpm.List err_data; @@ -1541,7 +1638,23 @@ namespace Pamac { unowned Alpm.List list = err_data; while (list != null) { Alpm.DepMissing* miss = list.data; - details += _("%s: requires %s").printf (miss->target, miss->depend.compute_string ()); + string depstring = miss->depend.compute_string (); + unowned Alpm.List trans_add = alpm_handle.trans_to_add (); + unowned Alpm.Package pkg; + string detail; + if (miss->causingpkg == null) { + /* package being installed/upgraded has unresolved dependency */ + detail = _("%s: requires %s").printf (miss->target, depstring); + } else if ((pkg = Alpm.pkg_find (trans_add, miss->causingpkg)) != null) { + /* upgrading a package breaks a local dependency */ + detail = _("%s: installing %s (%s) breaks dependency '%s'").printf (miss->target, miss->causingpkg, pkg.version, depstring); + } else { + /* removing a package breaks a local dependency */ + detail = _("%s: removing %s breaks dependency '%s'").printf (miss->target, miss->causingpkg, depstring); + } + if (!(detail in details)) { + details += detail; + } delete miss; list.next (); } @@ -1567,7 +1680,7 @@ namespace Pamac { } current_error.details = (owned) details; trans_release (); - trans_prepare_finished (false); + success = false; } else { // Search for holdpkg in target list bool found_locked_pkg = false; @@ -1585,11 +1698,10 @@ namespace Pamac { current_error.message = _("Failed to prepare transaction"); current_error.details = (owned) details; trans_release (); - trans_prepare_finished (false); - } else { - trans_prepare_finished (true); + success = false; } } + return success; } private void trans_prepare () { @@ -1618,16 +1730,188 @@ namespace Pamac { } } if (success) { - trans_prepare_real (); + success = trans_prepare_real (); } else { trans_release (); - trans_prepare_finished (false); } } else { if (cancellable.is_cancelled ()) { - trans_prepare_finished (true); + success = true; + } + } + trans_prepare_finished (success); + } + + private void build_prepare () { + // create a fake aur db + try { + var list = new StringBuilder (); + foreach (unowned string name_version in aur_desc_list) { + list.append (name_version); + list.append (" "); + } + Process.spawn_command_line_sync ("rm -f %ssync/aur.db".printf (alpm_handle.dbpath)); + Process.spawn_command_line_sync ("bsdtar -cf %ssync/aur.db -C %s %s".printf (alpm_handle.dbpath, aurdb_path, list.str)); + } catch (SpawnError e) { + stderr.printf ("SpawnError: %s\n", e.message); + } + // get an handle without emit signal callbacks AND fake aur db + alpm_handle = alpm_config.get_handle (); + if (alpm_handle == null) { + current_error = ErrorInfos () { + message = _("Failed to initialize alpm library") + }; + trans_commit_finished (false); + } else { + alpm_handle.questioncb = (Alpm.QuestionCallBack) cb_question; + alpm_handle.logcb = (Alpm.LogCallBack) cb_log; + lockfile = GLib.File.new_for_path (alpm_handle.lockfile); + // fake aur db + alpm_handle.register_syncdb ("aur", Alpm.Signature.Level.PACKAGE_OPTIONAL | Alpm.Signature.Level.DATABASE_OPTIONAL); + // add to_build in to_install for the fake trans prpeapre + foreach (unowned string name in to_build) { + to_install += name; + } + // check base-devel group needed to build pkgs + var backup_to_remove = new GenericSet (str_hash, str_equal); + foreach (unowned string name in to_remove) { + backup_to_remove.add (name); + } + unowned Alpm.List syncdbs = alpm_handle.syncdbs; + while (syncdbs != null) { + unowned Alpm.DB db = syncdbs.data; + unowned Alpm.Group? grp = db.get_group ("base-devel"); + if (grp != null) { + unowned Alpm.List packages = grp.packages; + while (packages != null) { + unowned Alpm.Package pkg = packages.data; + if (alpm_handle.localdb.get_pkg (pkg.name) == null) { + to_install += pkg.name; + } else { + // remove the needed pkg from to_remove + backup_to_remove.remove (pkg.name); + } + packages.next (); + } + } + syncdbs.next (); + } + // check git needed to build pkgs + if (alpm_handle.localdb.get_pkg ("git") == null) { + to_install += "git"; } else { - trans_prepare_finished (false); + // remove the needed pkg from to_remove + backup_to_remove.remove ("git"); + } + to_remove = {}; + foreach (unowned string name in backup_to_remove) { + to_remove += name; + } + // fake trans prepare + bool success = trans_init (flags); + if (success) { + foreach (unowned string name in to_install) { + success = trans_add_pkg (name); + if (!success) { + break; + } + } + if (success) { + foreach (unowned string name in to_remove) { + success = trans_remove_pkg (name); + if (!success) { + break; + } + } + } + if (success) { + foreach (unowned string path in to_load) { + success = trans_load_pkg (path); + if (!success) { + break; + } + } + } + if (success) { + success = trans_prepare_real (); + if (success) { + // check trans preparation result + string[] real_to_install = {}; + unowned Alpm.List pkgs_to_add = alpm_handle.trans_to_add (); + while (pkgs_to_add != null) { + unowned Alpm.Package trans_pkg = pkgs_to_add.data; + unowned Alpm.DB? db = trans_pkg.db; + if (db != null) { + if (db.name == "aur") { + // it is a aur pkg to build + aur_pkgbases_to_build.append (trans_pkg.pkgbase); + var infos = UpdateInfos () { + name = trans_pkg.name, + old_version = "", + new_version = trans_pkg.version, + repo = "", + download_size = 0 + }; + to_build_infos += (owned) infos; + if (!(trans_pkg.name in to_build)) { + to_install_as_dep.insert (trans_pkg.name, trans_pkg.name); + } + } else { + // it is a pkg to install + real_to_install += trans_pkg.name; + if (!(trans_pkg.name in to_install)) { + to_install_as_dep.insert (trans_pkg.name, trans_pkg.name); + } + } + } + pkgs_to_add.next (); + } + aur_conflicts_to_remove = {}; + unowned Alpm.List pkgs_to_remove = alpm_handle.trans_to_remove (); + while (pkgs_to_remove != null) { + unowned Alpm.Package trans_pkg = pkgs_to_remove.data; + // it is a pkg to remove + if (!(trans_pkg.name in to_remove)) { + var infos = UpdateInfos () { + name = trans_pkg.name, + old_version = trans_pkg.version, + new_version = "", + repo = "", + download_size = 0 + }; + aur_conflicts_to_remove += (owned) infos; + } + pkgs_to_remove.next (); + } + trans_release (); + try { + Process.spawn_command_line_sync ("rm -f %ssync/aur.db".printf (alpm_handle.dbpath)); + } catch (SpawnError e) { + stderr.printf ("SpawnError: %s\n", e.message); + } + // get standard handle + refresh_handle (); + // launch standard prepare + to_install = real_to_install; + trans_prepare (); + } else { + // get standard handle + refresh_handle (); + trans_prepare_finished (false); + } + } else { + trans_release (); + // get standard handle + refresh_handle (); + trans_prepare_finished (false); + } + } else { + if (cancellable.is_cancelled ()) { + success = true; + } + // get standard handle + refresh_handle (); + trans_prepare_finished (success); } } } @@ -1635,15 +1919,29 @@ namespace Pamac { public void start_trans_prepare (Alpm.TransFlag flags_, string[] to_install_, string[] to_remove_, - string[] to_load_) { + string[] to_load_, + string[] to_build_) { flags = flags_; to_install = to_install_; to_remove = to_remove_; to_load = to_load_; - try { - thread_pool.add (new AlpmAction (trans_prepare)); - } catch (ThreadError e) { - stderr.printf ("Thread Error %s\n", e.message); + to_build = to_build_; + to_build_infos = {}; + aur_pkgbases_to_build = new GLib.List (); + if (to_build.length != 0) { + compute_aur_build_list.begin (to_build, (obj, res) => { + try { + thread_pool.add (new AlpmAction (build_prepare)); + } catch (ThreadError e) { + stderr.printf ("Thread Error %s\n", e.message); + } + }); + } else { + try { + thread_pool.add (new AlpmAction (trans_prepare)); + } catch (ThreadError e) { + stderr.printf ("Thread Error %s\n", e.message); + } } } @@ -1698,12 +1996,24 @@ namespace Pamac { to_remove += (owned) infos; pkgs_to_remove.next (); } + UpdateInfos[] conflicts_to_remove = {}; + foreach (unowned UpdateInfos infos in aur_conflicts_to_remove){ + conflicts_to_remove += infos; + } + aur_conflicts_to_remove = {}; + string[] pkgbases_to_build = {}; + foreach (unowned string name in aur_pkgbases_to_build) { + pkgbases_to_build += name; + } var summary = TransactionSummary () { to_install = (owned) to_install, to_upgrade = (owned) to_upgrade, to_downgrade = (owned) to_downgrade, to_reinstall = (owned) to_reinstall, - to_remove = (owned) to_remove + to_remove = (owned) to_remove, + to_build = to_build_infos, + aur_conflicts_to_remove = conflicts_to_remove, + aur_pkgbases_to_build = pkgbases_to_build }; return summary; } @@ -1770,6 +2080,19 @@ namespace Pamac { } trans_release (); refresh_handle (); + bool need_refresh = false; + to_install_as_dep.foreach_remove ((pkgname, val) => { + unowned Alpm.Package? pkg = alpm_handle.localdb.get_pkg (pkgname); + if (pkg != null) { + pkg.reason = Alpm.Package.Reason.DEPEND; + need_refresh = true; + return true; // remove current pkgname + } + return false; + }); + if (need_refresh) { + refresh_handle (); + } trans_commit_finished (success); } @@ -1937,8 +2260,8 @@ private void cb_question (Alpm.Question.Data data) { data.conflict_remove = 1; break; case Alpm.Question.Type.REMOVE_PKGS: - // Do not upgrade packages which have unresolvable dependencies - data.remove_pkgs_skip = 1; + // Return an error if there are top-level packages which have unresolvable dependencies + data.remove_pkgs_skip = 0; break; case Alpm.Question.Type.SELECT_PROVIDER: string depend_str = data.select_provider_depend.compute_string (); @@ -2087,7 +2410,7 @@ private int cb_fetch (string fileurl, string localpath, int force) { Posix.FILE localf = Posix.FILE.open (tempfile.get_path (), open_mode); if (localf == null) { - stdout.printf ("could not open file %s\n", tempfile.get_path ()); + stderr.printf ("could not open file %s\n", tempfile.get_path ()); return -1; } diff --git a/src/installer.vala b/src/installer.vala index adea881..c565ca6 100644 --- a/src/installer.vala +++ b/src/installer.vala @@ -55,7 +55,7 @@ namespace Pamac { transaction.important_details_outpout.connect (on_important_details_outpout); progress_dialog.box.pack_start (transaction.progress_box); progress_dialog.box.reorder_child (transaction.progress_box, 0); - progress_dialog.expander.add (transaction.term_grid); + progress_dialog.expander.add (transaction.term_window); progress_dialog.close_button.clicked.connect (on_close_button_clicked); progress_dialog.close_button.visible = false; this.hold (); diff --git a/src/manager_window.vala b/src/manager_window.vala index 6f0dc02..f1d82cf 100644 --- a/src/manager_window.vala +++ b/src/manager_window.vala @@ -151,6 +151,7 @@ namespace Pamac { transaction_running = false; generate_mirrors_list = false; + this.title = dgettext (null, "Package Manager"); Timeout.add (100, populate_window); } @@ -277,6 +278,7 @@ namespace Pamac { transaction = new Transaction (this as Gtk.ApplicationWindow); transaction.mode = Mode.MANAGER; transaction.start_transaction.connect (on_start_transaction); + transaction.start_building.connect (on_start_building); transaction.important_details_outpout.connect (on_important_details_outpout); transaction.finished.connect (on_transaction_finished); transaction.write_pamac_config_finished.connect (on_write_pamac_config_finished); @@ -284,13 +286,10 @@ namespace Pamac { transaction.generate_mirrors_list.connect (on_generate_mirrors_list); // integrate progress box and term widget - main_stack.add_named (transaction.term_grid, "term"); + main_stack.add_named (transaction.term_window, "term"); transaction_infobox.pack_start (transaction.progress_box); - AlpmPackage pkg = transaction.find_installed_satisfier ("yaourt"); - if (pkg.name != "") { - support_aur (transaction.enable_aur); - } + support_aur (transaction.enable_aur); display_package_queue = new Queue (); @@ -307,16 +306,18 @@ namespace Pamac { void on_write_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon, bool enable_aur, bool search_aur) { - AlpmPackage pkg = transaction.find_installed_satisfier ("yaourt"); - if (pkg.name != "") { - support_aur (enable_aur); - } + support_aur (enable_aur); } void on_set_pkgreason_finished () { refresh_packages_list (); if (main_stack.visible_child_name == "details") { - display_package_properties (current_package_displayed); + if (transaction.get_installed_pkg (current_package_displayed).name != "" + || transaction.get_sync_pkg (current_package_displayed).name != "") { + display_package_properties (current_package_displayed); + } else { + display_aur_properties (current_package_displayed); + } } } @@ -335,14 +336,16 @@ namespace Pamac { uint total_pending = transaction.to_install.length + transaction.to_remove.length + transaction.to_build.length; if (total_pending == 0) { transaction.progress_box.action_label.label = ""; + cancel_button.sensitive = false; + apply_button.sensitive = false; if (important_details) { transaction_infobox.show_all (); - } else { - transaction_infobox.visible = false; } } else { string info = dngettext (null, "%u pending operation", "%u pending operations", total_pending).printf (total_pending); transaction.progress_box.action_label.label = info; + cancel_button.sensitive = true; + apply_button.sensitive = true; // fix an possible visibility issue transaction_infobox.show_all (); } @@ -413,6 +416,7 @@ namespace Pamac { details_grid.attach_next_to (box, label, Gtk.PositionType.RIGHT); } else { var label2 = new Gtk.Label (detail); + label2.use_markup = true; label2.halign = Gtk.Align.START; details_grid.attach_next_to (label2, label, Gtk.PositionType.RIGHT); } @@ -541,7 +545,16 @@ namespace Pamac { details_grid.attach_next_to (box, label, Gtk.PositionType.RIGHT); previous_widget = label as Gtk.Widget; } - previous_widget = populate_details_grid (dgettext (null, "Packager"), details.packager, previous_widget); + // make packager mail clickable + string[] splitted = details.packager.split ("<", 2); + string packager_name = splitted[0]; + if (splitted.length > 1) { + string packager_mail = splitted[1].split (">", 2)[0]; + string packager_detail = "%s %s".printf (packager_name, packager_mail, packager_mail); + previous_widget = populate_details_grid (dgettext (null, "Packager"), packager_detail, previous_widget); + } else { + previous_widget = populate_details_grid (dgettext (null, "Packager"), details.packager, previous_widget); + } previous_widget = populate_details_grid (dgettext (null, "Build Date"), details.builddate, previous_widget); if (details.installdate != "") { previous_widget = populate_details_grid (dgettext (null, "Install Date"), details.installdate, previous_widget); @@ -863,7 +876,7 @@ namespace Pamac { void display_aur_properties (string pkgname) { current_package_displayed = pkgname; files_scrolledwindow.visible = false; - set_aur_details (pkgname); + set_aur_details (current_package_displayed); } [GtkCallback] @@ -1480,11 +1493,18 @@ namespace Pamac { case "browse": button_back.visible = false; filters_stackswitcher.visible = true; + details_button.sensitive = true; break; case "details": + button_back.visible = true; + filters_stackswitcher.visible = false; + details_button.sensitive = true; + break; case "term": filters_stackswitcher.visible = false; button_back.visible = true; + details_button.get_style_context ().remove_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); + details_button.sensitive = false; break; default: break; @@ -1555,7 +1575,6 @@ namespace Pamac { [GtkCallback] void on_details_button_clicked () { - details_button.get_style_context ().remove_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); important_details = false; if (transaction_running) { main_stack.visible_child_name = "term"; @@ -1597,7 +1616,12 @@ namespace Pamac { set_pendings_operations (); refresh_packages_list (); if (main_stack.visible_child_name == "details") { - display_package_properties (current_package_displayed); + if (transaction.get_installed_pkg (current_package_displayed).name != "" + || transaction.get_sync_pkg (current_package_displayed).name != "") { + display_package_properties (current_package_displayed); + } else { + display_aur_properties (current_package_displayed); + } } while (Gtk.events_pending ()) { Gtk.main_iteration (); @@ -1618,6 +1642,10 @@ namespace Pamac { cancel_button.sensitive = false; } + void on_start_building () { + cancel_button.sensitive = true; + } + void on_important_details_outpout (bool must_show) { if (must_show) { main_stack.visible_child_name = "term"; @@ -1637,7 +1665,12 @@ namespace Pamac { void on_transaction_finished (bool success) { refresh_packages_list (); if (main_stack.visible_child_name == "details") { - display_package_properties (current_package_displayed); + if (transaction.get_installed_pkg (current_package_displayed).name != "" + || transaction.get_sync_pkg (current_package_displayed).name != "") { + display_package_properties (current_package_displayed); + } else { + display_aur_properties (current_package_displayed); + } } else if (main_stack.visible_child_name == "term") { button_back.visible = true; } @@ -1646,15 +1679,11 @@ namespace Pamac { if (success) { transaction_running = true; transaction.sysupgrade (false); - } else { - apply_button.sensitive = true; } refreshing = false; } else { transaction_running = false; generate_mirrors_list = false; - cancel_button.sensitive = true; - apply_button.sensitive = true; } set_pendings_operations (); } diff --git a/src/pamac_config.vala b/src/pamac_config.vala index 4628a76..a0116d4 100644 --- a/src/pamac_config.vala +++ b/src/pamac_config.vala @@ -28,7 +28,6 @@ namespace Pamac { public bool enable_aur { get; private set; } public bool search_aur { get; private set; } public bool check_aur_updates { get; private set; } - public bool no_confirm_build { get; private set; } public unowned HashTable environment_variables { get { return _environment_variables; @@ -73,7 +72,6 @@ namespace Pamac { enable_aur = false; search_aur = false; check_aur_updates = false; - no_confirm_build = false; parse_file (conf_path); } @@ -113,8 +111,6 @@ namespace Pamac { search_aur = true; } else if (key == "CheckAURUpdates") { check_aur_updates = true; - } else if (key == "NoConfirmBuild") { - no_confirm_build = true; } } } catch (GLib.Error e) { @@ -203,17 +199,6 @@ namespace Pamac { } else { data.append (line + "\n"); } - } else if (line.contains ("NoConfirmBuild")) { - if (new_conf.lookup_extended ("NoConfirmBuild", null, out variant)) { - if (variant.get_boolean ()) { - data.append ("NoConfirmBuild\n"); - } else { - data.append ("#NoConfirmBuild\n"); - } - new_conf.remove ("NoConfirmBuild"); - } else { - data.append (line + "\n"); - } } else { data.append (line + "\n"); } @@ -265,12 +250,6 @@ namespace Pamac { } else { data.append ("#CheckAURUpdates\n"); } - } else if (key == "NoConfirmBuild") { - if (val.get_boolean ()) { - data.append ("NoConfirmBuild\n"); - } else { - data.append ("#NoConfirmBuild\n"); - } } } } diff --git a/src/preferences_dialog.vala b/src/preferences_dialog.vala index 5b9edd4..674a0f9 100644 --- a/src/preferences_dialog.vala +++ b/src/preferences_dialog.vala @@ -47,16 +47,12 @@ namespace Pamac { [GtkChild] Gtk.Button generate_mirrors_list_button; [GtkChild] - Gtk.Box aur_config_box; - [GtkChild] Gtk.Switch enable_aur_button; [GtkChild] Gtk.CheckButton search_aur_checkbutton; [GtkChild] Gtk.CheckButton check_aur_updates_checkbutton; [GtkChild] - Gtk.CheckButton no_confirm_build_checkbutton; - [GtkChild] Gtk.Label cache_keep_nb_label; [GtkChild] Gtk.SpinButton cache_keep_nb_spin_button; @@ -132,22 +128,14 @@ namespace Pamac { transaction.write_mirrors_config_finished.connect (on_write_mirrors_config_finished); } - pkg = transaction.find_installed_satisfier ("yaourt"); - if (pkg.name == "") { - aur_config_box.visible = false; - } else { - enable_aur_button.active = transaction.enable_aur; - search_aur_checkbutton.active = transaction.search_aur; - search_aur_checkbutton.sensitive = transaction.enable_aur; - check_aur_updates_checkbutton.active = transaction.check_aur_updates; - check_aur_updates_checkbutton.sensitive = transaction.enable_aur; - no_confirm_build_checkbutton.active = transaction.no_confirm_build; - no_confirm_build_checkbutton.sensitive = transaction.enable_aur; - enable_aur_button.state_set.connect (on_enable_aur_button_state_set); - search_aur_checkbutton.toggled.connect (on_search_aur_checkbutton_toggled); - check_aur_updates_checkbutton.toggled.connect (on_check_aur_updates_checkbutton_toggled); - no_confirm_build_checkbutton.toggled.connect (on_no_confirm_build_checkbutton_toggled); - } + enable_aur_button.active = transaction.enable_aur; + search_aur_checkbutton.active = transaction.search_aur; + search_aur_checkbutton.sensitive = transaction.enable_aur; + check_aur_updates_checkbutton.active = transaction.check_aur_updates; + check_aur_updates_checkbutton.sensitive = transaction.enable_aur; + enable_aur_button.state_set.connect (on_enable_aur_button_state_set); + search_aur_checkbutton.toggled.connect (on_search_aur_checkbutton_toggled); + check_aur_updates_checkbutton.toggled.connect (on_check_aur_updates_checkbutton_toggled); } bool on_remove_unrequired_deps_button_state_set (bool new_state) { @@ -203,15 +191,8 @@ namespace Pamac { transaction.start_write_pamac_config (new_pamac_conf); } - void on_no_confirm_build_checkbutton_toggled () { - var new_pamac_conf = new HashTable (str_hash, str_equal); - new_pamac_conf.insert ("NoConfirmBuild", new Variant.boolean (no_confirm_build_checkbutton.active)); - transaction.start_write_pamac_config (new_pamac_conf); - } - void on_write_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon, - bool enable_aur, bool search_aur, bool check_aur_updates, - bool no_confirm_build) { + bool enable_aur, bool search_aur, bool check_aur_updates) { remove_unrequired_deps_button.state = recurse; if (refresh_period == 0) { check_updates_button.state = false; @@ -234,8 +215,6 @@ namespace Pamac { search_aur_checkbutton.sensitive = enable_aur; check_aur_updates_checkbutton.active = check_aur_updates; check_aur_updates_checkbutton.sensitive = enable_aur; - no_confirm_build_checkbutton.active = no_confirm_build; - no_confirm_build_checkbutton.sensitive = enable_aur; } bool on_check_space_button_state_set (bool new_state) { diff --git a/src/progress_box.vala b/src/progress_box.vala index cabc0aa..ce402b3 100644 --- a/src/progress_box.vala +++ b/src/progress_box.vala @@ -27,7 +27,6 @@ namespace Pamac { [GtkChild] public Gtk.Label action_label; - public ProgressBox () { Object (); } diff --git a/src/transaction.vala b/src/transaction.vala index 1b40a57..922faeb 100644 --- a/src/transaction.vala +++ b/src/transaction.vala @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -const string VERSION = "4.2.0"; +const string VERSION = "4.2.9"; namespace Pamac { [DBus (name = "org.manjaro.pamac")] @@ -46,7 +46,6 @@ namespace Pamac { public abstract AlpmPackage find_sync_satisfier (string depstring) throws IOError; public abstract async AlpmPackage[] search_pkgs (string search_string) throws IOError; public abstract async AURPackage[] search_in_aur (string search_string) throws IOError; - public abstract async string[] get_aur_build_list (string pkgname) throws IOError; public abstract string[] get_repos_names () throws IOError; public abstract async AlpmPackage[] get_repo_pkgs (string repo) throws IOError; public abstract string[] get_groups_names () throws IOError; @@ -56,7 +55,7 @@ namespace Pamac { public abstract string[] get_pkg_uninstalled_optdeps (string pkgname) throws IOError; public abstract void start_get_updates (bool check_aur_updates) throws IOError; public abstract void start_sysupgrade_prepare (bool enable_downgrade, string[] temporary_ignorepkgs) throws IOError; - public abstract void start_trans_prepare (int transflags, string[] to_install, string[] to_remove, string[] to_load) throws IOError; + public abstract void start_trans_prepare (int transflags, string[] to_install, string[] to_remove, string[] to_load, string[] to_build) throws IOError; public abstract void choose_provider (int provider) throws IOError; public abstract TransactionSummary get_transaction_summary () throws IOError; public abstract void start_trans_commit () throws IOError; @@ -78,8 +77,7 @@ namespace Pamac { public signal void trans_commit_finished (bool success); public signal void get_authorization_finished (bool authorized); public signal void write_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon, - bool enable_aur, bool search_aur, bool check_aur_updates, - bool no_confirm_build); + bool enable_aur, bool search_aur, bool check_aur_updates); public signal void write_alpm_config_finished (bool checkspace); public signal void write_mirrors_config_finished (string choosen_country, string choosen_generation_method); public signal void generate_mirrors_list_data (string line); @@ -105,7 +103,6 @@ namespace Pamac { public bool check_aur_updates { get { return pamac_config.check_aur_updates; } } public bool enable_aur { get { return pamac_config.enable_aur; } } public unowned GLib.HashTable environment_variables { get {return pamac_config.environment_variables; } } - public bool no_confirm_build { get { return pamac_config.no_confirm_build; } } public bool no_update_hide_icon { get { return pamac_config.no_update_hide_icon; } } public bool recurse { get { return pamac_config.recurse; } } public uint64 refresh_period { get { return pamac_config.refresh_period; } } @@ -118,6 +115,8 @@ namespace Pamac { public GenericSet to_remove; public GenericSet to_load; public GenericSet to_build; + Queue to_build_queue; + string[] aur_pkgs_to_install; GenericSet previous_to_install; GenericSet previous_to_remove; public GenericSet transaction_summary; @@ -133,6 +132,9 @@ namespace Pamac { uint pulse_timeout_id; bool sysupgrade_after_trans; bool enable_downgrade; + bool no_confirm_commit; + bool build_after_sysupgrade; + bool building; uint64 previous_xfered; uint64 download_rate; uint64 rates_nb; @@ -145,19 +147,20 @@ namespace Pamac { public ProgressBox progress_box; Vte.Terminal term; Vte.Pty pty; - public Gtk.Grid term_grid; + Cancellable build_cancellable; + public Gtk.ScrolledWindow term_window; //parent window public Gtk.ApplicationWindow? application_window { get; private set; } public signal void start_transaction (); + public signal void start_building (); public signal void important_details_outpout (bool must_show); public signal void alpm_handle_refreshed (); public signal void finished (bool success); public signal void set_pkgreason_finished (); public signal void get_updates_finished (Updates updates); public signal void write_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon, - bool enable_aur, bool search_aur, bool check_aur_updates, - bool no_confirm_build); + bool enable_aur, bool search_aur, bool check_aur_updates); public signal void write_alpm_config_finished (bool checkspace); public signal void write_mirrors_config_finished (string choosen_country, string choosen_generation_method); public signal void generate_mirrors_list (); @@ -173,6 +176,7 @@ namespace Pamac { to_remove = new GenericSet (str_hash, str_equal); to_load = new GenericSet (str_hash, str_equal); to_build = new GenericSet (str_hash, str_equal); + to_build_queue = new Queue (); previous_to_install = new GenericSet (str_hash, str_equal); previous_to_remove = new GenericSet (str_hash, str_equal); transaction_summary = new GenericSet (str_hash, str_equal); @@ -185,10 +189,14 @@ namespace Pamac { progress_box.progressbar.text = ""; //creating terminal term = new Vte.Terminal (); - term.scroll_on_output = false; + term.set_scrollback_lines (-1); term.expand = true; - term.height_request = 200; term.visible = true; + var black = Gdk.RGBA (); + black.parse ("black"); + term.set_color_cursor (black); + term.button_press_event.connect (on_term_button_press_event); + term.key_press_event.connect (on_term_key_press_event); // creating pty for term try { pty = term.pty_new_sync (Vte.PtyFlags.NO_HELPER); @@ -196,19 +204,19 @@ namespace Pamac { stderr.printf ("Error: %s\n", e.message); } // add term in a grid with a scrollbar - term_grid = new Gtk.Grid (); - term_grid.expand = true; - term_grid.visible = true; - var sb = new Gtk.Scrollbar (Gtk.Orientation.VERTICAL, term.vadjustment); - sb.visible = true; - term_grid.attach (term, 0, 0, 1, 1); - term_grid.attach (sb, 1, 0, 1, 1); - // connect to child_exited signal which will only be emit after a call to watch_child - term.child_exited.connect (on_term_child_exited); + term_window = new Gtk.ScrolledWindow (null, term.vadjustment); + term_window.expand = true; + term_window.visible = true; + term_window.propagate_natural_height = true; + term_window.add (term); + build_cancellable = new Cancellable (); // progress data previous_textbar = ""; previous_filename = ""; sysupgrade_after_trans = false; + no_confirm_commit = false; + build_after_sysupgrade = false; + building = false; timer = new Timer (); success = false; warning_textbuffer = new StringBuilder (); @@ -256,7 +264,7 @@ namespace Pamac { Gtk.main_iteration (); } } - Idle.add((owned) callback); + Idle.add ((owned) callback); }); start_get_authorization (); yield; @@ -284,7 +292,7 @@ namespace Pamac { } } - public void start_get_authorization () { + void start_get_authorization () { try { daemon.start_get_authorization (); } catch (IOError e) { @@ -316,23 +324,71 @@ namespace Pamac { } } - void spawn_in_term (string[] args, bool close_pid = true, out Pid child_pid = null) { + bool on_term_button_press_event (Gdk.EventButton event) { + // Check if right mouse button was clicked + if (event.type == Gdk.EventType.BUTTON_PRESS && event.button == 3) { + if (term.get_has_selection ()) { + var right_click_menu = new Gtk.Menu (); + var copy_item = new Gtk.MenuItem.with_label (dgettext (null, "Copy")); + copy_item.activate.connect (() => {term.copy_clipboard ();}); + right_click_menu.append (copy_item); + right_click_menu.show_all (); + right_click_menu.popup (null, null, null, event.button, event.time); + return true; + } + } + return false; + } + + bool on_term_key_press_event (Gdk.EventKey event) { + // Check if Ctrl + c keys were pressed + if (((event.state & Gdk.ModifierType.CONTROL_MASK) != 0) && (Gdk.keyval_name (event.keyval) == "c")) { + term.copy_clipboard (); + return true; + } + return false; + } + + void show_in_term (string message) { + term.set_pty (pty); try { - Process.spawn_async (null, args, null, SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD, pty.child_setup, out child_pid); + Process.spawn_async (null, {"echo", message}, null, SpawnFlags.SEARCH_PATH, pty.child_setup, null); } catch (SpawnError e) { stderr.printf ("SpawnError: %s\n", e.message); } + } + + async int spawn_in_term (string[] args, string? working_directory = null) { + SourceFunc callback = spawn_in_term.callback; + int status = 1; term.set_pty (pty); - if (close_pid) { - ChildWatch.add (child_pid, (pid, status) => { - // Triggered when the child indicated by child_pid exits - Process.close_pid (pid); + var launcher = new SubprocessLauncher (SubprocessFlags.NONE); + launcher.set_cwd (working_directory); + launcher.set_environ (Environ.get ()); + launcher.set_child_setup (pty.child_setup); + try { + Subprocess process = launcher.spawnv (args); + process.wait_async.begin (build_cancellable, (obj, res) => { + try { + process.wait_async.end (res); + if (process.get_if_exited ()) { + status = process.get_exit_status (); + } + } catch (Error e) { + // cancelled + process.send_signal (Posix.SIGTERM); + } + Idle.add ((owned) callback); }); + yield; + } catch (Error e) { + stderr.printf ("Error: %s\n", e.message); } + return status; } void reset_progress_box (string action) { - spawn_in_term ({"echo", action}); + show_in_term (action); progress_box.action_label.label = action; progress_box.progressbar.fraction = 0; progress_box.progressbar.text = ""; @@ -550,16 +606,6 @@ namespace Pamac { return pkgs; } - public async string[] get_aur_build_list (string pkgname) { - string[] names = {}; - try { - names = yield daemon.get_aur_build_list (pkgname); - } catch (IOError e) { - stderr.printf ("IOError: %s\n", e.message); - } - return names; - } - public string[] get_repos_names () { string[] repos_names = {}; try { @@ -719,9 +765,12 @@ namespace Pamac { } } if (updates.repos_updates.length != 0) { + build_after_sysupgrade = true; sysupgrade_simple (enable_downgrade); } else { - on_trans_prepare_finished (true); + // only aur updates + // run as a standard transaction + run (); } } else { if (updates.repos_updates.length != 0) { @@ -738,6 +787,7 @@ namespace Pamac { to_install.remove_all (); to_remove.remove_all (); to_build.remove_all (); + to_load.remove_all (); } void clear_previous_lists () { @@ -745,37 +795,38 @@ namespace Pamac { previous_to_remove.remove_all (); } + void start_trans_prepare (int transflags, string[] to_install, string[] to_remove, string[] to_load, string[] to_build) { + try { + daemon.start_trans_prepare (transflags, to_install, to_remove, to_load, to_build); + } catch (IOError e) { + stderr.printf ("IOError: %s\n", e.message); + stop_progressbar_pulse (); + success = false; + finish_transaction (); + } + } + public void run () { string action = dgettext (null, "Preparing") + "..."; reset_progress_box (action); - // run - if (to_install.length == 0 - && to_remove.length == 0 - && to_load.length == 0 - && to_build.length != 0) { - // there only AUR packages to build so no need to prepare transaction - on_trans_prepare_finished (true); - } else { - string [] to_install_ = {}; - string [] to_remove_ = {}; - string [] to_load_ = {}; - foreach (unowned string name in to_install) { - to_install_ += name; - } - foreach (unowned string name in to_remove) { - to_remove_ += name; - } - foreach (unowned string path in to_load) { - to_load_ += path; - } - try { - daemon.start_trans_prepare (flags, to_install_, to_remove_, to_load_); - } catch (IOError e) { - stderr.printf ("IOError: %s\n", e.message); - success = false; - finish_transaction (); - } + start_progressbar_pulse (); + string[] to_install_ = {}; + string[] to_remove_ = {}; + string[] to_load_ = {}; + string[] to_build_ = {}; + foreach (unowned string name in to_install) { + to_install_ += name; } + foreach (unowned string name in to_remove) { + to_remove_ += name; + } + foreach (unowned string path in to_load) { + to_load_ += path; + } + foreach (unowned string name in to_build) { + to_build_ += name; + } + start_trans_prepare (flags, to_install_, to_remove_, to_load_, to_build_); } void choose_provider (string depend, string[] providers) { @@ -843,6 +894,19 @@ namespace Pamac { transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos)); transaction_sum_dialog.sum_list.set (iter, 0, "%s".printf (dgettext (null, "To remove") + ":")); } + if (summary.aur_conflicts_to_remove.length > 0) { + // do not add type enum because it is just infos + foreach (unowned UpdateInfos infos in summary.aur_conflicts_to_remove) { + transaction_summary.add (infos.name); + transaction_sum_dialog.sum_list.insert_with_values (out iter, -1, + 1, infos.name, + 2, infos.old_version); + } + Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter); + int pos = (path.get_indices ()[0]) - (summary.aur_conflicts_to_remove.length - 1); + transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos)); + transaction_sum_dialog.sum_list.set (iter, 0, "%s".printf (dgettext (null, "To remove") + ":")); + } if (summary.to_downgrade.length > 0) { type |= Type.STANDARD; foreach (unowned UpdateInfos infos in summary.to_downgrade) { @@ -858,15 +922,22 @@ namespace Pamac { transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos)); transaction_sum_dialog.sum_list.set (iter, 0, "%s".printf (dgettext (null, "To downgrade") + ":")); } - if (to_build.length > 0) { + if (summary.to_build.length > 0) { type |= Type.BUILD; - foreach (unowned string name in to_build) { - transaction_summary.add (name); + // populate build queue + foreach (unowned string name in summary.aur_pkgbases_to_build) { + to_build_queue.push_tail (name); + } + aur_pkgs_to_install = {}; + foreach (unowned UpdateInfos infos in summary.to_build) { + aur_pkgs_to_install += infos.name; + transaction_summary.add (infos.name); transaction_sum_dialog.sum_list.insert_with_values (out iter, -1, - 1, name); + 1, infos.name, + 2, infos.new_version); } Gtk.TreePath path = transaction_sum_dialog.sum_list.get_path (iter); - int pos = (path.get_indices ()[0]) - ((int) to_build.length - 1); + int pos = (path.get_indices ()[0]) - (summary.to_build.length - 1); transaction_sum_dialog.sum_list.get_iter (out iter, new Gtk.TreePath.from_indices (pos)); transaction_sum_dialog.sum_list.set (iter, 0, "%s".printf (dgettext (null, "To build") + ":")); } @@ -924,7 +995,7 @@ namespace Pamac { return type; } - public void start_commit () { + void start_commit () { try { daemon.start_trans_commit (); } catch (IOError e) { @@ -934,52 +1005,84 @@ namespace Pamac { } } - public async void build_aur_packages () { - string action = dgettext (null, "Building packages") + "..."; + async void build_aur_packages () { + string pkgname = to_build_queue.pop_head (); + string action = dgettext (null, "Building %s".printf (pkgname)) + "..."; reset_progress_box (action); - term.grab_focus (); + build_cancellable.reset (); start_progressbar_pulse (); important_details_outpout (true); - start_transaction (); - string[] cmds = {"yaourt", "-S"}; - if (pamac_config.no_confirm_build) { - cmds += "--noconfirm"; - } - string[] packagebases = {}; - foreach (unowned string name in to_build) { - AURPackageDetails details = yield get_aur_details (name); - if (details.name != "") { - if (!(details.packagebase in packagebases)) { - packagebases += details.packagebase; - cmds += name; + to_build.remove_all (); + string [] built_pkgs = {}; + int status = 1; + string builddir = "/tmp/pamac-build"; + status = yield spawn_in_term ({"mkdir", "-p", builddir}); + if (status == 0) { + status = yield spawn_in_term ({"rm", "-rf", pkgname}, builddir); + if (!build_cancellable.is_cancelled ()) { + if (status == 0) { + building = true; + start_building (); + status = yield spawn_in_term ({"git", "clone", "https://aur.archlinux.org/%s.git".printf (pkgname)}, builddir); + if (status == 0) { + string pkgdir = "%s/%s".printf (builddir, pkgname); + status = yield spawn_in_term ({"makepkg", "-c"}, pkgdir); + building = false; + if (status == 0) { + foreach (unowned string aurpkg in aur_pkgs_to_install) { + string standard_output; + try { + Process.spawn_command_line_sync ("find %s -name %s".printf (pkgdir, "'%s-*.pkg.tar*'".printf (aurpkg)), + out standard_output, + null, + out status); + if (status == 0) { + foreach (unowned string path in standard_output.split ("\n")) { + if (path != "") { + built_pkgs += path; + } + } + } + } catch (SpawnError e) { + stderr.printf ("SpawnError: %s\n", e.message); + status = 1; + } + } + } + } } } else { - cmds += name; + status = 1; } } - Pid child_pid; - spawn_in_term (cmds, false, out child_pid); - // watch_child is needed in order to have the child_exited signal emitted - term.watch_child (child_pid); -//~ foreach (unowned string pkgname in to_build) { -//~ stdout.printf("aur deps for %s:\n", pkgname); -//~ get_aur_build_list.begin (pkgname, (obj, res) => { -//~ string[] names = get_aur_build_list.end (res); -//~ foreach (unowned string name in names) { -//~ stdout.printf("\t%s\n", name); -//~ } -//~ }); -//~ } + building = false; + if (status == 0) { + if (built_pkgs.length > 0) { + no_confirm_commit = true; + show_in_term (""); + stop_progressbar_pulse (); + start_trans_prepare (flags, {}, {}, built_pkgs, {}); + } + } else { + to_load.remove_all (); + to_build_queue.clear (); + stop_progressbar_pulse (); + success = false; + finish_transaction (); + } } public void cancel () { - try { - daemon.trans_cancel (); - } catch (IOError e) { - stderr.printf ("IOError: %s\n", e.message); + if (building) { + build_cancellable.cancel (); + } else { + try { + daemon.trans_cancel (); + } catch (IOError e) { + stderr.printf ("IOError: %s\n", e.message); + } } - progress_box.hide (); - spawn_in_term ({"/usr/bin/echo", dgettext (null, "Transaction cancelled") + ".\n"}); + show_in_term (dgettext (null, "Transaction cancelled") + ".\n"); warning_textbuffer = new StringBuilder (); } @@ -1031,31 +1134,31 @@ namespace Pamac { previous_filename = details[0]; string msg = dgettext (null, "Installing %s").printf (details[0]) + "..."; progress_box.action_label.label = msg; - spawn_in_term ({"echo", dgettext (null, "Installing %s").printf ("%s (%s)".printf (details[0], details[1])) + "..."}); + show_in_term (dgettext (null, "Installing %s").printf ("%s (%s)".printf (details[0], details[1])) + "..."); break; case 2: //Alpm.Package.Operation.UPGRADE previous_filename = details[0]; string msg = dgettext (null, "Upgrading %s").printf (details[0]) + "..."; progress_box.action_label.label = msg; - spawn_in_term ({"echo", dgettext (null, "Upgrading %s").printf ("%s (%s -> %s)".printf (details[0], details[1], details[2])) + "..."}); + show_in_term (dgettext (null, "Upgrading %s").printf ("%s (%s -> %s)".printf (details[0], details[1], details[2])) + "..."); break; case 3: //Alpm.Package.Operation.REINSTALL previous_filename = details[0]; string msg = dgettext (null, "Reinstalling %s").printf (details[0]) + "..."; progress_box.action_label.label = msg; - spawn_in_term ({"echo", dgettext (null, "Reinstalling %s").printf ("%s (%s)".printf (details[0], details[1])) + "..."}); + show_in_term (dgettext (null, "Reinstalling %s").printf ("%s (%s)".printf (details[0], details[1])) + "..."); break; case 4: //Alpm.Package.Operation.DOWNGRADE previous_filename = details[0]; string msg = dgettext (null, "Downgrading %s").printf (details[0]) + "..."; progress_box.action_label.label = msg; - spawn_in_term ({"echo", dgettext (null, "Downgrading %s").printf ("%s (%s -> %s)".printf (details[0], details[1], details[2])) + "..."}); + show_in_term (dgettext (null, "Downgrading %s").printf ("%s (%s -> %s)".printf (details[0], details[1], details[2])) + "..."); break; case 5: //Alpm.Package.Operation.REMOVE previous_filename = details[0]; string msg = dgettext (null, "Removing %s").printf (details[0]) + "..."; progress_box.action_label.label = msg; - spawn_in_term ({"echo", dgettext (null, "Removing %s").printf ("%s (%s)".printf (details[0], details[1])) + "..."}); + show_in_term (dgettext (null, "Removing %s").printf ("%s (%s)".printf (details[0], details[1])) + "..."); break; } break; @@ -1090,7 +1193,7 @@ namespace Pamac { break; case 28: //Alpm.Event.Type.PKGDOWNLOAD_START // special case handle differently - spawn_in_term ({"echo", dgettext (null, "Downloading %s").printf (details[0]) + "..."}); + show_in_term (dgettext (null, "Downloading %s").printf (details[0]) + "..."); string name_version_release = details[0].slice (0, details[0].last_index_of_char ('-')); string name_version = name_version_release.slice (0, name_version_release.last_index_of_char ('-')); string name = name_version.slice (0, name_version.last_index_of_char ('-')); @@ -1153,10 +1256,10 @@ namespace Pamac { } if (action != null) { progress_box.action_label.label = action; - spawn_in_term ({"echo", action}); + show_in_term (action); } if (detailed_action != null) { - spawn_in_term ({"echo", detailed_action}); + show_in_term (detailed_action); } } @@ -1329,7 +1432,7 @@ namespace Pamac { } } if (line != null) { - spawn_in_term ({"echo", "-n", line}); + show_in_term (line.replace ("\n", "")); } } @@ -1362,21 +1465,37 @@ namespace Pamac { } void display_error (string message, string[] details) { - spawn_in_term ({"echo", "-n", message}); - var dialog = new Gtk.MessageDialog (application_window, - Gtk.DialogFlags.MODAL, - Gtk.MessageType.ERROR, - Gtk.ButtonsType.CLOSE, - message); + var dialog = new Gtk.Dialog.with_buttons (message, + application_window, + Gtk.DialogFlags.MODAL | Gtk.DialogFlags.USE_HEADER_BAR); + var textbuffer = new StringBuilder (); if (details.length != 0) { - var textbuffer = new StringBuilder (); - spawn_in_term ({"echo", ":"}); + show_in_term (message + ":"); foreach (unowned string detail in details) { - spawn_in_term ({"echo", detail}); + show_in_term (detail); textbuffer.append (detail + "\n"); } - dialog.secondary_text = textbuffer.str; + } else { + show_in_term (message); + textbuffer.append (message); } + dialog.deletable = false; + unowned Gtk.Widget widget = dialog.add_button (dgettext (null, "_Close"), Gtk.ResponseType.CLOSE); + widget.can_focus = true; + widget.has_focus = true; + widget.can_default = true; + widget.has_default = true; + var scrolledwindow = new Gtk.ScrolledWindow (null, null); + var label = new Gtk.Label (textbuffer.str); + label.margin = 12; + scrolledwindow.visible = true; + label.visible = true; + scrolledwindow.add (label); + scrolledwindow.expand = true; + unowned Gtk.Box box = dialog.get_content_area (); + box.add (scrolledwindow); + dialog.default_width = 600; + dialog.default_height = 300; dialog.run (); dialog.destroy (); } @@ -1417,8 +1536,8 @@ namespace Pamac { if (success) { show_warnings (); Type type = set_transaction_sum (); - if (type == Type.UPDATE && mode == Mode.UPDATER) { - // there only updates + if (no_confirm_commit || (type == Type.UPDATE && mode == Mode.UPDATER)) { + // no_confirm_commit or only updates start_commit (); } else if (type != 0) { if (transaction_sum_dialog.run () == Gtk.ResponseType.OK) { @@ -1428,6 +1547,7 @@ namespace Pamac { } if (type == Type.BUILD) { // there only AUR packages to build + release (); on_trans_commit_finished (true); } else { // backup to_install and to_remove @@ -1444,10 +1564,11 @@ namespace Pamac { } else { transaction_sum_dialog.hide (); unowned string action = dgettext (null, "Transaction cancelled"); - spawn_in_term ({"echo", action + ".\n"}); + show_in_term (action + ".\n"); progress_box.action_label.label = action; release (); transaction_summary.remove_all (); + to_build_queue.clear (); sysupgrade_after_trans = false; success = false; finish_transaction (); @@ -1455,13 +1576,14 @@ namespace Pamac { } else { //var err = ErrorInfos (); //err.message = dgettext (null, "Nothing to do") + "\n"; - spawn_in_term ({"echo", dgettext (null, "Nothing to do") + ".\n"}); + show_in_term (dgettext (null, "Nothing to do") + ".\n"); release (); clear_lists (); finish_transaction (); //handle_error (err); } } else { + to_load.remove_all (); warning_textbuffer = new StringBuilder (); handle_error (get_current_error ()); } @@ -1469,23 +1591,27 @@ namespace Pamac { void on_trans_commit_finished (bool success) { this.success = success; + // needed before build_aur_packages and remove_makedeps + no_confirm_commit = false; if (success) { show_warnings (); - if (to_build.length != 0) { - if (previous_to_install.length != 0 - || previous_to_remove.length != 0 - || to_load.length != 0) { - spawn_in_term ({"echo", dgettext (null, "Transaction successfully finished") + ".\n"}); - } + to_load.remove_all (); + if (to_build_queue.get_length () != 0) { + show_in_term (""); + clear_previous_lists (); build_aur_packages.begin (); } else { clear_previous_lists (); if (sysupgrade_after_trans) { sysupgrade_after_trans = false; sysupgrade (false); + } else if (build_after_sysupgrade) { + build_after_sysupgrade = false; + // build aur updates in to_build + run (); } else { unowned string action = dgettext (null, "Transaction successfully finished"); - spawn_in_term ({"echo", action + ".\n"}); + show_in_term (action + ".\n"); progress_box.action_label.label = action; finish_transaction (); } @@ -1502,6 +1628,8 @@ namespace Pamac { foreach (unowned string name in previous_to_remove) { to_remove.add (name); } + } else { + to_load.remove_all (); } clear_previous_lists (); warning_textbuffer = new StringBuilder (); @@ -1512,39 +1640,18 @@ namespace Pamac { previous_filename = ""; } - void on_term_child_exited (int status) { - stop_progressbar_pulse (); - clear_previous_lists (); - to_build.remove_all (); - // let the time to the daemon to update databases - Timeout.add (1000, () => { - if (status == 0) { - success = true; - unowned string action = dgettext (null, "Transaction successfully finished"); - spawn_in_term ({"echo", action + "."}); - progress_box.action_label.label = action; - } else { - success = false; - } - finish_transaction (); - return false; - }); - } - void on_set_pkgreason_finished () { set_pkgreason_finished (); } void on_write_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon, - bool enable_aur, bool search_aur, bool check_aur_updates, - bool no_confirm_build) { + bool enable_aur, bool search_aur, bool check_aur_updates) { pamac_config.reload (); if (recurse) { flags |= (1 << 5); //Alpm.TransFlag.RECURSE } write_pamac_config_finished (recurse, refresh_period, no_update_hide_icon, - enable_aur, search_aur, check_aur_updates, - no_confirm_build); + enable_aur, search_aur, check_aur_updates); } void on_write_alpm_config_finished (bool checkspace) { @@ -1556,12 +1663,12 @@ namespace Pamac { } void on_generate_mirrors_list_data (string line) { - spawn_in_term ({"echo", line}); + show_in_term (line); } void on_generate_mirrors_list_finished () { stop_progressbar_pulse (); - spawn_in_term ({"echo"}); + show_in_term (""); // force a dbs refresh start_refresh (true); } diff --git a/src/updater_window.vala b/src/updater_window.vala index 3764208..8a92ccf 100644 --- a/src/updater_window.vala +++ b/src/updater_window.vala @@ -75,6 +75,7 @@ namespace Pamac { important_details = false; generate_mirrors_list = false; + headerbar.title = dgettext (null, "Update Manager"); Timeout.add (100, populate_window); } @@ -89,13 +90,14 @@ namespace Pamac { transaction = new Transaction (this as Gtk.ApplicationWindow); transaction.mode = Mode.UPDATER; transaction.start_transaction.connect (on_start_transaction); + transaction.start_building.connect (on_start_building); transaction.important_details_outpout.connect (on_important_details_output); transaction.finished.connect (populate_updates_list); transaction.get_updates_finished.connect (on_get_updates_finished); transaction.generate_mirrors_list.connect (on_generate_mirrors_list); // integrate progress box and term widget - stack.add_named (transaction.term_grid, "term"); + stack.add_named (transaction.term_window, "term"); transaction_infobox.pack_start (transaction.progress_box); // A timeout is needed to let the time to the daemon to deal @@ -264,6 +266,10 @@ namespace Pamac { cancel_button.sensitive = false; } + void on_start_building () { + cancel_button.sensitive = true; + } + void on_important_details_output (bool must_show) { if (must_show) { stackswitcher.visible = false; @@ -300,7 +306,7 @@ namespace Pamac { } void on_get_updates_finished (Updates updates) { - headerbar.title = ""; + headerbar.title = dgettext (null, "Update Manager"); repos_updates_list.clear (); stackswitcher.visible = false; repos_scrolledwindow.visible = true;