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 {
......
This diff is collapsed.
......@@ -50,7 +50,7 @@ executable('pamac-system-daemon',
libpamac = library('pamac',
sources: [common_sources, 'error.vala', 'alpm_config.vala', 'aur.vala', 'database.vala', 'transaction_interface.vala', 'alpm_utils.vala', 'transaction_interface_root.vala', 'transaction_interface_daemon.vala', 'transaction.vala'],
dependencies: [gio, posix, math, json, appstream, libsoup, libalpm, libcurl],
dependencies: [alpm_deps, math, json, appstream, libsoup, libcurl],
vala_args: [common_vala_args, alpm_vala_args, '--thread'],
c_args: [common_c_args, alpm_c_args],
vala_gir: 'Pamac-1.0.gir',
......
......@@ -56,6 +56,7 @@ namespace Pamac {
public signal void emit_log (uint level, string msg);
public signal void set_pkgreason_finished ();
public signal void refresh_finished (bool success);
public signal void database_modified ();
public signal void downloading_updates_finished ();
public signal void trans_prepare_finished (bool success);
public signal void trans_commit_finished (bool success);
......@@ -76,7 +77,7 @@ namespace Pamac {
lockfile = GLib.File.new_for_path (alpm_utils.alpm_handle.lockfile);
check_old_lock ();
check_extern_lock ();
Timeout.add (500, check_extern_lock);
Timeout.add (200, check_extern_lock);
create_thread_pool ();
refreshed = false;
alpm_utils.emit_event.connect ((primary_event, secondary_event, details) => {
......@@ -107,6 +108,7 @@ namespace Pamac {
trans_prepare_finished (success);
});
alpm_utils.trans_commit_finished.connect ((success) => {
database_modified ();
trans_commit_finished (success);
});
}
......@@ -209,6 +211,7 @@ namespace Pamac {
if (!lockfile.query_exists ()) {
lock_id = new BusName ("");
alpm_utils.refresh_handle ();
database_modified ();
}
} else {
if (lockfile.query_exists ()) {
......@@ -292,6 +295,7 @@ namespace Pamac {
alpm_utils.alpm_config.write (new_alpm_conf);
alpm_utils.alpm_config.reload ();
alpm_utils.refresh_handle ();
database_modified ();
write_alpm_config_finished ((alpm_utils.alpm_handle.checkspace == 1));
}
......@@ -326,6 +330,7 @@ namespace Pamac {
}
alpm_utils.alpm_config.reload ();
alpm_utils.refresh_handle ();
database_modified ();
generate_mirrors_list_finished ();
}
......@@ -369,6 +374,7 @@ namespace Pamac {
if (authorized) {
alpm_utils.set_pkgreason (pkgname, reason);
}
database_modified ();
set_pkgreason_finished ();
});
}
......@@ -379,13 +385,6 @@ namespace Pamac {
return;
}
alpm_utils.force_refresh = force;
if (alpm_utils.force_refresh) {
refreshed = false;
}
if (refreshed) {
refresh_finished (true);
return;
}
if (alpm_utils.downloading_updates) {
alpm_utils.cancellable.cancel ();
// let time to cancel download updates
......@@ -541,12 +540,16 @@ namespace Pamac {
[DBus (no_reply = true)]
public void quit () throws Error {
// wait for all tasks to be processed
ThreadPool.free ((owned) thread_pool, false, true);
// do not quit if locked
if (lock_id != "" && lock_id != "extern"){
return;
}
// do not quit if downloading updates
if (alpm_utils.downloading_updates) {
return;
}
// wait for all tasks to be processed
ThreadPool.free ((owned) thread_pool, false, true);
loop.quit ();
}
}
......
......@@ -238,6 +238,25 @@ namespace Pamac {
}
}
protected override bool ask_review_build_files () {
// ask user confirmation
stdout.printf ("%s ? %s ", dgettext (null, "Review build files"), dgettext (null, "[y/N]"));
char buf[32];
if (stdin.gets (buf) != null) {
string ans = (string) buf;
// remove trailing newline and uppercase
ans = ans.replace ("\n", "").down ();
// just return use default
if (ans != "") {
if (ans == dgettext (null, "y") ||
ans == dgettext (null, "yes")) {
return true;
}
}
}
return false;
}
protected override bool ask_confirmation (TransactionSummary summary) {
uint64 dsize = 0;
uint64 rsize = 0;
......@@ -458,19 +477,25 @@ namespace Pamac {
protected override async void review_build_files (string pkgname) {
stdout.printf (dgettext (null, "Review %s build files".printf (pkgname)) + "\n");
Posix.sleep (1);
string builddir_name = Path.build_path ("/", database.config.aur_build_dir, "pamac-build", pkgname);
string pkgdir_name = Path.build_path ("/", database.config.aur_build_dir, "pamac-build", pkgname);
string[] cmds = {"nano", "-S", "-w", "-i"};
// diff
string diff_name = Path.build_path ("/", pkgdir_name, "diff");
var diff_file = File.new_for_path (diff_name);
if (diff_file.query_exists ()) {
cmds += diff_name;
}
// PKGBUILD
cmds += Path.build_path ("/", builddir_name, "PKGBUILD");
cmds += Path.build_path ("/", pkgdir_name, "PKGBUILD");
// other file
var build_dir = File.new_for_path (builddir_name);
var pkgdir = File.new_for_path (pkgdir_name);
try {
FileEnumerator enumerator = yield build_dir.enumerate_children_async ("standard::*", FileQueryInfoFlags.NONE);
FileEnumerator enumerator = yield pkgdir.enumerate_children_async ("standard::*", FileQueryInfoFlags.NONE);
FileInfo info;
while ((info = enumerator.next_file (null)) != null) {
unowned string filename = info.get_name ();
if (".install" in filename || ".patch" in filename) {
cmds += Path.build_path ("/", builddir_name, filename);
cmds += Path.build_path ("/", pkgdir_name, filename);
}
}
var process = new Subprocess.newv (cmds, SubprocessFlags.STDIN_INHERIT);
......
......@@ -34,6 +34,7 @@ namespace Pamac {
public Gtk.ApplicationWindow? application_window { get; construct; }
// ask_confirmation option
public bool no_confirm_upgrade { get; set; }
bool review_build_files_answer;
public TransactionGtk (Database database, Gtk.ApplicationWindow? application_window) {
Object (database: database, application_window: application_window);
......@@ -84,7 +85,6 @@ namespace Pamac {
warning_textbuffer.append (msg + "\n");
});
emit_error.connect (display_error);
refresh_finished.connect (on_refresh_finished);
finished.connect (on_finished);
sysupgrade_finished.connect (on_finished);
start_generating_mirrors_list.connect (start_progressbar_pulse);
......@@ -99,6 +99,7 @@ namespace Pamac {
// flags
set_trans_flags ();
no_confirm_upgrade = false;
review_build_files_answer = false;
}
void set_trans_flags () {
......@@ -229,6 +230,14 @@ namespace Pamac {
return index;
}
protected override bool ask_review_build_files () {
if (review_build_files_answer) {
review_build_files_answer = false;
return true;
}
return false;
}
protected override bool ask_confirmation (TransactionSummary summary) {
show_warnings (true);
uint must_confirm_length = summary.to_install.length ()
......@@ -244,6 +253,7 @@ namespace Pamac {
uint64 dsize = 0;
transaction_summary.remove_all ();
transaction_sum_dialog.sum_list.clear ();
transaction_sum_dialog.review_button.visible = false;
var iter = Gtk.TreeIter ();
if (summary.to_remove.length () > 0) {
foreach (unowned Package infos in summary.to_remove) {
......@@ -285,6 +295,7 @@ namespace Pamac {
transaction_sum_dialog.sum_list.set (iter, 0, "<b>%s</b>".printf (dgettext (null, "To downgrade") + ":"));
}
if (summary.to_build.length () > 0) {
transaction_sum_dialog.review_button.visible = true;
foreach (unowned AURPackage infos in summary.to_build) {
transaction_summary.add (infos.name);
transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
......@@ -344,13 +355,16 @@ namespace Pamac {
transaction_sum_dialog.top_label.set_markup ("<b>%s: %s</b>".printf (dgettext (null, "Total download size"), format_size (dsize)));
transaction_sum_dialog.top_label.visible = true;
}
if (transaction_sum_dialog.run () == Gtk.ResponseType.OK) {
var response = transaction_sum_dialog.run ();
if (response == Gtk.ResponseType.OK) {
transaction_sum_dialog.hide ();
return true;
} else {
transaction_sum_dialog.hide ();
transaction_summary.remove_all ();
}
if (response == Gtk.ResponseType.REJECT) {
review_build_files_answer = true;
}
transaction_sum_dialog.hide ();
transaction_summary.remove_all ();
return false;
}
......@@ -359,6 +373,8 @@ namespace Pamac {