Commit c09096ef authored by guinux's avatar guinux

transaction process improvements

parent 4c401444
......@@ -7,7 +7,7 @@
<property name="border_width">3</property>
<property name="title" translatable="yes">Transaction Summary</property>
<property name="window_position">center-on-parent</property>
<property name="default_width">600</property>
<property name="default_width">700</property>
<property name="icon_name">system-software-install</property>
<property name="type_hint">dialog</property>
<property name="deletable">False</property>
......@@ -53,11 +53,23 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="review_button">
<property name="label" translatable="yes">Edit build files</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
......@@ -152,6 +164,7 @@
<action-widgets>
<action-widget response="-6">cancel_button</action-widget>
<action-widget response="-5">apply_button</action-widget>
<action-widget response="-2">review_button</action-widget>
</action-widgets>
</template>
</interface>
......@@ -134,20 +134,19 @@ internal class AlpmConfig {
}
}
public Alpm.Handle? get_handle (bool files_db = false, bool tmp_db = false, bool copy_dbs = true) {
public Alpm.Handle? get_handle (bool files_db = false, bool tmp_db = false) {
Alpm.Errno error = 0;
Alpm.Handle? handle = null;
if (tmp_db) {
string tmp_dbpath = "/tmp/pamac-checkdbs";
try {
if (! GLib.FileUtils.test (tmp_dbpath, GLib.FileTest.IS_DIR)) {
var file = GLib.File.new_for_path (tmp_dbpath);
if (!file.query_exists ()) {
Process.spawn_command_line_sync ("mkdir -p %s/sync".printf (tmp_dbpath));
Process.spawn_command_line_sync ("ln -sf %slocal %s".printf (dbpath, tmp_dbpath));
Process.spawn_command_line_sync ("chmod -R 777 %s/sync".printf (tmp_dbpath));
if (copy_dbs) {
Process.spawn_command_line_sync ("bash -c 'cp -p %ssync/*.{db,files} %s/sync'".printf (dbpath, tmp_dbpath));
}
}
Process.spawn_command_line_sync ("ln -sf %slocal %s".printf (dbpath, tmp_dbpath));
Process.spawn_command_line_sync ("cp -au %ssync %s".printf (dbpath, tmp_dbpath));
handle = new Alpm.Handle (rootdir, tmp_dbpath, out error);
if (error == Alpm.Errno.DB_VERSION) {
try {
......
......@@ -29,7 +29,6 @@ namespace Pamac {
internal Mutex provider_mutex;
internal int? choosen_provider;
internal bool force_refresh;
internal bool refreshed;
internal bool enable_downgrade;
internal int flags;
string[] to_syncfirst;
......@@ -72,7 +71,6 @@ namespace Pamac {
refresh_handle ();
cancellable = new Cancellable ();
curl = new Curl.Easy ();
refreshed = false;
downloading_updates = false;
Curl.global_init (Curl.GLOBAL_SSL);
}
......@@ -198,7 +196,6 @@ namespace Pamac {
if (cancellable.is_cancelled ()) {
refresh_finished (false);
} else if (success) {
refreshed = true;
refresh_finished (true);
} else {
current_error.message = _("Failed to synchronize any databases");
......@@ -281,7 +278,7 @@ namespace Pamac {
internal int download_updates () {
downloading_updates = true;
// use tmp handle
var handle = alpm_config.get_handle (false, true, false);
var handle = alpm_config.get_handle (false, true);
handle.fetchcb = (Alpm.FetchCallBack) cb_fetch;
cancellable.reset ();
int success = handle.trans_init (Alpm.TransFlag.DOWNLOADONLY);
......@@ -899,6 +896,14 @@ namespace Pamac {
}
trans_release ();
if (success) {
// remove syncfirsts from to_install
string[] to_install_backup = to_install;
to_install = {};
foreach (unowned string name in to_install_backup) {
if (!(name in to_syncfirst)) {
to_install += name;
}
}
success = trans_init (flags);
if (success && sysupgrade) {
success = trans_sysupgrade ();
......@@ -929,7 +934,14 @@ namespace Pamac {
}
if (success) {
success = trans_prepare_real ();
} else {
// continue if needed
if (success && (alpm_handle.trans_to_add ().length + alpm_handle.trans_to_remove ().length) == 0) {
trans_release ();
trans_commit_finished (success);
return;
}
}
if (!success) {
trans_release ();
}
}
......
......@@ -316,7 +316,7 @@ namespace Pamac {
i++;
}
if (!error) {
try_lock_and_run (start_refresh);
try_lock_and_run (start_sysupgrade);
}
} else {
display_help ();
......@@ -337,7 +337,6 @@ namespace Pamac {
transaction = new TransactionCli (database);
transaction.finished.connect (on_transaction_finished);
transaction.sysupgrade_finished.connect (on_transaction_finished);
transaction.refresh_finished.connect (on_refresh_finished);
transaction.start_preparing.connect (() => {
trans_cancellable = true;
});
......@@ -844,7 +843,7 @@ namespace Pamac {
}
}
foreach (unowned string pkgname in pkgnames) {
var details = database.get_pkg_details (pkgname, "");
var details = database.get_pkg_details (pkgname, "", false);
if (details.name == "") {
print_error (dgettext (null, "target not found: %s").printf (pkgname) + "\n");
continue;
......@@ -1650,29 +1649,19 @@ namespace Pamac {
}
}
void start_refresh () {
void start_sysupgrade () {
if (Posix.geteuid () != 0) {
// let's time to pkttyagent to get registred
Timeout.add (200, () => {
transaction.start_refresh (force_refresh);
transaction.start_sysupgrade (force_refresh, enable_downgrade, temporary_ignorepkgs, overwrite_files);
return false;
});
} else {
transaction.start_refresh (force_refresh);
transaction.start_sysupgrade (force_refresh, enable_downgrade, temporary_ignorepkgs, overwrite_files);
}
loop.run ();
}
void on_refresh_finished (bool success) {
if (success) {
transaction.start_sysupgrade (enable_downgrade, temporary_ignorepkgs, overwrite_files);
} else {
transaction.unlock ();
loop.quit ();
exit_status = 1;
}
}
void on_transaction_finished (bool success) {
transaction.unlock ();
loop.quit ();
......
......@@ -28,6 +28,7 @@ namespace Pamac {
string locale;
public signal void get_updates_progress (uint percent);
public signal void refreshed ();
public Config config { get; construct set; }
......@@ -75,6 +76,7 @@ namespace Pamac {
} else {
files_handle = alpm_config.get_handle (true);
}
refreshed ();
}
public List<string> get_mirrors_countries () {
......@@ -852,7 +854,7 @@ namespace Pamac {
return optdeps;
}
public PackageDetails get_pkg_details (string pkgname, string appname) {
public PackageDetails get_pkg_details (string pkgname, string appname, bool use_sync_pkg) {
string name = "";
string app_name = "";
string version = "";
......@@ -881,7 +883,7 @@ namespace Pamac {
var details = PackageDetailsStruct ();
unowned Alpm.Package? alpm_pkg = alpm_handle.localdb.get_pkg (pkgname);
unowned Alpm.Package? sync_pkg = get_syncpkg (pkgname);
if (alpm_pkg == null) {
if (alpm_pkg == null || use_sync_pkg) {
alpm_pkg = sync_pkg;
} else {
installed_version = alpm_pkg.version;
......@@ -1121,10 +1123,25 @@ namespace Pamac {
return version.str;
}
public async string clone_build_files (string pkgname, bool overwrite_files) {
async int launch_subprocess (SubprocessLauncher launcher, string[] cmds) {
int status = 1;
try {
Subprocess process = launcher.spawnv (cmds);
yield process.wait_async ();
if (process.get_if_exited ()) {
status = process.get_exit_status ();
}
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
return status;
}
public async File? clone_build_files (string pkgname, bool overwrite_files) {
int status = 1;
string builddir_name = Path.build_path ("/", config.aur_build_dir, "pamac-build");
string[] cmds;
var launcher = new SubprocessLauncher (SubprocessFlags.NONE);
var builddir = File.new_for_path (builddir_name);
if (!builddir.query_exists ()) {
try {
......@@ -1134,59 +1151,77 @@ namespace Pamac {
stderr.printf ("Error: %s\n", e.message);
}
}
string pkgdir_name = builddir_name + "/" + pkgname;
var pkgdir = File.new_for_path (pkgdir_name);
var launcher = new SubprocessLauncher (SubprocessFlags.NONE);
if (overwrite_files) {
try {
Process.spawn_command_line_sync ("rm -rf %s".printf (pkgdir_name));
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
}
var pkgdir = builddir.get_child (pkgname);
if (pkgdir.query_exists ()) {
var aur_pkg = yield get_aur_pkg (pkgname);
if (aur_pkg.version == get_srcinfo_version (pkgdir_name)) {
// up to date
return pkgdir_name;
if (overwrite_files) {
launcher.set_cwd (builddir_name);
cmds = {"rm", "-rf %s".printf (pkgdir.get_path ())};
yield launch_subprocess (launcher, cmds);
cmds = {"git", "clone", "-q", "--depth=1", "https://aur.archlinux.org/%s.git".printf (pkgname)};
} else {
launcher.set_cwd (pkgdir_name);
cmds = {"git", "pull", "-q"};
try {
Subprocess process = launcher.spawnv (cmds);
yield process.wait_async ();
if (process.get_if_exited ()) {
status = process.get_exit_status ();
}
if (status == 0) {
return pkgdir_name;
} else {
Process.spawn_command_line_sync ("rm -rf %s".printf (pkgdir_name));
launcher.set_cwd (builddir_name);
cmds = {"git", "clone", "-q", "--depth=1", "https://aur.archlinux.org/%s.git".printf (pkgname)};
var aur_pkg = yield get_aur_pkg (pkgname);
if (aur_pkg.version == get_srcinfo_version (pkgdir.get_path ())) {
// up to date
return pkgdir;
}
// fetch modifications
launcher.set_cwd (pkgdir.get_path ());
cmds = {"git", "fetch", "-q"};
status = yield launch_subprocess (launcher, cmds);
// write diff file
if (status == 0) {
launcher.set_flags (SubprocessFlags.STDOUT_PIPE);
try {
Subprocess process = launcher.spawnv ({"git", "diff", "origin/master"});
yield process.wait_async ();
var dis = new DataInputStream (process.get_stdout_pipe ());
var file = File.new_for_path (Path.build_path ("/", pkgdir.get_path (), "diff"));
if (file.query_exists ()) {
// delete the file before rewrite it
yield file.delete_async ();
}
// creating a DataOutputStream to the file
var dos = new DataOutputStream (yield file.create_async (FileCreateFlags.REPLACE_DESTINATION));
// writing makepkg output to diff
yield dos.splice_async (dis, 0);
if (process.get_if_exited ()) {
status = process.get_exit_status ();
}
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
launcher.set_flags (SubprocessFlags.NONE);
}
// merge modifications
if (status == 0) {
cmds = {"git", "merge", "-q"};
status = yield launch_subprocess (launcher, cmds);
}
if (status == 0) {
return pkgdir;
} else {
launcher.set_cwd (builddir_name);
cmds = {"rm", "-rf %s".printf (pkgdir.get_path ())};
yield launch_subprocess (launcher, cmds);
cmds = {"git", "clone", "-q", "--depth=1", "https://aur.archlinux.org/%s.git".printf (pkgname)};
}
}
} else {
launcher.set_cwd (builddir_name);
cmds = {"git", "clone", "-q", "--depth=1", "https://aur.archlinux.org/%s.git".printf (pkgname)};
}
try {
Subprocess process = launcher.spawnv (cmds);
yield process.wait_async ();
Process.spawn_command_line_sync ("chmod --quiet -R ugo+w %s".printf (pkgdir_name));
if (process.get_if_exited ()) {
status = process.get_exit_status ();
status = yield launch_subprocess (launcher, cmds);
if (status == 0) {
try {
Process.spawn_command_line_sync ("chmod --quiet -R ugo+w %s".printf (pkgdir.get_path ()));
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
if (status == 0) {
return pkgdir_name;
return pkgdir;
}
return "";
return null;
}
public async AURPackage get_aur_pkg (string pkgname) {
......@@ -1372,7 +1407,7 @@ namespace Pamac {
return get_aur_updates_real (yield aur_multiinfo (local_pkgs));
}
public void refresh_files_dbs () {
public async void refresh_tmp_files_dbs () {
var tmp_files_handle = alpm_config.get_handle (true, true);
unowned Alpm.List<unowned Alpm.DB> syncdbs = tmp_files_handle.syncdbs;
while (syncdbs != null) {
......@@ -1384,12 +1419,11 @@ namespace Pamac {
public async Updates get_updates () {
// be sure we have the good updates
refresh ();
alpm_config = new AlpmConfig ("/etc/pacman.conf");
var tmp_handle = alpm_config.get_handle (false, true);
var repos_updates = new List<Package> ();
unowned Alpm.Package? pkg = null;
unowned Alpm.Package? candidate = null;
// use a tmp handle
var tmp_handle = alpm_config.get_handle (false, true);
// refresh tmp dbs
// count this step as 90% of the total
get_updates_progress (0);
......
......@@ -39,8 +39,8 @@ namespace Pamac {
base.startup ();
important_details = false;
var pamac_config = new Config ("/etc/pamac.conf");
database = new Database (pamac_config);
var config = new Config ("/etc/pamac.conf");
database = new Database (config);
// integrate progress box and term widget
progress_dialog = new ProgressDialog ();
transaction = new TransactionGtk (database, progress_dialog as Gtk.ApplicationWindow);
......@@ -151,6 +151,7 @@ namespace Pamac {
}
void on_transaction_finished (bool success) {
transaction.unlock ();
if (!success || important_details) {
progress_dialog.close_button.visible = true;
} else {
......
......@@ -158,6 +158,7 @@ namespace Pamac {
Gtk.MenuItem deselect_item;
Gtk.MenuItem upgrade_item;
Gtk.MenuItem install_item;
Gtk.MenuItem build_item;
Gtk.MenuItem remove_item;
Gtk.MenuItem details_item;
GLib.List<string> selected_pkgs;
......@@ -184,11 +185,8 @@ namespace Pamac {
public TransactionGtk transaction;
public Database database;
bool intern_lock;
GLib.File lockfile;
delegate void TransactionAction ();
bool refreshing;
bool important_details;
bool transaction_running;
bool sysupgrade_running;
......@@ -221,7 +219,6 @@ namespace Pamac {
select_all_button.visible = false;
scroll_to_top = true;
searchbar.connect_entry (search_entry);
refreshing = false;
important_details = false;
transaction_running = false;
sysupgrade_running = false;
......@@ -244,6 +241,9 @@ namespace Pamac {
install_item = new Gtk.MenuItem.with_label (dgettext (null, "Install"));
install_item.activate.connect (on_install_item_activate);
right_click_menu.append (install_item);
build_item = new Gtk.MenuItem.with_label (dgettext (null, "Build"));
build_item.activate.connect (on_build_item_activate);
right_click_menu.append (build_item);
remove_item = new Gtk.MenuItem.with_label (dgettext (null, "Remove"));
remove_item.activate.connect (on_remove_item_activate);
right_click_menu.append (remove_item);
......@@ -252,7 +252,6 @@ namespace Pamac {
details_item = new Gtk.MenuItem.with_label (dgettext (null, "Details"));
details_item.activate.connect (on_details_item_activate);
right_click_menu.append (details_item);
right_click_menu.show_all ();
packages_list = new Gtk.ListStore (9,
typeof (uint), //origin
......@@ -371,14 +370,14 @@ namespace Pamac {
database = new Database (config);
database.enable_appstream ();
database.get_updates_progress.connect (on_get_updates_progress);
// check extern lock
lockfile = GLib.File.new_for_path (database.get_lockfile ());
intern_lock = false;
Timeout.add (200, check_extern_lock);
database.refreshed.connect (() => {
scroll_to_top = false;
refresh_packages_list ();
});
// refresh files dbs in tmp in background
database.refresh_tmp_files_dbs.begin ();
transaction = new TransactionGtk (database, this);
transaction.no_confirm_upgrade = true;
transaction.start_preparing.connect (on_start_preparing);
transaction.stop_preparing.connect (on_stop_preparing);
transaction.start_downloading.connect (on_start_downloading);
......@@ -386,7 +385,6 @@ namespace Pamac {
transaction.start_building.connect (on_start_building);
transaction.stop_building.connect (on_stop_building);
transaction.important_details_outpout.connect (on_important_details_outpout);
transaction.refresh_finished.connect (on_refresh_finished);
transaction.sysupgrade_finished.connect (on_transaction_finished);
transaction.finished.connect (on_transaction_finished);
transaction.write_pamac_config_finished.connect (on_write_pamac_config_finished);
......@@ -436,7 +434,7 @@ namespace Pamac {
[GtkCallback]
bool on_ManagerWindow_delete_event () {
if (transaction_running || sysupgrade_running || refreshing || generate_mirrors_list) {
if (transaction_running || sysupgrade_running || generate_mirrors_list) {
// do not close window
return true;
} else {
......@@ -445,24 +443,6 @@ namespace Pamac {
}
}
bool check_lock_and_updates () {
if (!lockfile.query_exists ()) {
database.refresh ();
refresh_packages_list ();
Timeout.add (200, check_extern_lock);
return false;
}
return true;
}
bool check_extern_lock () {
if (!intern_lock && lockfile.query_exists ()) {
Timeout.add (1000, check_lock_and_updates);
return false;
}
return true;
}
void on_write_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon,
bool enable_aur) {
support_aur (enable_aur);
......@@ -470,9 +450,6 @@ namespace Pamac {
void on_set_pkgreason_finished () {
transaction.unlock ();
intern_lock = false;
scroll_to_top = false;
refresh_packages_list ();
if (main_stack.visible_child_name == "details") {
if (database.get_installed_pkg (current_package_displayed).name != ""
|| database.get_sync_pkg (current_package_displayed).name != "") {
......@@ -519,12 +496,12 @@ namespace Pamac {
void try_lock_and_run (TransactionAction action) {
if (transaction.get_lock ()) {
intern_lock = true;
action ();
} else {
waiting = true;
transaction.progress_box.action_label.label = dgettext (null, "Waiting for another package manager to quit") + "...";
transaction.start_progressbar_pulse ();
apply_button.sensitive = false;
cancel_button.sensitive = true;
show_transaction_infobox ();
Timeout.add (5000, () => {
......@@ -534,7 +511,6 @@ namespace Pamac {
bool locked = transaction.get_lock ();
if (locked) {
waiting = false;
intern_lock = true;
transaction.stop_progressbar_pulse ();
action ();
}
......@@ -545,7 +521,7 @@ namespace Pamac {
void set_pendings_operations () {
refresh_state_icons ();
if (!transaction_running && !generate_mirrors_list && !refreshing && !sysupgrade_running) {
if (!transaction_running && !generate_mirrors_list && !sysupgrade_running) {
if (filters_stack.visible_child_name == "updates") {
uint64 total_dsize = 0;
packages_list.foreach ((model, path, iter) => {
......@@ -562,7 +538,7 @@ namespace Pamac {
} else {
transaction.progress_box.action_label.label = "";
}
if (!transaction_running && !generate_mirrors_list && !refreshing && !sysupgrade_running
if (!transaction_running && !generate_mirrors_list && !sysupgrade_running
&& (to_update.length > 0)) {
apply_button.sensitive = true;
} else {
......@@ -737,7 +713,6 @@ namespace Pamac {
void on_mark_explicit_button_clicked (Gtk.Button button) {
if (transaction.get_lock ()) {
intern_lock = true;
transaction.start_set_pkgreason (current_package_displayed, 0); //Alpm.Package.Reason.EXPLICIT
}
}
......@@ -876,8 +851,8 @@ namespace Pamac {
return pixbuf;
}
async void set_package_details (string pkgname, string app_name) {
PackageDetails details = database.get_pkg_details (pkgname, app_name);
async void set_package_details (string pkgname, string app_name, bool sync_pkg) {
PackageDetails details = database.get_pkg_details (pkgname, app_name, sync_pkg);
// download screenshot
app_screenshot.pixbuf = null;
if (details.screenshot != "") {
......@@ -1242,7 +1217,7 @@ namespace Pamac {
}
database.get_aur_pkg.begin (current_package_displayed, (obj, res) => {
AURPackage pkg = database.get_aur_pkg.end (res);
transaction.populate_build_files.begin (pkg.packagebase, true);
transaction.populate_build_files.begin (pkg.packagebase, true, true);
this.get_window ().set_cursor (null);
});
}
......@@ -1571,7 +1546,7 @@ namespace Pamac {
}
}
void display_package_properties (string pkgname, string app_name = "") {
void display_package_properties (string pkgname, string app_name = "", bool sync_pkg = false) {
current_package_displayed = pkgname;
// select details if build files was selected
if (properties_listbox.get_selected_row ().get_index () == 3) {
......@@ -1579,7 +1554,7 @@ namespace Pamac {
}
files_row.visible = true;
build_files_row.visible = false;
set_package_details.begin (current_package_displayed, app_name);
set_package_details.begin (current_package_displayed, app_name, sync_pkg);
}
void display_aur_properties (string pkgname) {
......@@ -1606,12 +1581,20 @@ namespace Pamac {
string pkgname;
string app_name;
packages_list.get (iter, 1, out pkgname, 7, out app_name);
display_package_properties (pkgname, app_name);
bool sync_pkg = false;
if (filters_stack.visible_child_name == "updates") {
sync_pkg = true;