Commit 4c401444 authored by guinux's avatar guinux

reliability improvements

parent a7ac8851
......@@ -5,9 +5,9 @@ Pamac is a Package Manager based on libalpm with AUR and Appstream support
- libpamac: Library to access package infos and run transactions
- Python bindings for libpamac
- pamac: a CLI
- pamac_manager/pamac-updater: a Gtk3 GUI
- pamac-manager/pamac-updater: a Gtk3 GUI
- pamac-tray: a Gtk3 tray icon with updates notifications
- ppamac-tray-appindicator: a AppIndicator tray icon with updates notifications
- pamac-tray-appindicator: a AppIndicator tray icon with updates notifications
#### Installing from source
......
......@@ -188,7 +188,7 @@ class GetInfosCase(unittest.TestCase):
loop.quit()
self.assertTrue(found)
self.db.search_in_aur_async(
self.db.search_in_aur(
'pamac', on_search_aur_pkgs_ready_callback, None)
loop.run()
......
This diff is collapsed.
......@@ -338,6 +338,12 @@ namespace Pamac {
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;
});
transaction.stop_preparing.connect (() => {
trans_cancellable = false;
});
transaction.start_downloading.connect (() => {
trans_cancellable = true;
});
......
This diff is collapsed.
......@@ -2843,9 +2843,11 @@ namespace Pamac {
void on_start_preparing () {
this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH));
cancel_button.sensitive = true;
}
void on_stop_preparing () {
cancel_button.sensitive = false;
this.get_window ().set_cursor (null);
// restore build_files_notebook
if (properties_listbox.get_selected_row ().get_index () == 3) {
......
......@@ -42,7 +42,7 @@ executable('pamac-clean-cache',
install: true)
executable('pamac-system-daemon',
sources: ['common_daemon.vala', 'package.vala', 'pamac_config.vala', 'alpm_config.vala', 'aur.vala', 'alpm_utils.vala', 'system_daemon.vala'],
sources: ['common_daemon.vala', 'package.vala', 'pamac_config.vala', 'alpm_config.vala', 'alpm_utils.vala', 'system_daemon.vala'],
dependencies: [vala_deps, alpm_deps, json, libsoup, polkit, libcurl, appstream],
vala_args: [common_vala_args, alpm_vala_args, '--thread'],
c_args: [common_c_args, alpm_c_args],
......
......@@ -487,13 +487,11 @@ namespace Pamac {
private void launch_prepare_thread () {
if (alpm_utils.to_build.length != 0) {
alpm_utils.compute_aur_build_list.begin (() => {
try {
thread_pool.add (new AlpmAction (alpm_utils.build_prepare));
} catch (ThreadError e) {
stderr.printf ("Thread Error %s\n", e.message);
}
});
try {
thread_pool.add (new AlpmAction (alpm_utils.build_prepare));
} catch (ThreadError e) {
stderr.printf ("Thread Error %s\n", e.message);
}
} else {
try {
thread_pool.add (new AlpmAction (alpm_utils.trans_prepare));
......
......@@ -456,6 +456,8 @@ 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[] cmds = {"nano", "-S", "-w", "-i"};
// PKGBUILD
......
......@@ -147,7 +147,9 @@ namespace Pamac {
current_action = action;
show_in_term (action);
progress_box.action_label.label = action;
progress_box.progressbar.fraction = 0;
if (pulse_timeout_id == 0) {
progress_box.progressbar.fraction = 0;
}
progress_box.progressbar.text = "";
}
}
......
......@@ -42,6 +42,9 @@ namespace Pamac {
string[] temporary_ignorepkgs;
string[] overwrite_files;
// building data
string aurdb_path;
GenericSet<string?> already_checked_aur_dep;
GenericSet<string?> aur_desc_list;
Queue<string> to_build_queue;
string[] aur_pkgs_to_install;
GenericSet<string?> build_files_reviewed;
......@@ -92,7 +95,7 @@ namespace Pamac {
construct {
if (Posix.geteuid () == 0) {
// we are root
transaction_interface = new TransactionInterfaceRoot ();
transaction_interface = new TransactionInterfaceRoot (database.config);
} else {
// use dbus daemon
transaction_interface = new TransactionInterfaceDaemon (database.config);
......@@ -110,6 +113,9 @@ namespace Pamac {
temporary_ignorepkgs = {};
overwrite_files = {};
// building data
aurdb_path = "/tmp/pamac-aur";
already_checked_aur_dep = new GenericSet<string?> (str_hash, str_equal);
aur_desc_list = new GenericSet<string?> (str_hash, str_equal);
to_build_queue = new Queue<string> ();
build_files_reviewed = new GenericSet<string?> (str_hash, str_equal);
build_cancellable = new Cancellable ();
......@@ -239,6 +245,164 @@ namespace Pamac {
downloading_updates_finished ();
}
async void compute_aur_build_list () {
try {
Process.spawn_command_line_sync ("mkdir -p %s".printf (aurdb_path));
} catch (SpawnError e) {
stderr.printf ("SpawnError: %s\n", e.message);
}
aur_desc_list.remove_all ();
already_checked_aur_dep.remove_all ();
yield check_aur_dep_list (to_build);
// 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 (database.get_db_path ()));
Process.spawn_command_line_sync ("bsdtar -cf %ssync/aur.db -C %s %s".printf (database.get_db_path (), aurdb_path, list.str));
} catch (SpawnError e) {
stderr.printf ("SpawnError: %s\n", e.message);
}
}
async void check_aur_dep_list (string[] pkgnames) {
string[] dep_to_check = {};
foreach (unowned string name in pkgnames) {
if (build_cancellable.is_cancelled ()) {
break;
}
string version = "";
string pkgbase = "";
string desc = "";
string[] depends = {};
string[] conflicts = {};
string[] provides = {};
string[] replaces = {};
// clone build files
emit_action (dgettext (null, "Checking %s build files".printf (name)) + "...");
string pkgdir_name = yield database.clone_build_files (name, false);
if (pkgdir_name == "") {
// error
continue;
}
// read .SRCINFO
var srcinfo = File.new_for_path (pkgdir_name + "/.SRCINFO");
try {
var dis = new DataInputStream (srcinfo.read ());
string line;
while ((line = dis.read_line ()) != null) {
if ("pkgbase = " in line) {
pkgbase = line.split ("pkgbase = ", 2)[1];
} else if ("pkgdesc = " in line) {
desc = line.split ("pkgdesc = ", 2)[1];
} else if ("pkgver = " in line) {
version = line.split ("pkgver = ", 2)[1];
} else if ("pkgrel = " in line) {
version += "-";
version += line.split ("pkgrel = ", 2)[1];
// compute depends, makedepends and checkdepends in depends
} else if ("checkdepends = " in line) {
depends += line.split ("checkdepends = ", 2)[1];
} else if ("makedepends = " in line) {
depends += line.split ("makedepends = ", 2)[1];
} else if ("depends = " in line) {
depends += line.split ("depends = ", 2)[1];
} else if ("provides = " in line) {
provides += line.split ("provides = ", 2)[1];
} else if ("conflicts = " in line) {
conflicts += line.split ("conflicts = ", 2)[1];
} else if ("replaces = " in line) {
replaces += line.split ("replaces = ", 2)[1];
}
}
// check deps
foreach (unowned string dep_string in depends) {
var pkg = database.find_installed_satisfier (dep_string);
if (pkg.name == "") {
pkg = database.find_sync_satisfier (dep_string);
}
if (pkg.name == "") {
string dep_name = Alpm.Depend.from_string (dep_string).name;
if (!(dep_name in already_checked_aur_dep)) {
already_checked_aur_dep.add (dep_name);
var aur_pkg = yield database.get_aur_pkg (dep_name);
if (aur_pkg.name != "") {
dep_to_check += (owned) dep_name;
}
}
}
}
// write desc file
string pkgdir = "%s-%s".printf (name, version);
string pkgdir_path = "%s/%s".printf (aurdb_path, pkgdir);
aur_desc_list.add (pkgdir);
var file = GLib.File.new_for_path (pkgdir_path);
// always recreate desc in case of .SRCINFO modifications
if (file.query_exists ()) {
Process.spawn_command_line_sync ("rm -rf %s".printf (pkgdir_path));
}
file.make_directory ();
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 (pkgbase));
// desc
dos.put_string ("%DESC%\n%s\n\n".printf (desc));
// version
dos.put_string ("%VERSION%\n%s\n\n".printf (version));
// fake arch
dos.put_string ("%ARCH%\nany\n\n");
// depends
if (depends.length > 0) {
dos.put_string ("%DEPENDS%\n");
foreach (unowned string depend in depends) {
dos.put_string ("%s\n".printf (depend));
}
dos.put_string ("\n");
}
// conflicts
if (conflicts.length > 0) {
dos.put_string ("%CONFLICTS%\n");
foreach (unowned string conflict in conflicts) {
dos.put_string ("%s\n".printf (conflict));
}
dos.put_string ("\n");
}
// provides
if (provides.length > 0) {
dos.put_string ("%PROVIDES%\n");
foreach (unowned string provide in provides) {
dos.put_string ("%s\n".printf (provide));
}
dos.put_string ("\n");
}
// replaces
if (replaces.length > 0) {
dos.put_string ("%REPLACES%\n");
foreach (unowned string replace in replaces) {
dos.put_string ("%s\n".printf (replace));
}
dos.put_string ("\n");
}
} 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);
}
}
void sysupgrade_real () {
// this will respond with trans_prepare_finished signal
transaction_interface.start_sysupgrade_prepare (enable_downgrade, temporary_ignorepkgs, to_build, overwrite_files);
......@@ -268,7 +432,20 @@ namespace Pamac {
}
void trans_prepare_real () {
transaction_interface.start_trans_prepare (flags, to_install, to_remove, to_load, to_build, overwrite_files);
if (to_build.length != 0) {
// set building to allow cancellation
building = true;
build_cancellable.reset ();
compute_aur_build_list.begin (() => {
building = false;
if (build_cancellable.is_cancelled ()) {
on_trans_prepare_finished (false);
}
transaction_interface.start_trans_prepare (flags, to_install, to_remove, to_load, to_build, overwrite_files);
});
} else {
transaction_interface.start_trans_prepare (flags, to_install, to_remove, to_load, to_build, overwrite_files);
}
}
public void start (string[] to_install, string[] to_remove, string[] to_load, string[] to_build, string[] overwrite_files) {
......@@ -343,7 +520,7 @@ namespace Pamac {
var dis = new DataInputStream (process.get_stdout_pipe ());
string? line;
// Read lines until end of file (null) is reached
while ((line = dis.read_line ()) != null) {
while ((line = yield dis.read_line_async ()) != null) {
var file = GLib.File.new_for_path (line);
string filename = file.get_basename ();
string name_version_release = filename.slice (0, filename.last_index_of_char ('-'));
......
......@@ -20,9 +20,9 @@
namespace Pamac {
internal class TransactionInterfaceRoot: Object, TransactionInterface {
public TransactionInterfaceRoot () {
public TransactionInterfaceRoot (Config config) {
// alpm_utils global variable declared in alpm_utils.vala
// and initiate in database.vala
alpm_utils = new AlpmUtils (config);
alpm_utils.emit_event.connect ((primary_event, secondary_event, details) => {
emit_event (primary_event, secondary_event, details);
});
......@@ -229,6 +229,11 @@ namespace Pamac {
}
}
int build_prepare () {
alpm_utils.build_prepare ();
return 0;
}
int trans_prepare () {
alpm_utils.trans_prepare ();
return 0;
......@@ -236,9 +241,7 @@ namespace Pamac {
private void launch_prepare () {
if (alpm_utils.to_build.length != 0) {
alpm_utils.compute_aur_build_list.begin (() => {
alpm_utils.build_prepare ();
});
new Thread<int> ("build_prepare", build_prepare);
} else {
new Thread<int> ("trans_prepare", trans_prepare);
}
......
......@@ -27,6 +27,7 @@ namespace Pamac {
indicator_status_icon.set_status (AppIndicator.IndicatorStatus.PASSIVE);
// add a item without label to not show it in menu
// this allow left click action
var menu = create_menu ();
var item = new Gtk.MenuItem ();
item.visible = true;
item.activate.connect (left_clicked);
......
......@@ -31,6 +31,7 @@ namespace Pamac {
// Show popup menu on right button
void menu_popup () {
var menu = create_menu ();
menu.popup_at_pointer (null);
}
......
......@@ -39,11 +39,9 @@ namespace Pamac {
public abstract class TrayIcon: Gtk.Application {
Notify.Notification notification;
Database database;
SystemDaemon system_daemon;
bool extern_lock;
uint refresh_timeout_id;
public Gtk.Menu menu;
GLib.File lockfile;
uint updates_nb;
......@@ -52,27 +50,12 @@ namespace Pamac {
flags = ApplicationFlags.FLAGS_NONE;
}
void init_database () {
var config = new Config ("/etc/pamac.conf");
database = new Database (config);
database.refresh_files_dbs_on_get_updates = true;
database.config.notify["refresh-period"].connect((obj, prop) => {
launch_refresh_timeout (database.config.refresh_period);
});
database.config.notify["check-aur-updates"].connect((obj, prop) => {
check_updates ();
});
database.config.notify["no-update-hide-icon"].connect((obj, prop) => {
set_icon_visible (!database.config.no_update_hide_icon);
});
}
void start_system_daemon () {
void start_system_daemon (HashTable<string,string> environment_variables) {
if (system_daemon == null) {
try {
system_daemon = Bus.get_proxy_sync (BusType.SYSTEM, "org.manjaro.pamac.system", "/org/manjaro/pamac/system");
// Set environment variables
system_daemon.set_environment_variables (database.config.environment_variables);
system_daemon.set_environment_variables (environment_variables);
system_daemon.downloading_updates_finished.connect (on_downloading_updates_finished);
system_daemon.write_pamac_config_finished.connect (on_write_pamac_config_finished);
} catch (Error e) {
......@@ -94,8 +77,8 @@ namespace Pamac {
public abstract void init_status_icon ();
// Create menu for right button
void create_menu () {
menu = new Gtk.Menu ();
public Gtk.Menu create_menu () {
var menu = new Gtk.Menu ();
var item = new Gtk.MenuItem.with_label (_("Package Manager"));
item.activate.connect (execute_manager);
menu.append (item);
......@@ -103,6 +86,7 @@ namespace Pamac {
item.activate.connect (this.release);
menu.append (item);
menu.show_all ();
return menu;
}
public void left_clicked () {
......@@ -138,28 +122,51 @@ namespace Pamac {
public abstract void set_icon_visible (bool visible);
bool check_updates () {
if (database.config.refresh_period != 0) {
database.get_updates.begin ((obj, res) => {
var updates = database.get_updates.end (res);
updates_nb = updates.repos_updates.length () + updates.aur_updates.length ();
if (updates_nb == 0) {
set_icon (noupdate_icon_name);
set_tooltip (noupdate_info);
set_icon_visible (!database.config.no_update_hide_icon);
close_notification ();
} else {
if (!check_pamac_running () && database.config.download_updates) {
start_system_daemon ();
try {
system_daemon.start_download_updates ();
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
var config = new Config ("/etc/pamac.conf");
if (config.refresh_period != 0) {
// get updates
string[] cmds = {"pamac", "checkupdates"};
if (config.check_aur_updates) {
cmds += "-a";
}
try {
var process = new Subprocess.newv (cmds, SubprocessFlags.STDOUT_PIPE);
process.wait ();
if (process.get_if_exited ()) {
int status = process.get_exit_status ();
// status 100 means updates are available
if (status == 100) {
var dis = new DataInputStream (process.get_stdout_pipe ());
updates_nb = 0;
// count lines
while (dis.read_line () != null) {
updates_nb++;
}
// remove the first which is not an update
updates_nb--;
if (!check_pamac_running () && config.download_updates) {
start_system_daemon (config.environment_variables);
try {
system_daemon.start_download_updates ();
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
} else {
show_or_update_notification ();
}
// refresh files dbs in tmp
var database = new Database (config);
database.refresh_files_dbs ();
} else {
show_or_update_notification ();
set_icon (noupdate_icon_name);
set_tooltip (noupdate_info);
set_icon_visible (!config.no_update_hide_icon);
close_notification ();
}
}
});
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
}
return true;
}
......@@ -169,8 +176,12 @@ namespace Pamac {
stop_system_daemon ();
}
void on_write_pamac_config_finished () {
database.config.reload ();
void on_write_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon,
bool enable_aur, string aur_build_dir, bool check_aur_updates,
bool download_updates) {
set_icon_visible (!no_update_hide_icon);
launch_refresh_timeout (refresh_period);
check_updates ();
}
void show_or_update_notification () {
......@@ -277,9 +288,9 @@ namespace Pamac {
Intl.textdomain ("pamac");
Intl.setlocale (LocaleCategory.ALL, "");
init_database ();
var config = new Config ("/etc/pamac.conf");
// if refresh period is 0, just return so tray will exit
if (database.config.refresh_period == 0) {
if (config.refresh_period == 0) {
return;
}
......@@ -288,18 +299,18 @@ namespace Pamac {
extern_lock = false;
refresh_timeout_id = 0;
create_menu ();
init_status_icon ();
set_icon (noupdate_icon_name);
set_tooltip (noupdate_info);
set_icon_visible (!database.config.no_update_hide_icon);
set_icon_visible (!config.no_update_hide_icon);
Notify.init (_("Package Manager"));
start_system_daemon ();
start_system_daemon (config.environment_variables);
// start and stop daemon just to connect to signal
stop_system_daemon ();
var database = new Database (config);
lockfile = GLib.File.new_for_path (database.get_lockfile ());
Timeout.add (200, check_extern_lock);
// wait 30 seconds before check updates
......@@ -307,7 +318,7 @@ namespace Pamac {
check_updates ();
return false;
});
launch_refresh_timeout (database.config.refresh_period);
launch_refresh_timeout (config.refresh_period);
this.hold ();
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment