first commit

This commit is contained in:
guinux
2014-10-22 18:44:02 +02:00
commit 60a34f6681
69 changed files with 9721 additions and 0 deletions

146
src/Makefile Normal file
View File

@@ -0,0 +1,146 @@
COMMON_VALA_FLAGS = --pkg=libalpm \
--pkg=gio-2.0 \
--pkg=posix \
--pkg=json-glib-1.0 \
--pkg=libsoup-2.4 \
--vapidir=../vapi \
--Xcc=-I../util \
-X -D_FILE_OFFSET_BITS=64 \
--target-glib=2.38
COMMON_SOURCES = ../util/alpm-util.c \
alpm_config.vala \
pamac_config.vala \
aur.vala \
common.vala
MANAGER_GRESOURCE_FILE = ../resources/pamac.manager.gresource.xml
MANAGER_RESOURCES_FILES = ../resources/manager_window.ui \
../resources/packages_chooser_dialog.ui \
../resources/history_dialog.ui \
../resources/preferences_dialog.ui \
../resources/progress_window.ui \
../resources/choose_provider_dialog.ui \
../resources/transaction_sum_dialog.ui \
../resources/transaction_info_dialog.ui \
../resources/package-available.png \
../resources/package-install.png \
../resources/package-installed-locked.png \
../resources/package-installed-updated.png \
../resources/package-reinstall.png \
../resources/package-remove.png
UPDATER_GRESOURCE_FILE = ../resources/pamac.updater.gresource.xml
UPDATER_RESOURCES_FILES = ../resources/updater_window.ui \
../resources/preferences_dialog.ui \
../resources/progress_window.ui \
../resources/choose_provider_dialog.ui \
../resources/transaction_sum_dialog.ui \
../resources/transaction_info_dialog.ui
INSTALLER_GRESOURCE_FILE = ../resources/pamac.installer.gresource.xml
INSTALLER_RESOURCES_FILES = ../resources/progress_window.ui \
../resources/choose_provider_dialog.ui \
../resources/transaction_sum_dialog.ui \
../resources/transaction_info_dialog.ui
DIALOGS_FILES = choose_provider_dialog.vala \
transaction_sum_dialog.vala \
transaction_info_dialog.vala \
progress_window.vala
pamac-daemon: $(COMMON_SOURCES) daemon.vala
valac -o pamac-daemon \
$(COMMON_VALA_FLAGS) \
--pkg=polkit-gobject-1 \
-X -DGETTEXT_PACKAGE="pacman" \
--thread \
$(COMMON_SOURCES) \
daemon.vala
pamac-tray: $(COMMON_SOURCES) tray.vala
valac -o pamac-tray \
$(COMMON_VALA_FLAGS) \
--pkg=gtk+-3.0 \
--pkg=libnotify \
-X -DGETTEXT_PACKAGE="pamac" \
$(COMMON_SOURCES) \
tray.vala
manager_resources.c: $(MANAGER_GRESOURCE_FILE) $(MANAGER_RESOURCES_FILES)
glib-compile-resources $(MANAGER_GRESOURCE_FILE) --sourcedir=../resources --target=manager_resources.c --generate-source
updater_resources.c: $(UPDATER_GRESOURCE_FILE) $(UPDATER_RESOURCES_FILES)
glib-compile-resources $(UPDATER_GRESOURCE_FILE) --sourcedir=../resources --target=updater_resources.c --generate-source
installer_resources.c: $(INSTALLER_GRESOURCE_FILE) $(INSTALLER_RESOURCES_FILES)
glib-compile-resources $(INSTALLER_GRESOURCE_FILE) --sourcedir=../resources --target=installer_resources.c --generate-source
pamac-manager: $(COMMON_SOURCES) $(DIALOGS_FILES) preferences_dialog.vala history_dialog.vala packages_chooser_dialog.vala manager_resources.c package.vala transaction.vala packages_model.vala manager_window.vala manager.vala
valac -o pamac-manager \
$(COMMON_VALA_FLAGS) \
--pkg=gtk+-3.0 \
--pkg=gmodule-2.0 \
--pkg=gdk-3.0 \
--pkg=vte-2.91 \
--gresources=$(MANAGER_GRESOURCE_FILE) \
-X -DGETTEXT_PACKAGE="pamac" \
$(COMMON_SOURCES) \
$(DIALOGS_FILES) \
preferences_dialog.vala \
history_dialog.vala \
packages_chooser_dialog.vala \
manager_resources.c \
package.vala \
transaction.vala \
packages_model.vala \
manager_window.vala \
manager.vala
pamac-updater: $(COMMON_SOURCES) $(DIALOGS_FILES) preferences_dialog.vala updater_resources.c transaction.vala updater_window.vala updater.vala
valac -o pamac-updater \
$(COMMON_VALA_FLAGS) \
--pkg=gtk+-3.0 \
--pkg=gmodule-2.0 \
--pkg=vte-2.91 \
--gresources=$(UPDATER_GRESOURCE_FILE) \
-X -DGETTEXT_PACKAGE="pamac" \
$(COMMON_SOURCES) \
$(DIALOGS_FILES) \
preferences_dialog.vala \
updater_resources.c \
transaction.vala \
updater_window.vala \
updater.vala
pamac-install: $(COMMON_SOURCES) $(DIALOGS_FILES) installer_resources.c transaction.vala installer.vala
valac -o pamac-install \
$(COMMON_VALA_FLAGS) \
--pkg=gtk+-3.0 \
--pkg=gmodule-2.0 \
--pkg=vte-2.91 \
--gresources=$(INSTALLER_GRESOURCE_FILE) \
-X -DGETTEXT_PACKAGE="pamac" \
$(COMMON_SOURCES) \
$(DIALOGS_FILES) \
installer_resources.c \
transaction.vala \
installer.vala
all: pamac-daemon pamac-tray pamac-updater pamac-manager pamac-install
clean:
rm -f *.c pamac-daemon pamac-tray pamac-updater pamac-manager pamac-install
install:
install -Dm744 pamac-daemon /usr/bin/pamac-daemon
install -Dm755 pamac-tray /usr/bin/pamac-tray
install -Dm755 pamac-manager /usr/bin/pamac-manager
install -Dm755 pamac-updater /usr/bin/pamac-updater
install -Dm755 pamac-install /usr/bin/pamac-install
uninstall:
rm -f /usr/bin/pamac-daemon /usr/bin/pamac-updater /usr/bin/pamac-tray /usr/bin/pamac-manager /usr/bin/pamac-install

258
src/alpm_config.vala Normal file
View File

@@ -0,0 +1,258 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Alpm {
class Repo {
public string name;
public SigLevel siglevel;
public string[] urls;
public Repo (string name) {
this.name = name;
urls = {};
}
}
public class Config {
public Handle handle;
private string[] priv_holdpkg;
private string[] priv_syncfirst;
public string[] holdpkg;
public string[] syncfirst;
SigLevel siglevel;
SigLevel localfilesiglevel;
SigLevel remotefilesiglevel;
Repo[] repo_order;
public Config (string path) {
// rootdir and dbpath are hardcoded so we parse config file only once
const string rootdir = "/";
const string dbpath = "/var/lib/pacman";
Alpm.Errno error;
handle = new Handle (rootdir, dbpath, out error);
const string gpgdir = "/etc/pacman.d/gnupg/";
const string logfile = "/var/log/pacman.log";
const string cachedir = "/var/cache/pacman/pkg/";
priv_holdpkg = {};
priv_syncfirst = {};
siglevel = SigLevel.PACKAGE | SigLevel.PACKAGE_OPTIONAL | SigLevel.DATABASE | SigLevel.DATABASE_OPTIONAL;
localfilesiglevel = SigLevel.USE_DEFAULT;
remotefilesiglevel = SigLevel.USE_DEFAULT;
repo_order = {};
// parse conf file
parse_file (path);
// check essential settings
if (handle.gpgdir == null) handle.gpgdir = gpgdir;
if (handle.logfile == null) handle.logfile = logfile;
if (handle.arch == null) handle.arch = Posix.utsname().machine;
if (handle.cachedirs == null) handle.add_cachedir(cachedir);
// register dbs
foreach (Repo repo in repo_order) {
unowned DB db = handle.register_syncdb (repo.name, repo.siglevel);
foreach (string url in repo.urls) {
db.add_server (url.replace ("$repo", repo.name).replace ("$arch", handle.arch));
}
}
}
public void parse_file (string path, string? section = null) {
string current_section = section;
var file = GLib.File.new_for_path (path);
if (file.query_exists () == false)
GLib.stderr.printf ("File '%s' doesn't exist.\n", file.get_path ());
else {
try {
// Open file for reading and wrap returned FileInputStream into a
// DataInputStream, so we can read line by line
var dis = new DataInputStream (file.read ());
string line;
// Read lines until end of file (null) is reached
while ((line = dis.read_line (null)) != null) {
line = line.strip ();
if (line.length == 0) continue;
if (line[0] == '#') continue;
if (line[0] == '[' && line[line.length-1] == ']') {
current_section = line[1:-1];
if (current_section != "options") {
Repo repo = new Repo (current_section);
repo.siglevel = siglevel;
repo_order += repo;
}
continue;
}
string[] splitted = line.split ("=");
string _key = splitted[0].strip ();
string _value = null;
if (splitted[1] != null)
_value = splitted[1].strip ();
if (_key == "Include")
parse_file (_value, current_section);
if (current_section == "options") {
if (_key == "GPGDir")
handle.gpgdir = _value;
else if (_key == "LogFile")
handle.logfile = _value;
else if (_key == "Architecture") {
if (_value == "auto")
handle.arch = Posix.utsname ().machine;
else
handle.arch = _value;
} else if (_key == "UseDelta")
handle.deltaratio = double.parse (_value);
else if (_key == "UseSysLog")
handle.usesyslog = 1;
else if (_key == "CheckSpace")
handle.checkspace = 1;
else if (_key == "SigLevel")
siglevel = define_siglevel (siglevel, _value);
else if (_key == "LocalSigLevel")
handle.localfilesiglevel = merge_siglevel (siglevel, define_siglevel (localfilesiglevel, _value));
else if (_key == "RemoteSigLevel")
handle.remotefilesiglevel = merge_siglevel (siglevel, define_siglevel (remotefilesiglevel, _value));
else if (_key == "HoldPkg") {
foreach (string name in _value.split (" ")) {
priv_holdpkg += name;
}
} else if (_key == "SyncFirst") {
foreach (string name in _value.split (" ")) {
priv_syncfirst += name;
}
} else if (_key == "CacheDir") {
foreach (string dir in _value.split (" ")) {
handle.add_cachedir (dir);
}
} else if (_key == "IgnoreGroup") {
foreach (string name in _value.split (" ")) {
handle.add_ignoregroup (name);
}
} else if (_key == "IgnorePkg") {
foreach (string name in _value.split (" ")) {
handle.add_ignorepkg (name);
}
} else if (_key == "Noextract") {
foreach (string name in _value.split (" ")) {
handle.add_noextract (name);
}
} else if (_key == "NoUpgrade") {
foreach (string name in _value.split (" ")) {
handle.add_noupgrade (name);
}
}
} else {
foreach (Repo _repo in repo_order) {
if (_repo.name == current_section) {
if (_key == "Server")
_repo.urls += _value;
else if (_key == "SigLevel")
_repo.siglevel = define_siglevel(siglevel, _value);
}
}
}
}
} catch (GLib.Error e) {
GLib.stderr.printf("%s\n", e.message);
}
holdpkg = priv_holdpkg;
syncfirst = priv_syncfirst;
}
}
public SigLevel define_siglevel (SigLevel default_level, string conf_string) {
foreach (string directive in conf_string.split(" ")) {
bool affect_package = false;
bool affect_database = false;
if ("Package" in directive) affect_package = true;
else if ("Database" in directive) affect_database = true;
else {
affect_package = true;
affect_database = true;
}
if ("Never" in directive) {
if (affect_package) {
default_level &= ~SigLevel.PACKAGE;
default_level |= SigLevel.PACKAGE_SET;
}
if (affect_database) default_level &= ~SigLevel.DATABASE;
}
else if ("Optional" in directive) {
if (affect_package) {
default_level |= SigLevel.PACKAGE;
default_level |= SigLevel.PACKAGE_OPTIONAL;
default_level |= SigLevel.PACKAGE_SET;
}
if (affect_database) {
default_level |= SigLevel.DATABASE;
default_level |= SigLevel.DATABASE_OPTIONAL;
}
}
else if ("Required" in directive) {
if (affect_package) {
default_level |= SigLevel.PACKAGE;
default_level &= ~SigLevel.PACKAGE_OPTIONAL;
default_level |= SigLevel.PACKAGE_SET;
}
if (affect_database) {
default_level |= SigLevel.DATABASE;
default_level &= ~SigLevel.DATABASE_OPTIONAL;
}
}
else if ("TrustedOnly" in directive) {
if (affect_package) {
default_level &= ~SigLevel.PACKAGE_MARGINAL_OK;
default_level &= ~SigLevel.PACKAGE_UNKNOWN_OK;
default_level |= SigLevel.PACKAGE_TRUST_SET;
}
if (affect_database) {
default_level &= ~SigLevel.DATABASE_MARGINAL_OK;
default_level &= ~SigLevel.DATABASE_UNKNOWN_OK;
}
}
else if ("TrustAll" in directive) {
if (affect_package) {
default_level |= SigLevel.PACKAGE_MARGINAL_OK;
default_level |= SigLevel.PACKAGE_UNKNOWN_OK;
default_level |= SigLevel.PACKAGE_TRUST_SET;
}
if (affect_database) {
default_level |= SigLevel.DATABASE_MARGINAL_OK;
default_level |= SigLevel.DATABASE_UNKNOWN_OK;
}
}
else GLib.stderr.printf("unrecognized siglevel: %s\n", conf_string);
}
default_level &= ~SigLevel.USE_DEFAULT;
return default_level;
}
public SigLevel merge_siglevel (SigLevel base_level, SigLevel over_level) {
if ((over_level & SigLevel.USE_DEFAULT) != 0) over_level = base_level;
else {
if ((over_level & SigLevel.PACKAGE_SET) == 0) {
over_level |= base_level & SigLevel.PACKAGE;
over_level |= base_level & SigLevel.PACKAGE_OPTIONAL;
}
if ((over_level & SigLevel.PACKAGE_TRUST_SET) == 0) {
over_level |= base_level & SigLevel.PACKAGE_MARGINAL_OK;
over_level |= base_level & SigLevel.PACKAGE_UNKNOWN_OK;
}
}
return over_level;
}
}
}

102
src/aur.vala Normal file
View File

@@ -0,0 +1,102 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//~ const string srcpkgdir = "/tmp/pamac";
namespace AUR {
// AUR urls
const string aur_url = "http://aur.archlinux.org";
const string rpc_url = aur_url + "/rpc.php";
const string rpc_search = "?type=search&arg=";
const string rpc_info = "?type=info&arg=";
const string rpc_multiinfo = "?type=multiinfo";
const string rpc_multiinfo_arg = "&arg[]=";
const string aur_url_id = "/packages.php?setlang=en&ID=";
public Json.Array search (string needle) {
string uri = rpc_url + rpc_search + needle;
var session = new Soup.Session ();
var message = new Soup.Message ("GET", uri);
session.send_message (message);
Json.Array results = new Json.Array ();
try {
var parser = new Json.Parser ();
parser.load_from_data ((string) message.response_body.flatten ().data, -1);
unowned Json.Object root_object = parser.get_root ().get_object ();
results = root_object.get_array_member ("results");
//~ foreach (unowned Json.Node node in results.get_elements ()) {
//~ Json.Object pkg_info = node.get_object ();
//~ results.append (new Pamac.Package (null, pkg_info));
//~ }
} catch (Error e) {
print (e.message);
}
return results;
}
public Json.Object? info (string pkgname) {
unowned Json.Object? pkg_info = null;
string uri = rpc_url + rpc_info + pkgname;
stdout.printf("get %s from AUR\n", pkgname);
var session = new Soup.Session ();
var message = new Soup.Message ("GET", uri);
session.send_message (message);
try {
var parser = new Json.Parser ();
parser.load_from_data ((string) message.response_body.flatten ().data, -1);
pkg_info = parser.get_root ().get_object ().get_object_member ("results");
} catch (Error e) {
stderr.printf ("Failed to get infos about %s from AUR\n", pkgname);
print (e.message);
}
return pkg_info;
}
public Json.Array multiinfo (string[] pkgnames) {
Json.Array results = new Json.Array ();
var builder = new StringBuilder ();
builder.append (rpc_url);
builder.append (rpc_multiinfo);
foreach (string pkgname in pkgnames) {
builder.append (rpc_multiinfo_arg);
builder.append (pkgname);
}
var session = new Soup.Session ();
var message = new Soup.Message ("GET", builder.str);
session.send_message (message);
try {
var parser = new Json.Parser ();
parser.load_from_data ((string) message.response_body.flatten ().data, -1);
unowned Json.Object root_object = parser.get_root ().get_object ();
results = root_object.get_array_member ("results");
//~ foreach (var node in results.get_elements ()) {
//~ var pkg_info = node.get_object ();
//~ results.append (new Pamac.Package (null, pkg_info));
//~ }
} catch (Error e) {
print (e.message);
}
return results;
}
}

72
src/aur3.vala Normal file
View File

@@ -0,0 +1,72 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//~ const string srcpkgdir = "/tmp/pamac";
namespace AUR {
// AUR urls
const string aur_url = "http://aur3.org/";
public string[] search (string needle) {
string[] results = {};
try {
// Resolve hostname to IP address
var resolver = Resolver.get_default ();
var addresses = resolver.lookup_by_name (host, null);
var address = addresses.nth_data (0);
// Connect
var client = new SocketClient ();
var conn = client.connect (new InetSocketAddress (address, 1819));
// Send HTTP GET request
var message = @"nd $query";
conn.output_stream.write (message.data);
// Receive response
var response = new DataInputStream (conn.input_stream);
string line;
while ((line = response.read_line (null)) != null) {
results += line;
}
} catch (Error e) {
stderr.printf ("%s\n", e.message);
}
return results;
}
public void info (string pkgname) {
string uri = rpc_url + rpc_info + pkgname;
var session = new Soup.Session ();
var message = new Soup.Message ("GET", uri);
session.send_message (message);
try {
var parser = new Json.Parser ();
parser.load_from_data ((string) message.response_body.flatten ().data, -1);
var root_object = parser.get_root ().get_object ();
var pkg_info = root_object.get_object_member ("results");
AUR.Pkg aur_pkg = new AUR.Pkg (pkg_info);
stdout.printf ("got %s (%s)\n", aur_pkg.name, aur_pkg.license);
} catch (Error e) {
stderr.printf ("Failed to get infos about %s from AUR\n", pkgname);
print (e.message);
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
[GtkTemplate (ui = "/org/manjaro/pamac/transaction/choose_provider_dialog.ui")]
public class ChooseProviderDialog : Gtk.Dialog {
[GtkChild]
public Gtk.Label label;
[GtkChild]
public Gtk.ComboBoxText comboboxtext;
public ChooseProviderDialog (Gtk.ApplicationWindow? window) {
Object (transient_for: window, use_header_bar: 0);
}
}
}

265
src/common.vala Normal file
View File

@@ -0,0 +1,265 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
public struct UpdatesInfos {
public string name;
public string version;
public string db_name;
public string tarpath;
public uint64 download_size;
}
public struct Updates {
public bool syncfirst;
public UpdatesInfos[] infos;
}
public enum Mode {
MANAGER,
UPDATER,
NO_CONFIRM
}
public struct TransactionData {
public Alpm.TransFlag flags;
// those hashtables will be used as set
public HashTable<string, string> to_add;
public HashTable<string, string> to_remove;
public HashTable<string, string> to_load;
public HashTable<string, string> to_build;
}
public struct ErrorInfos {
public string str;
public string[] details;
public ErrorInfos () {
str = "";
details = {};
}
}
}
public string format_size (uint64 size) {
float KiB_size = size / 1024;
if (KiB_size < 1000) {
string size_string = dgettext ("pamac", "%.0f KiB").printf (KiB_size);
return size_string;
} else {
string size_string = dgettext ("pamac", "%.2f MiB").printf (KiB_size / 1024);
return size_string;
}
}
public int pkgcmp (Alpm.Package pkg1, Alpm.Package pkg2) {
return strcmp (pkg1.name, pkg2.name);
}
public unowned Alpm.List<Alpm.Package?> search_all_dbs (Alpm.Handle handle, Alpm.List<string?> needles) {
unowned Alpm.List<Alpm.Package?> syncpkgs = null;
unowned Alpm.List<Alpm.Package?> tmp = null;
unowned Alpm.List<Alpm.Package?> diff = null;
unowned Alpm.List<Alpm.Package?> result = null;
result = handle.localdb.search (needles);
foreach (unowned Alpm.DB db in handle.syncdbs) {
if (syncpkgs.length == 0)
syncpkgs = db.search (needles);
else {
tmp = db.search (needles);
diff = tmp.diff (syncpkgs, (Alpm.List.CompareFunc) pkgcmp);
syncpkgs.join (diff);
}
}
diff = syncpkgs.diff (result, (Alpm.List.CompareFunc) pkgcmp);
result.join (diff);
//result.sort ((Alpm.List.CompareFunc) pkgcmp);
return result;
}
public unowned Alpm.List<Alpm.Package?> group_pkgs_all_dbs (Alpm.Handle handle, string grp_name) {
unowned Alpm.List<Alpm.Package?> result = null;
unowned Alpm.Group? grp = handle.localdb.get_group (grp_name);
if (grp != null) {
foreach (unowned Alpm.Package pkg in grp.packages)
result.add (pkg);
}
// FIX IT: provided methods don't work for syncdbs so it's done manually
foreach (unowned Alpm.DB db in handle.syncdbs) {
foreach (unowned Alpm.Package pkg in db.pkgcache) {
foreach (string name in pkg.groups) {
if (name == grp_name) {
if (Alpm.pkg_find (result, pkg.name) == null)
result.add (pkg);
}
}
}
}
//result.sort ((Alpm.List.CompareFunc) pkgcmp);
return result;
}
public unowned Alpm.List<Alpm.Package?> get_all_pkgs (Alpm.Handle handle) {
unowned Alpm.List<Alpm.Package?> syncpkgs = null;
unowned Alpm.List<Alpm.Package?> tmp = null;
unowned Alpm.List<Alpm.Package?> diff = null;
unowned Alpm.List<Alpm.Package?> result = null;
result = handle.localdb.pkgcache;
foreach (unowned Alpm.DB db in handle.syncdbs) {
if (syncpkgs.length == 0)
syncpkgs = db.pkgcache;
else {
tmp = db.pkgcache;
diff = tmp.diff (syncpkgs, (Alpm.List.CompareFunc) pkgcmp);
syncpkgs.join (diff);
}
}
diff = syncpkgs.diff (result, (Alpm.List.CompareFunc) pkgcmp);
result.join (diff);
//result.sort ((Alpm.List.CompareFunc) pkgcmp);
return result;
}
public unowned Alpm.Package? get_syncpkg (Alpm.Handle handle, string name) {
unowned Alpm.Package? pkg = null;
foreach (unowned Alpm.DB db in handle.syncdbs) {
pkg = db.get_pkg (name);
if (pkg != null)
break;
}
return pkg;
}
public Pamac.UpdatesInfos[] get_syncfirst_updates (Alpm.Config alpm_config) {
Pamac.UpdatesInfos infos = Pamac.UpdatesInfos ();
Pamac.UpdatesInfos[] syncfirst_infos = {};
unowned Alpm.Package? pkg = null;
unowned Alpm.Package? candidate = null;
foreach (string name in alpm_config.syncfirst) {
pkg = Alpm.find_satisfier (alpm_config.handle.localdb.pkgcache, name);
if (pkg != null) {
candidate = Alpm.sync_newversion (pkg, alpm_config.handle.syncdbs);
if (candidate != null) {
infos.name = candidate.name;
infos.version = candidate.version;
infos.db_name = candidate.db.name;
infos.tarpath = "";
infos.download_size = candidate.download_size;
syncfirst_infos += infos;
}
}
}
return syncfirst_infos;
}
public string[] get_ignore_pkgs (Alpm.Config alpm_config) {
string[] ignore_pkgs = {};
unowned Alpm.Group? group = null;
foreach (string name in alpm_config.handle.ignorepkgs)
ignore_pkgs += name;
foreach (string grp_name in alpm_config.handle.ignoregroups) {
group = alpm_config.handle.localdb.get_group (grp_name);
if (group != null) {
foreach (unowned Alpm.Package found_pkg in group.packages)
ignore_pkgs += found_pkg.name;
}
}
return ignore_pkgs;
}
public Pamac.UpdatesInfos[] get_repos_updates (Alpm.Config alpm_config, string[] ignore_pkgs) {
unowned Alpm.Package? candidate = null;
Pamac.UpdatesInfos infos = Pamac.UpdatesInfos ();
Pamac.UpdatesInfos[] updates = {};
foreach (unowned Alpm.Package local_pkg in alpm_config.handle.localdb.pkgcache) {
// continue only if the local pkg is not in IgnorePkg or IgnoreGroup
if ((local_pkg.name in ignore_pkgs) == false) {
candidate = Alpm.sync_newversion (local_pkg, alpm_config.handle.syncdbs);
if (candidate != null) {
infos.name = candidate.name;
infos.version = candidate.version;
infos.db_name = candidate.db.name;
infos.tarpath = "";
infos.download_size = candidate.download_size;
updates += infos;
}
}
}
return updates;
}
public Pamac.UpdatesInfos[] get_aur_updates (Alpm.Config alpm_config, string[] ignore_pkgs) {
unowned Alpm.Package? sync_pkg = null;
unowned Alpm.Package? candidate = null;
string[] local_pkgs = {};
Pamac.UpdatesInfos infos = Pamac.UpdatesInfos ();
Pamac.UpdatesInfos[] aur_updates = {};
// get local pkgs
foreach (unowned Alpm.Package local_pkg in alpm_config.handle.localdb.pkgcache) {
// continue only if the local pkg is not in IgnorePkg or IgnoreGroup
if ((local_pkg.name in ignore_pkgs) == false) {
// check updates from AUR only for local packages
foreach (unowned Alpm.DB db in alpm_config.handle.syncdbs) {
sync_pkg = Alpm.find_satisfier (db.pkgcache, local_pkg.name);
if (sync_pkg != null)
break;
}
if (sync_pkg == null) {
// check update from AUR only if no package from dbs will replace it
candidate = Alpm.sync_newversion (local_pkg, alpm_config.handle.syncdbs);
if (candidate == null) {
local_pkgs += local_pkg.name;
}
}
}
}
// get aur updates
Json.Array aur_pkgs = AUR.multiinfo (local_pkgs);
int cmp;
string version;
string name;
foreach (Json.Node node in aur_pkgs.get_elements ()) {
unowned Json.Object pkg_info = node.get_object ();
version = pkg_info.get_string_member ("Version");
name = pkg_info.get_string_member ("Name");
cmp = Alpm.pkg_vercmp (version, alpm_config.handle.localdb.get_pkg (name).version);
if (cmp == 1) {
infos.name = name;
infos.version = version;
infos.db_name = "AUR";
infos.tarpath = pkg_info.get_string_member ("URLPath");
infos.download_size = 0;
aur_updates += infos;
}
}
return aur_updates;
}

697
src/daemon.vala Normal file
View File

@@ -0,0 +1,697 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Alpm;
using Pamac;
using Polkit;
// i18n
const string GETTEXT_PACKAGE = "pacman";
PamacServer server;
MainLoop loop;
[DBus (name = "org.manjaro.pamac")]
public class PamacServer : Object {
Alpm.Config alpm_config;
Pamac.Config pamac_config;
unowned Alpm.DB localdb;
unowned Alpm.List<DB?> syncdbs;
public uint64 previous_percent;
unowned Alpm.List<string?> local_packages;
int force_refresh;
bool emit_refreshed_signal;
public Cond provider_cond;
public Mutex provider_mutex;
public int? choosen_provider;
public signal void emit_event (uint event, string msg);
public signal void emit_providers (string depend, string[] providers);
public signal void emit_progress (uint progress, string action, string pkgname, int percent, uint n_targets, uint current_target);
public signal void emit_download (string filename, uint64 xfered, uint64 total);
public signal void emit_totaldownload (uint64 total);
public signal void emit_log (uint level, string msg);
public signal void emit_updates (Updates updates);
public signal void emit_refreshed (ErrorInfos error);
public signal void emit_trans_prepared (ErrorInfos error);
public signal void emit_trans_committed (ErrorInfos error);
public PamacServer () {
previous_percent = 0;
local_packages = null;
get_handle ();
force_refresh = 0;
emit_refreshed_signal = true;
}
private void get_handle () {
alpm_config = new Alpm.Config ("/etc/pacman.conf");
pamac_config = new Pamac.Config ("/etc/pamac.conf");
alpm_config.handle.eventcb = (EventCallBack) cb_event;
alpm_config.handle.progresscb = (ProgressCallBack) cb_progress;
alpm_config.handle.questioncb = (QuestionCallBack) cb_question;
alpm_config.handle.dlcb = (DownloadCallBack) cb_download;
alpm_config.handle.totaldlcb = (TotalDownloadCallBack) cb_totaldownload;
alpm_config.handle.logcb = (LogCallBack) cb_log;
localdb = alpm_config.handle.localdb;
syncdbs = alpm_config.handle.syncdbs;
}
public void write_config (HashTable<string,string> new_conf, GLib.BusName sender) {
try {
Polkit.Authority authority = Polkit.Authority.get_sync (null);
Polkit.Subject subject = Polkit.SystemBusName.new (sender);
Polkit.AuthorizationResult result = authority.check_authorization_sync
(subject,
"org.manjaro.pamac.commit",
null,
Polkit.CheckAuthorizationFlags.ALLOW_USER_INTERACTION,
null);
if (result.get_is_authorized ()) {
pamac_config.write (new_conf);
}
} catch (GLib.Error e) {
stderr.printf ("%s\n", e.message);
}
}
private void refresh_real () {
ErrorInfos err = ErrorInfos ();
string[] details = {};
uint success = 0;
int ret = alpm_config.handle.trans_init (0);
if (ret == 0) {
foreach (unowned DB db in syncdbs) {
ret = db.update (force_refresh);
if (ret >= 0) {
success++;
}
}
// We should always succeed if at least one DB was upgraded - we may possibly
// fail later with unresolved deps, but that should be rare, and would be expected
if (success == 0) {
err.str = _("failed to synchronize any databases\n");
details += Alpm.strerror (alpm_config.handle.errno ()) + "\n";
err.details = details;
}
trans_release ();
get_handle ();
if (emit_refreshed_signal)
emit_refreshed (err);
else
emit_refreshed_signal = true;
}
}
public async void refresh (int force, bool emit_signal) {
force_refresh = force;
emit_refreshed_signal = emit_signal;
try {
new Thread<void*>.try ("refresh thread", (ThreadFunc) refresh_real);
} catch (GLib.Error e) {
stderr.printf ("%s\n", e.message);
}
}
public UpdatesInfos[] get_updates () {
UpdatesInfos[] updates = {};
updates = get_syncfirst_updates (alpm_config);
if (updates.length != 0) {
return updates;
} else {
string[] ignore_pkgs = get_ignore_pkgs (alpm_config);
updates = get_repos_updates (alpm_config, ignore_pkgs);
if (pamac_config.enable_aur) {
UpdatesInfos[] aur_updates = get_aur_updates (alpm_config, ignore_pkgs);
foreach (UpdatesInfos infos in aur_updates)
updates += infos;
}
return updates;
}
}
public ErrorInfos trans_init (TransFlag transflags) {
ErrorInfos err = ErrorInfos ();
int ret = alpm_config.handle.trans_init (transflags);
if (ret == -1) {
//err = _("failed to init transaction (%s)\n").printf (Alpm.strerror (errno));
err.str = Alpm.strerror (alpm_config.handle.errno ()) + "\n";
}
return err;
}
public ErrorInfos trans_sysupgrade (int enable_downgrade) {
ErrorInfos err = ErrorInfos ();
int ret = alpm_config.handle.trans_sysupgrade (enable_downgrade);
if (ret == -1) {;
err.str = Alpm.strerror (alpm_config.handle.errno ()) + "\n";
}
return err;
}
public ErrorInfos trans_add_pkg (string pkgname) {
ErrorInfos err = ErrorInfos ();
unowned Package? pkg = null;
//pkg = alpm_config.handle.find_dbs_satisfier (syncdbs, pkgname);
foreach (var db in syncdbs) {
pkg = find_satisfier (db.pkgcache, pkgname);
if (pkg != null)
break;
}
if (pkg == null) {
err.str = _("target not found: %s\n").printf (pkgname);
return err;
}
int ret = alpm_config.handle.trans_add_pkg (pkg);
if (ret == -1) {
Alpm.Errno errno = alpm_config.handle.errno ();
if (errno == Errno.TRANS_DUP_TARGET || errno == Errno.PKG_IGNORED)
// just skip duplicate or ignored targets
return err;
else {
err.str = "'%s': %s\n".printf (pkg.name, Alpm.strerror (errno));
return err;
}
}
return err;
}
public ErrorInfos trans_load_pkg (string pkgpath) {
ErrorInfos err = ErrorInfos ();
unowned Package? pkg = alpm_config.handle.load_file (pkgpath, 1, alpm_config.handle.localfilesiglevel);
if (pkg == null) {
err.str = "'%s': %s\n".printf (pkgpath, Alpm.strerror (alpm_config.handle.errno ()));
return err;
} else {
int ret = alpm_config.handle.trans_add_pkg (pkg);
if (ret == -1) {
Alpm.Errno errno = alpm_config.handle.errno ();
if (errno == Errno.TRANS_DUP_TARGET || errno == Errno.PKG_IGNORED) {
// just skip duplicate or ignored targets
return err;
} else {
err.str = "'%s': %s\n".printf (pkg.name, Alpm.strerror (errno));
return err;
}
}
}
return err;
}
public ErrorInfos trans_remove_pkg (string pkgname) {
ErrorInfos err = ErrorInfos ();
unowned Package? pkg = localdb.get_pkg (pkgname);
if (pkg == null) {
err.str = _("target not found: %s\n").printf (pkgname);
return err;
}
int ret = alpm_config.handle.trans_remove_pkg (pkg);
if (ret == -1) {
err.str = "'%s': %s\n".printf (pkg.name, Alpm.strerror (alpm_config.handle.errno ()));
}
return err;
}
public void trans_prepare_real () {
ErrorInfos err = ErrorInfos ();
string[] details = {};
Alpm.List<void*> err_data = null;
int ret = alpm_config.handle.trans_prepare (out err_data);
if (ret == -1) {
Alpm.Errno errno = alpm_config.handle.errno ();
//err = _("failed to prepare transaction (%s)\n").printf ();
err.str = Alpm.strerror (errno) + "\n";
switch (errno) {
case Errno.PKG_INVALID_ARCH:
foreach (void *i in err_data) {
char *pkgname = i;
details += _("package %s does not have a valid architecture\n").printf (pkgname);
}
break;
case Errno.UNSATISFIED_DEPS:
foreach (void *i in err_data) {
DepMissing *miss = i;
string depstring = miss->depend.compute_string ();
details += _("%s: requires %s\n").printf (miss->target, depstring);
}
break;
case Errno.CONFLICTING_DEPS:
foreach (void *i in err_data) {
Conflict *conflict = i;
// only print reason if it contains new information
if (conflict->reason.mod == DepMod.ANY)
details += _("%s and %s are in conflict\n").printf (conflict->package1, conflict->package2);
else {
string reason = conflict->reason.compute_string ();
details += _("%s and %s are in conflict (%s)\n").printf (conflict->package1, conflict->package2, reason);
}
}
break;
default:
break;
}
err.details = details;
trans_release ();
}
emit_trans_prepared (err);
}
public async void trans_prepare () {
try {
new Thread<void*>.try ("prepare thread", (ThreadFunc) trans_prepare_real);
} catch (GLib.Error e) {
stderr.printf ("%s\n", e.message);
}
}
public void choose_provider (int provider) {
provider_mutex.lock ();
choosen_provider = provider;
provider_cond.signal ();
provider_mutex.unlock ();
}
public UpdatesInfos[] trans_to_add () {
UpdatesInfos info = UpdatesInfos ();
UpdatesInfos[] infos = {};
foreach (unowned Package pkg in alpm_config.handle.trans_to_add ()) {
info.name = pkg.name;
info.version = pkg.version;
// if pkg was load from a file, pkg.db is null
if (pkg.db != null)
info.db_name = pkg.db.name;
else
info.db_name = "";
info.tarpath = "";
info.download_size = pkg.download_size;
infos += info;
}
return infos;
}
public UpdatesInfos[] trans_to_remove () {
UpdatesInfos info = UpdatesInfos ();
UpdatesInfos[] infos = {};
foreach (unowned Package pkg in alpm_config.handle.trans_to_remove ()) {
info.name = pkg.name;
info.version = pkg.version;
info.db_name = pkg.db.name;
info.tarpath = "";
info.download_size = pkg.download_size;
infos += info;
}
return infos;
}
private void trans_commit_real () {
ErrorInfos err = ErrorInfos ();
string[] details = {};
Alpm.List<void*> err_data = null;
int ret = alpm_config.handle.trans_commit (out err_data);
if (ret == -1) {
Alpm.Errno errno = alpm_config.handle.errno ();
//err = _("failed to commit transaction (%s)\n").printf (Alpm.strerror (errno));
err.str = Alpm.strerror (errno) + "\n";
switch (errno) {
case Alpm.Errno.FILE_CONFLICTS:
TransFlag flags = alpm_config.handle.trans_get_flags ();
if ((flags & TransFlag.FORCE) != 0) {
details += _("unable to %s directory-file conflicts\n").printf ("--force");
}
foreach (void *i in err_data) {
FileConflict *conflict = i;
switch (conflict->type) {
case FileConflictType.TARGET:
details += _("%s exists in both '%s' and '%s'\n").printf (conflict->file, conflict->target, conflict->ctarget);
break;
case FileConflictType.FILESYSTEM:
details += _("%s: %s exists in filesystem\n").printf (conflict->target, conflict->file);
break;
}
}
break;
case Alpm.Errno.PKG_INVALID:
case Alpm.Errno.PKG_INVALID_CHECKSUM:
case Alpm.Errno.PKG_INVALID_SIG:
case Alpm.Errno.DLT_INVALID:
foreach (void *i in err_data) {
char *filename = i;
details += _("%s is invalid or corrupted\n").printf (filename);
}
break;
default:
break;
}
err.details = details;
}
trans_release ();
get_handle ();
emit_trans_committed (err);
}
public async void trans_commit (GLib.BusName sender) {
try {
Polkit.Authority authority = Polkit.Authority.get_sync (null);
Polkit.Subject subject = Polkit.SystemBusName.new (sender);
Polkit.AuthorizationResult result = authority.check_authorization_sync
(subject,
"org.manjaro.pamac.commit",
null,
Polkit.CheckAuthorizationFlags.ALLOW_USER_INTERACTION,
null);
if (result.get_is_authorized ()) {
new Thread<void*>.try ("commit thread", (ThreadFunc) trans_commit_real);
} else {
ErrorInfos err = ErrorInfos ();
err.str = "Not Authorized\n";
emit_trans_committed (err);
trans_release ();
}
} catch (GLib.Error e) {
stderr.printf ("%s\n", e.message);
}
}
public int trans_release () {
return alpm_config.handle.trans_release ();
}
public void trans_cancel () {
alpm_config.handle.trans_interrupt ();
alpm_config.handle.trans_release ();
get_handle ();
}
public void quit () {
GLib.File lockfile = GLib.File.new_for_path ("/var/lib/pacman/db.lck");
if (lockfile.query_exists () == false)
loop.quit ();
}
// End of Server Object
}
private void write_log_file (string event) {
var now = new DateTime.now_local ();
string log = "%s %s".printf (now.format ("[%Y-%m-%d %H:%M]"), event);
var file = GLib.File.new_for_path ("/var/log/pamac.log");
try {
// creating a DataOutputStream to the file
var dos = new DataOutputStream (file.append_to (FileCreateFlags.NONE));
// writing a short string to the stream
dos.put_string (log);
} catch (GLib.Error e) {
GLib.stderr.printf("%s\n", e.message);
}
}
private void cb_event (Event event, void *data1, void *data2) {
string event_str = null;
switch (event) {
case Event.CHECKDEPS_START:
event_str = _("checking dependencies...\n");
break;
case Event.FILECONFLICTS_START:
event_str = _("checking for file conflicts...\n");
break;
case Event.RESOLVEDEPS_START:
event_str = _("resolving dependencies...\n");
break;
case Event.INTERCONFLICTS_START:
event_str = _("looking for inter-conflicts...\n");
break;
case Event.ADD_START:
unowned Package pkg = (Package) data1;
event_str = _("installing %s...\n").printf ("%s (%s)".printf (pkg.name, pkg.version));
break;
case Event.ADD_DONE:
unowned Package pkg = (Package) data1;
string log = "installed %s (%s)\n".printf (pkg.name, pkg.version);
write_log_file (log);
break;
case Event.REMOVE_START:
unowned Package pkg = (Package) data1;
event_str = _("removing %s...\n").printf ("%s (%s)".printf (pkg.name, pkg.version));
break;
case Event.REMOVE_DONE:
unowned Package pkg = (Package) data1;
string log = "removed %s (%s)\n".printf (pkg.name, pkg.version);
write_log_file (log);
break;
case Event.UPGRADE_START:
unowned Package new_pkg = (Package) data1;
unowned Package old_pkg = (Package) data2;
event_str = _("upgrading %s...\n").printf ("%s (%s -> %s)".printf (old_pkg.name, old_pkg.version, new_pkg.version));
break;
case Event.UPGRADE_DONE:
unowned Package new_pkg = (Package) data1;
unowned Package old_pkg = (Package) data2;
string log = _("upgraded %s (%s -> %s)\n").printf (old_pkg.name, old_pkg.version, new_pkg.version);
write_log_file (log);
break;
case Event.DOWNGRADE_START:
unowned Package new_pkg = (Package) data1;
unowned Package old_pkg = (Package) data2;
event_str = _("downgrading %s...\n").printf ("%s (%s -> %s)".printf (old_pkg.name, old_pkg.version, new_pkg.version));
break;
case Event.DOWNGRADE_DONE:
unowned Package new_pkg = (Package) data1;
unowned Package old_pkg = (Package) data2;
string log = _("downgraded %s (%s -> %s)\n").printf (old_pkg.name, old_pkg.version, new_pkg.version);
write_log_file (log);
break;
case Event.REINSTALL_START:
unowned Package pkg = (Package) data1;
event_str = _("reinstalling %s...\n").printf ("%s (%s)".printf (pkg.name, pkg.version));
break;
case Event.REINSTALL_DONE:
unowned Package pkg = (Package) data1;
string log = "reinstalled %s (%s)\n".printf (pkg.name, pkg.version);
write_log_file (log);
break;
case Event.INTEGRITY_START:
event_str = _("checking package integrity...\n");
break;
case Event.KEYRING_START:
event_str = _("checking keyring...\n");
break;
case Event.KEY_DOWNLOAD_START:
event_str = _("downloading required keys...\n");
break;
case Event.LOAD_START:
event_str = _("loading package files...\n");
break;
case Event.DELTA_INTEGRITY_START:
event_str = _("checking delta integrity...\n");
break;
case Event.DELTA_PATCHES_START:
event_str = _("applying deltas...\n");
break;
case Event.DELTA_PATCH_START:
unowned string string1 = (string) data1;
unowned string string2 = (string) data2;
event_str = _("generating %s with %s... ").printf (string1, string2);
break;
case Event.DELTA_PATCH_DONE:
event_str = _("success!\n");
break;
case Event.DELTA_PATCH_FAILED:
event_str = _("failed.\n");
break;
case Event.SCRIPTLET_INFO:
unowned string info = (string) data1;
event_str = info;
write_log_file (event_str);
break;
case Event.RETRIEVE_START:
event_str = _("Retrieving packages ...\n");
break;
case Event.DISKSPACE_START:
event_str = _("checking available disk space...\n");
break;
case Event.OPTDEP_REQUIRED:
unowned Package pkg = (Package) data1;
Depend *depend = data2;
event_str = _("%s optionally requires %s\n").printf (pkg.name, depend->compute_string ());
break;
case Event.DATABASE_MISSING:
event_str = _("database file for '%s' does not exist\n").printf ((char *) data1);
break;
/* all the simple done events, with fallthrough for each */
case Event.FILECONFLICTS_DONE:
case Event.CHECKDEPS_DONE:
case Event.RESOLVEDEPS_DONE:
case Event.INTERCONFLICTS_DONE:
case Event.INTEGRITY_DONE:
case Event.KEYRING_DONE:
case Event.KEY_DOWNLOAD_DONE:
case Event.LOAD_DONE:
case Event.DELTA_INTEGRITY_DONE:
case Event.DELTA_PATCHES_DONE:
case Event.DISKSPACE_DONE:
/* nothing */
break;
default:
event_str = "unknown event";
break;
}
if (event_str != null)
server.emit_event ((uint) event, event_str);
}
private void cb_question (Question question, void *data1, void *data2, void *data3, out int response) {
switch (question) {
case Question.INSTALL_IGNOREPKG:
// Do not install package in IgnorePkg/IgnoreGroup
response = 0;
break;
case Question.REPLACE_PKG:
// Auto-remove conflicts in case of replaces
response = 1;
break;
case Question.CONFLICT_PKG:
// Auto-remove conflicts
response = 1;
break;
case Question.REMOVE_PKGS:
// Do not upgrade packages which have unresolvable dependencies
response = 1;
break;
case Question.SELECT_PROVIDER:
unowned Alpm.List<Package?> providers = (Alpm.List<Package?>) data1;
Depend *depend = data2;
string depend_str = depend->compute_string ();
string[] providers_str = {};
foreach (unowned Package pkg in providers) {
providers_str += pkg.name;
}
server.provider_cond = Cond ();
server.provider_mutex = Mutex ();
server.choosen_provider = null;
server.emit_providers (depend_str, providers_str);
server.provider_mutex.lock ();
while (server.choosen_provider == null) {
server.provider_cond.wait (server.provider_mutex);
}
response = server.choosen_provider;
server.provider_mutex.unlock ();
break;
case Question.CORRUPTED_PKG:
// Auto-remove corrupted pkgs in cache
response = 1;
break;
case Question.IMPORT_KEY:
PGPKey *key = data1;
// Do not get revoked key
if (key->revoked == 1) response = 0;
// Auto get not revoked key
else response = 1;
break;
default:
response = 0;
break;
}
}
private void cb_progress (Progress progress, string pkgname, int percent, uint n_targets, uint current_target) {
string action = "";
switch (progress) {
case Progress.ADD_START:
action = _("installing");
break;
case Progress.UPGRADE_START:
action = _("upgrading");
break;
case Progress.DOWNGRADE_START:
action = _("downgrading");
break;
case Progress.REINSTALL_START:
action = _("reinstalling");
break;
case Progress.REMOVE_START:
action = _("removing");
break;
case Progress.CONFLICTS_START:
action = _("checking for file conflicts");
break;
case Progress.DISKSPACE_START:
action = _("checking available disk space");
break;
case Progress.INTEGRITY_START:
action = _("checking package integrity");
break;
case Progress.KEYRING_START:
action = _("checking keys in keyring");
break;
case Progress.LOAD_START:
action = _("loading package files");
break;
default:
break;
}
if ((uint64) percent != server.previous_percent) {
server.previous_percent = (uint64) percent;
server.emit_progress ((uint) progress, action, pkgname, percent, n_targets, current_target);
}
}
private void cb_download (string filename, uint64 xfered, uint64 total) {
if (xfered != server.previous_percent) {
server.previous_percent = xfered;
server.emit_download (filename, xfered, total);
}
}
private void cb_totaldownload (uint64 total) {
server.emit_totaldownload (total);
}
private void cb_log (LogLevel level, string fmt, va_list args) {
LogLevel logmask = LogLevel.ERROR | LogLevel.WARNING;
if ((level & logmask) == 0)
return;
string? log = null;
log = fmt.vprintf (args);
if (log != null)
server.emit_log ((uint) level, log);
}
void on_bus_acquired (DBusConnection conn) {
server = new PamacServer ();
try {
conn.register_object ("/org/manjaro/pamac", server);
}
catch (IOError e) {
stderr.printf ("Could not register service\n");
}
}
void main () {
// i18n
Intl.setlocale(LocaleCategory.ALL, "");
Intl.textdomain(GETTEXT_PACKAGE);
Bus.own_name(BusType.SYSTEM, "org.manjaro.pamac", BusNameOwnerFlags.NONE,
on_bus_acquired,
() => {},
() => stderr.printf("Could not acquire name\n"));
loop = new MainLoop ();
loop.run ();
}

40
src/history_dialog.vala Normal file
View File

@@ -0,0 +1,40 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
[GtkTemplate (ui = "/org/manjaro/pamac/manager/history_dialog.ui")]
public class HistoryDialog : Gtk.Dialog {
[GtkChild]
public Gtk.TextView textview;
public HistoryDialog (ManagerWindow window) {
Object (transient_for: window, use_header_bar: 0);
}
[GtkCallback]
public void on_textview_size_allocate () {
// auto-scrolling method
var scrollable = textview as Gtk.Scrollable;
var adj = scrollable.get_vadjustment ();
adj.set_value (adj.get_upper () - adj.get_page_size ());
}
}
}

69
src/installer.vala Normal file
View File

@@ -0,0 +1,69 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
public class Installer: Gtk.Application {
Transaction transaction;
Pamac.Config pamac_config;
public Installer () {
application_id = "org.manjaro.pamac.install";
flags |= ApplicationFlags.HANDLES_OPEN;
}
public override void startup () {
// i18n
Intl.textdomain ("pamac");
Intl.setlocale (LocaleCategory.ALL, "");
base.startup ();
pamac_config = new Pamac.Config ("/etc/pamac.conf");
transaction = new Pamac.Transaction (null, pamac_config);
transaction.finished.connect (on_emit_trans_finished);
this.hold ();
}
public override void activate () {
print ("\nError: Path(s) of tarball(s) to install is needed\n");
transaction.stop_daemon ();
this.release ();
}
public override void open (File[] files, string hint) {
foreach (File file in files) {
string? path = file.get_path ();
transaction.data.to_load.insert (path, path);
}
transaction.run ();
}
public void on_emit_trans_finished (bool error) {
transaction.stop_daemon ();
this.release ();
}
public static int main (string[] args) {
var installer = new Installer();
return installer.run (args);
}
}
}

55
src/manager.vala Normal file
View File

@@ -0,0 +1,55 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
public class Manager : Gtk.Application {
ManagerWindow manager_window;
public Manager () {
application_id = "org.manjaro.pamac.manager";
flags = ApplicationFlags.FLAGS_NONE;
}
public override void startup () {
// i18n
Intl.textdomain ("pamac");
Intl.setlocale (LocaleCategory.ALL, "");
base.startup ();
manager_window = new ManagerWindow (this);
}
public override void activate () {
manager_window.present ();
}
public override void shutdown () {
base.shutdown ();
manager_window.transaction.stop_daemon ();
}
}
public static int main (string[] args) {
var manager = new Manager ();
return manager.run (args);
}
}

927
src/manager_window.vala Normal file
View File

@@ -0,0 +1,927 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Gtk;
using Alpm;
const string VERSION = "2.0";
namespace Pamac {
public struct SortInfo {
public int column_number;
public Gtk.SortType sort_type;
}
[GtkTemplate (ui = "/org/manjaro/pamac/manager/manager_window.ui")]
public class ManagerWindow : Gtk.ApplicationWindow {
// icons
public Gdk.Pixbuf? installed_icon;
public Gdk.Pixbuf? uninstalled_icon;
public Gdk.Pixbuf? to_install_icon;
public Gdk.Pixbuf? to_reinstall_icon;
public Gdk.Pixbuf? to_remove_icon;
public Gdk.Pixbuf? locked_icon;
// manager objects
[GtkChild]
public TreeView packages_treeview;
[GtkChild]
public TreeViewColumn state_column;
[GtkChild]
public TreeViewColumn name_column;
[GtkChild]
public TreeViewColumn version_column;
[GtkChild]
public TreeViewColumn repo_column;
[GtkChild]
public TreeViewColumn size_column;
[GtkChild]
public Notebook filters_notebook;
[GtkChild]
public SearchEntry search_entry;
[GtkChild]
public TreeView search_treeview;
[GtkChild]
public TreeView groups_treeview;
[GtkChild]
public TreeView states_treeview;
[GtkChild]
public TreeView repos_treeview;
[GtkChild]
public TreeView deps_treeview;
[GtkChild]
public TreeView details_treeview;
[GtkChild]
public ScrolledWindow deps_scrolledwindow;
[GtkChild]
public ScrolledWindow details_scrolledwindow;
[GtkChild]
public ScrolledWindow files_scrolledwindow;
[GtkChild]
public Label name_label;
[GtkChild]
public Label desc_label;
[GtkChild]
public Label link_label;
[GtkChild]
public Label licenses_label;
[GtkChild]
public TextView files_textview;
[GtkChild]
public Switch search_aur_button;
[GtkChild]
public Button valid_button;
[GtkChild]
public Button cancel_button;
public ListStore search_list;
public ListStore groups_list;
public ListStore states_list;
public ListStore repos_list;
public ListStore deps_list;
public ListStore details_list;
PackagesModel packages_list;
HashTable<string, Json.Array> aur_results;
public Pamac.Config pamac_config;
public Transaction transaction;
public SortInfo sortinfo;
//dialogs
HistoryDialog history_dialog;
PackagesChooserDialog packages_chooser_dialog;
PreferencesDialog preferences_dialog;
public ManagerWindow (Gtk.Application application) {
Object (application: application);
aur_results = new HashTable<string, Json.Array> (str_hash, str_equal);
search_list = new Gtk.ListStore (1, typeof (string));
search_treeview.set_model (search_list);
groups_list = new Gtk.ListStore (1, typeof (string));
groups_treeview.set_model (groups_list);
states_list = new Gtk.ListStore (1, typeof (string));
states_treeview.set_model (states_list);
repos_list = new Gtk.ListStore (1, typeof (string));
repos_treeview.set_model (repos_list);
deps_list = new Gtk.ListStore (2, typeof (string), typeof (string));
deps_treeview.set_model (deps_list);
details_list = new Gtk.ListStore (2, typeof (string), typeof (string));
details_treeview.set_model (details_list);;
try {
installed_icon = new Gdk.Pixbuf.from_resource ("/org/manjaro/pamac/manager/package-installed-updated.png");
uninstalled_icon = new Gdk.Pixbuf.from_resource ("/org/manjaro/pamac/manager/package-available.png");
to_install_icon = new Gdk.Pixbuf.from_resource ("/org/manjaro/pamac/manager/package-install.png");
to_reinstall_icon = new Gdk.Pixbuf.from_resource ("/org/manjaro/pamac/manager/package-reinstall.png");
to_remove_icon = new Gdk.Pixbuf.from_resource ("/org/manjaro/pamac/manager/package-remove.png");
locked_icon = new Gdk.Pixbuf.from_resource ("/org/manjaro/pamac/manager/package-installed-locked.png");
} catch (GLib.Error e) {
stderr.printf (e.message);
}
pamac_config = new Pamac.Config ("/etc/pamac.conf");
transaction = new Pamac.Transaction (this as ApplicationWindow, pamac_config);
transaction.finished.connect (on_emit_trans_finished);
history_dialog = new HistoryDialog (this);
packages_chooser_dialog = new PackagesChooserDialog (this, transaction);
preferences_dialog = new PreferencesDialog (this as ApplicationWindow);
set_buttons_sensitive (false);
search_aur_button.set_active (pamac_config.enable_aur);
// sort by name by default
sortinfo = {0, SortType.ASCENDING};
update_lists ();
}
public void enable_aur (bool enable) {
search_aur_button.set_active (enable);
}
public void set_buttons_sensitive (bool sensitive) {
valid_button.set_sensitive (sensitive);
cancel_button.set_sensitive (sensitive);
}
public void update_lists () {
Alpm.List <string?> grps = null;
TreeIter iter;
foreach (unowned DB db in transaction.alpm_config.handle.syncdbs) {
repos_list.insert_with_values (out iter, -1, 0, db.name);
foreach (unowned Group grp in db.groupcache) {
if (grps.find_str (grp.name) == null)
grps.add(grp.name);
}
}
repos_list.insert_with_values (out iter, -1, 0, dgettext (null, "local"));
foreach (string name in grps)
groups_list.insert_with_values (out iter, -1, 0, name);
groups_list.set_sort_column_id (0, SortType.ASCENDING);
states_list.insert_with_values (out iter, -1, 0, dgettext (null, "Installed"));
//states_list.insert_with_values (out iter, -1, 0, dgettext (null, "Uninstalled"));
states_list.insert_with_values (out iter, -1, 0, dgettext (null, "Orphans"));
states_list.insert_with_values (out iter, -1, 0, dgettext (null, "To install"));
states_list.insert_with_values (out iter, -1, 0, dgettext (null, "To remove"));
}
public void set_infos_list (Pamac.Package pkg) {
name_label.set_markup ("<big><b>%s %s</b></big>".printf (pkg.name, pkg.version));
// fix &,-,>,< in desc
string desc;
if (pkg.alpm_pkg != null)
desc = pkg.alpm_pkg.desc;
else
desc = pkg.aur_json.get_string_member ("Description");
desc = desc.replace ("&", "&amp;");
desc = desc.replace ("<->", "/");
desc_label.set_markup (desc);
// fix & in url
string url;
if (pkg.alpm_pkg != null)
url = pkg.alpm_pkg.url;
else
url = pkg.aur_json.get_string_member ("URL");
url = url.replace ("&", "&amp;");
link_label.set_markup ("<a href=\"%s\">%s</a>".printf (url, url));
StringBuilder licenses = new StringBuilder ();
licenses.append (dgettext (null, "Licenses"));
licenses.append (":");
if (pkg.alpm_pkg != null) {
foreach (unowned string license in pkg.alpm_pkg.licenses) {
licenses.append (" ");
licenses.append (license);
}
} else {
licenses.append (" ");
licenses.append (pkg.aur_json.get_string_member ("License"));
}
licenses_label.set_markup (licenses.str);
}
public void set_deps_list (Alpm.Package pkg) {
deps_list.clear ();
TreeIter iter;
unowned Alpm.List<Depend?> list = pkg.depends;
size_t len = list.length;
size_t i;
if (len != 0) {
deps_list.insert_with_values (out iter, -1,
0, dgettext (null, "Depends On") + ":",
1, list.nth (0).get_data ().compute_string ());
i = 1;
while (i < len) {
deps_list.insert_with_values (out iter, -1,
1, list.nth (i).get_data ().compute_string ());
i++;
}
}
list = pkg.optdepends;
len = list.length;
if (len != 0) {
unowned Depend optdep = list.nth (0).get_data ();
unowned Alpm.Package? satisfier = find_satisfier (
transaction.alpm_config.handle.localdb.pkgcache,
optdep.name);
string optdep_str = optdep.compute_string ();
if (satisfier != null)
optdep_str = optdep_str + " [" + dgettext (null, "Installed") + "]";
deps_list.insert_with_values (out iter, -1,
0, dgettext (null, "Optional Deps") + ":",
1, optdep_str);
i = 1;
while (i < len) {
optdep = list.nth (i).get_data ();
satisfier = find_satisfier (
transaction.alpm_config.handle.localdb.pkgcache,
optdep.name);
optdep_str = optdep.compute_string ();
if (satisfier != null)
optdep_str = optdep_str + " [" + dgettext (null, "Installed") + "]";
deps_list.insert_with_values (out iter, -1, 1, optdep_str);
i++;
}
}
if (pkg.origin == PkgFrom.LOCALDB) {
unowned Alpm.List<string?> str_list = pkg.compute_requiredby ();
len = str_list.length;
if (len != 0) {
deps_list.insert_with_values (out iter, -1,
0, dgettext (null, "Required By") + ":",
1, str_list.nth (0).get_data ());
i = 1;
while (i < len) {
deps_list.insert_with_values (out iter, -1,
1, str_list.nth (i).get_data ());
i++;
}
}
}
list = pkg.provides;
len = list.length;
if (len != 0) {
deps_list.insert_with_values (out iter, -1,
0, dgettext (null, "Provides") + ":",
1, list.nth (0).get_data ().compute_string ());
i = 1;
while (i < len) {
deps_list.insert_with_values (out iter, -1,
1, list.nth (i).get_data ().compute_string ());
i++;
}
}
list = pkg.replaces;
len = list.length;
if (len != 0) {
deps_list.insert_with_values (out iter, -1,
0, dgettext (null, "Replaces") + ":",
1, list.nth (0).get_data ().compute_string ());
i = 1;
while (i < len) {
deps_list.insert_with_values (out iter, -1,
1, list.nth (i).get_data ().compute_string ());
i++;
}
}
list = pkg.conflicts;
len = list.length;
if (len != 0) {
deps_list.insert_with_values (out iter, -1,
0, dgettext (null, "Conflicts With") + ":",
1, list.nth (0).get_data ().compute_string ());
i = 1;
while (i < len) {
deps_list.insert_with_values (out iter, -1,
1, list.nth (i).get_data ().compute_string ());
i++;
}
}
}
public void set_details_list (Alpm.Package pkg) {
details_list.clear ();
TreeIter iter;
if (pkg.origin == PkgFrom.SYNCDB) {
details_list.insert_with_values (out iter, -1,
0, dgettext (null, "Repository") + ":",
1, pkg.db.name);
}
unowned Alpm.List<string?> list = pkg.groups;
size_t len = list.length;
size_t i;
if (len != 0) {
details_list.insert_with_values (out iter, -1,
0, dgettext (null, "Groups") + ":",
1, list.nth (0).get_data ());
i = 1;
while (i < len) {
details_list.insert_with_values (out iter, -1,
1, list.nth (i).get_data ());
i++;
}
}
details_list.insert_with_values (out iter, -1,
0, dgettext (null, "Packager") + ":",
1, pkg.packager);
if (pkg.origin == PkgFrom.LOCALDB) {
GLib.Time time = GLib.Time.local ((time_t) pkg.installdate);
string strtime = time.format ("%a %d %b %Y %X %Z");
details_list.insert_with_values (out iter, -1,
0, dgettext (null, "Install Date") + ":",
1, strtime);
string reason;
if (pkg.reason == PkgReason.EXPLICIT)
reason = dgettext (null, "Explicitly installed");
else if (pkg.reason == PkgReason.EXPLICIT)
reason = dgettext (null, "Installed as a dependency for another package");
else
reason = dgettext (null, "Unknown");
details_list.insert_with_values (out iter, -1,
0, dgettext (null, "Install Reason") + ":",
1, reason);
}
if (pkg.origin == PkgFrom.SYNCDB) {
details_list.insert_with_values (out iter, -1,
0, dgettext (null, "Signatures") + ":",
1, pkg.base64_sig != null ? "Yes" : "No");
}
if (pkg.origin == PkgFrom.LOCALDB) {
unowned Alpm.List<Backup?> backup_list = pkg.backup;
len = backup_list.length;
if (len != 0) {
details_list.insert_with_values (out iter, -1,
0, dgettext (null, "Backup files") + ":",
1, "/" + backup_list.nth (0).get_data ().name);
i = 1;
while (i < len) {
details_list.insert_with_values (out iter, -1,
1, "/" + backup_list.nth (i).get_data ().name);
i++;
}
}
}
}
public void set_files_list (Alpm.Package pkg) {
StringBuilder text = new StringBuilder ();
foreach (unowned Alpm.File file in pkg.files) {
if (text.len != 0)
text.append ("\n");
text.append ("/");
text.append (file.name);
}
files_textview.buffer.set_text (text.str, (int) text.len);
}
public async unowned Alpm.List<Alpm.Package?> search_pkgs (string search_string, out Json.Array aur_pkgs) {
unowned Alpm.List<Alpm.Package?> pkgs = null;
unowned Alpm.List<string?> needles = null;
string[] splitted = search_string.split (" ");
foreach (unowned string part in splitted)
needles.add (part);
pkgs = search_all_dbs (transaction.alpm_config.handle, needles);
if (search_aur_button.get_active()) {
if (aur_results.contains (search_string)) {
aur_pkgs = aur_results.get (search_string);
} else {
aur_pkgs = AUR.search (search_string);
aur_results.insert (search_string, aur_pkgs);
}
} else {
aur_pkgs = new Json.Array ();
}
return pkgs;
}
public void populate_packages_list (Alpm.List<Alpm.Package?>? pkgs, Json.Array? aur_pkgs = null) {
packages_treeview.freeze_child_notify ();
packages_treeview.set_model (null);
// populate liststore
packages_list = new PackagesModel (pkgs, aur_pkgs, this);
// sort liststore
int column = sortinfo.column_number;
if (column == 0)
packages_list.sort_by_name (sortinfo.sort_type);
else if (column == 1)
packages_list.sort_by_state (sortinfo.sort_type);
else if (column == 2)
packages_list.sort_by_version (sortinfo.sort_type);
else if (column == 3)
packages_list.sort_by_repo (sortinfo.sort_type);
else if (column == 4)
packages_list.sort_by_size (sortinfo.sort_type);
packages_treeview.set_model (packages_list);
packages_treeview.thaw_child_notify ();
this.get_window ().set_cursor (null);
}
public void refresh_packages_list () {
int current_page = filters_notebook.get_current_page ();
if (current_page == 0) {
TreeModel model;
TreeIter? iter;
TreeSelection selection = search_treeview.get_selection ();
if (selection.get_selected (out model, out iter)) {
on_search_treeview_selection_changed ();
}
} else if (current_page == 1) {
on_groups_treeview_selection_changed ();
} else if (current_page == 2) {
on_states_treeview_selection_changed ();
} else if (current_page == 3) {
on_repos_treeview_selection_changed ();
}
}
[GtkCallback]
public void on_packages_treeview_selection_changed () {
TreeModel model;
TreeIter? iter;
TreeSelection selection = packages_treeview.get_selection ();
if (selection.get_selected (out model, out iter)) {
Pamac.Package pkg = (Pamac.Package) iter.user_data;
if (pkg.alpm_pkg != null) {
set_infos_list (pkg);
set_deps_list (pkg.alpm_pkg);
set_details_list (pkg.alpm_pkg);
deps_scrolledwindow.visible = true;
details_scrolledwindow.visible = true;
if (pkg.alpm_pkg.origin == PkgFrom.LOCALDB) {
set_files_list (pkg.alpm_pkg);
files_scrolledwindow.visible = true;
} else {
files_scrolledwindow.visible = false;
}
} else if (pkg.aur_json != null) {
set_infos_list (pkg);
deps_scrolledwindow.visible = false;
details_scrolledwindow.visible = false;
files_scrolledwindow.visible = false;
}
}
}
[GtkCallback]
public void on_packages_treeview_row_activated (TreeView treeview, TreePath path, TreeViewColumn column) {
TreeIter iter;
if (packages_list.get_iter (out iter, path)) {
GLib.Value val;
packages_list.get_value (iter, 0, out val);
string name = val.get_string ();
if (name != dgettext (null, "No package found")) {
if (transaction.data.to_add.contains (name)) {
transaction.data.to_add.steal (name);
} else if (transaction.data.to_remove.contains (name)) {
transaction.data.to_remove.steal (name);
} else if (transaction.data.to_build.contains (name)) {
transaction.data.to_build.steal (name);
} else {
packages_list.get_value (iter, 3, out val);
string db_name = val.get_string ();
if (db_name == "local") {
if (!(name in transaction.alpm_config.holdpkg)) {
transaction.data.to_remove.insert (name, name);
}
} else if (db_name == "AUR") {
transaction.data.to_build.insert (name, name);
} else {
transaction.data.to_add.insert (name, name);
}
}
}
}
if (transaction.data.to_add.size () + transaction.data.to_remove.size () + transaction.data.to_build.size () == 0) {
set_buttons_sensitive (false);
} else {
set_buttons_sensitive (true);
}
// force a display refresh
packages_treeview.queue_draw ();
}
[GtkCallback]
public bool on_list_treeview_button_press_event (Gdk.EventButton event) {
// to do
return false;
}
[GtkCallback]
public void on_name_column_clicked () {
SortType new_order;
if (name_column.sort_indicator == false)
new_order = SortType.ASCENDING;
else {
if (sortinfo.sort_type == SortType.ASCENDING)
new_order = SortType.DESCENDING;
else
new_order = SortType.ASCENDING;
}
packages_list.sort_by_name (new_order);
// force a display refresh
packages_treeview.queue_draw ();
}
[GtkCallback]
public void on_state_column_clicked () {
SortType new_order;
if (state_column.sort_indicator == false)
new_order = SortType.ASCENDING;
else {
if (sortinfo.sort_type == SortType.ASCENDING)
new_order = SortType.DESCENDING;
else
new_order = SortType.ASCENDING;
}
packages_list.sort_by_state (new_order);
// force a display refresh
packages_treeview.queue_draw ();
}
[GtkCallback]
public void on_version_column_clicked () {
SortType new_order;
if (version_column.sort_indicator == false)
new_order = SortType.ASCENDING;
else {
if (sortinfo.sort_type == SortType.ASCENDING)
new_order = SortType.DESCENDING;
else
new_order = SortType.ASCENDING;
}
packages_list.sort_by_version (new_order);
// force a display refresh
packages_treeview.queue_draw ();
}
[GtkCallback]
public void on_repo_column_clicked () {
SortType new_order;
if (repo_column.sort_indicator == false)
new_order = SortType.ASCENDING;
else {
if (sortinfo.sort_type == SortType.ASCENDING)
new_order = SortType.DESCENDING;
else
new_order = SortType.ASCENDING;
}
packages_list.sort_by_repo (new_order);
// force a display refresh
packages_treeview.queue_draw ();
}
[GtkCallback]
public void on_size_column_clicked () {
SortType new_order;
if (size_column.sort_indicator == false)
new_order = SortType.ASCENDING;
else {
if (sortinfo.sort_type == SortType.ASCENDING)
new_order = SortType.DESCENDING;
else
new_order = SortType.ASCENDING;
}
packages_list.sort_by_size (new_order);
// force a display refresh
packages_treeview.queue_draw ();
}
[GtkCallback]
public void on_search_entry_activate () {
string search_string = search_entry.get_text ();
if (search_string != "") {
this.get_window ().set_cursor (new Gdk.Cursor (Gdk.CursorType.WATCH));
while (Gtk.events_pending ())
Gtk.main_iteration ();
search_pkgs.begin (search_string, (obj, res) => {
Json.Array aur_pkgs;
unowned Alpm.List<Alpm.Package?> pkgs = search_pkgs.end (res, out aur_pkgs);
if (pkgs.length != 0) {
// add search string in search_list if needed
bool found = false;
TreeIter? iter;
TreeModel model;
TreeSelection selection = search_treeview.get_selection ();
// check if search string is already selected in search list
if (selection.get_selected (out model, out iter)) {
GLib.Value val;
model.get_value (iter, 0, out val);
string selected_string = val.get_string ();
if (selected_string == search_string) {
found = true;
// we need to populate packages_list
populate_packages_list (pkgs, aur_pkgs);
} else {
search_list.foreach ((_model, _path, _iter) => {
GLib.Value line;
model.get_value (_iter, 0, out line);
if ((string) line == search_string) {
found = true;
// populate will be done because we select the iter in search_list
selection.select_iter (_iter);
}
return found;
});
}
}
if (!found) {
search_list.insert_with_values (out iter, -1, 0, search_string);
// populate will be done because we select the iter in search_list
selection.select_iter (iter);
}
} else
// populate with empty lists
populate_packages_list (pkgs, aur_pkgs);
});
}
}
[GtkCallback]
public void on_search_entry_icon_press (EntryIconPosition p0, Gdk.Event? p1) {
on_search_entry_activate ();
}
[GtkCallback]
public void on_search_treeview_selection_changed () {
TreeModel model;
TreeIter? iter;
TreeSelection selection = search_treeview.get_selection ();
if (selection.get_selected (out model, out iter)) {
this.get_window ().set_cursor (new Gdk.Cursor (Gdk.CursorType.WATCH));
while (Gtk.events_pending ())
Gtk.main_iteration ();
GLib.Value val;
model.get_value (iter, 0, out val);
string search_string = val.get_string ();
search_pkgs.begin (search_string, (obj, res) => {
Json.Array aur_pkgs;
unowned Alpm.List<Alpm.Package?> pkgs = search_pkgs.end (res, out aur_pkgs);
populate_packages_list (pkgs, aur_pkgs);
});
}
}
[GtkCallback]
public void on_groups_treeview_selection_changed () {
TreeModel model;
TreeIter? iter;
TreeSelection selection = groups_treeview.get_selection ();
if (selection.get_selected (out model, out iter)) {
this.get_window ().set_cursor (new Gdk.Cursor (Gdk.CursorType.WATCH));
while (Gtk.events_pending ())
Gtk.main_iteration ();
GLib.Value val;
model.get_value (iter, 0, out val);
string grp_name = val.get_string ();
unowned Alpm.List<Alpm.Package?> pkgs = group_pkgs_all_dbs (transaction.alpm_config.handle, grp_name);
populate_packages_list (pkgs);
}
}
[GtkCallback]
public void on_states_treeview_selection_changed () {
TreeModel model;
TreeIter? iter;
TreeSelection selection = states_treeview.get_selection ();
if (selection.get_selected (out model, out iter)) {
this.get_window ().set_cursor (new Gdk.Cursor (Gdk.CursorType.WATCH));
while (Gtk.events_pending ())
Gtk.main_iteration ();
GLib.Value val;
model.get_value (iter, 0, out val);
string state = val.get_string ();
unowned Alpm.List<Alpm.Package?> pkgs = null;
unowned Alpm.Package? find_pkg = null;
if (state == dgettext (null, "To install")) {
foreach (string name in transaction.data.to_add.get_keys ()) {
find_pkg = transaction.alpm_config.handle.localdb.get_pkg (name);
if (find_pkg != null)
pkgs.add (find_pkg);
else {
find_pkg = get_syncpkg (transaction.alpm_config.handle, name);
if (find_pkg != null)
pkgs.add (find_pkg);
}
}
} else if (state == dgettext (null, "To remove")) {
foreach (string name in transaction.data.to_remove.get_keys ()) {
find_pkg = transaction.alpm_config.handle.localdb.get_pkg (name);
if (find_pkg != null)
pkgs.add (find_pkg);
}
} else if (state == dgettext (null, "Installed")) {
pkgs = transaction.alpm_config.handle.localdb.pkgcache;
} else if (state == dgettext (null, "Uninstalled")) {
unowned Alpm.List<Alpm.Package?> tmp = null;
unowned Alpm.List<Alpm.Package?> diff = null;
foreach (unowned DB db in transaction.alpm_config.handle.syncdbs) {
if (pkgs.length == 0)
pkgs = db.pkgcache;
else {
tmp = db.pkgcache;
diff = tmp.diff (pkgs, (Alpm.List.CompareFunc) pkgcmp);
pkgs.join (diff);
}
}
} else if (state == dgettext (null, "Orphans")) {
foreach (unowned Alpm.Package pkg in transaction.alpm_config.handle.localdb.pkgcache) {
if (pkg.reason == PkgReason.DEPEND) {
if (pkg.compute_requiredby().length == 0)
pkgs.add (pkg);
}
}
}
populate_packages_list (pkgs);
}
}
[GtkCallback]
public void on_repos_treeview_selection_changed () {
TreeModel model;
TreeIter? iter;
TreeSelection selection = repos_treeview.get_selection ();
if (selection.get_selected (out model, out iter)) {
this.get_window ().set_cursor (new Gdk.Cursor (Gdk.CursorType.WATCH));
while (Gtk.events_pending ())
Gtk.main_iteration ();
GLib.Value val;
model.get_value (iter, 0, out val);
string repo = val.get_string ();
unowned Alpm.List<Alpm.Package?> pkgs = null;
unowned Alpm.Package? find_pkg = null;
if (repo == dgettext (null, "local")) {
foreach (unowned Alpm.Package pkg in transaction.alpm_config.handle.localdb.pkgcache) {
find_pkg = get_syncpkg (transaction.alpm_config.handle, pkg.name);
if (find_pkg == null)
pkgs.add (pkg);
}
} else {
foreach (unowned DB db in transaction.alpm_config.handle.syncdbs) {
if (db.name == repo) {
foreach (unowned Alpm.Package pkg in db.pkgcache) {
find_pkg = transaction.alpm_config.handle.localdb.get_pkg (pkg.name);
if (find_pkg != null)
pkgs.add (find_pkg);
else
pkgs.add (pkg);
}
}
}
}
populate_packages_list (pkgs);
}
}
[GtkCallback]
public void on_filters_notebook_switch_page (Widget page, uint page_num) {
refresh_packages_list ();
}
[GtkCallback]
public void on_history_item_activate () {
var file = GLib.File.new_for_path ("/var/log/pamac.log");
if (!file.query_exists ())
GLib.stderr.printf ("File '%s' doesn't exist.\n", file.get_path ());
else {
StringBuilder text = new StringBuilder ();
try {
// Open file for reading and wrap returned FileInputStream into a
// DataInputStream, so we can read line by line
var dis = new DataInputStream (file.read ());
string line;
// Read lines until end of file (null) is reached
while ((line = dis.read_line (null)) != null) {
text.append (line);
text.append ("\n");
}
} catch (GLib.Error e) {
GLib.stderr.printf("%s\n", e.message);
}
history_dialog.textview.buffer.set_text (text.str, (int) text.len);
history_dialog.run ();
history_dialog.hide ();
}
}
[GtkCallback]
public void on_local_item_activate () {
int response = packages_chooser_dialog.run ();
if (response== ResponseType.ACCEPT) {
SList<string> packages_paths = packages_chooser_dialog.get_filenames ();
if (packages_paths.length () != 0) {
foreach (string path in packages_paths) {
transaction.data.to_load.insert (path, path);
}
this.get_window ().set_cursor (new Gdk.Cursor (Gdk.CursorType.WATCH));
packages_chooser_dialog.hide ();
while (Gtk.events_pending ())
Gtk.main_iteration ();
transaction.run ();
}
} else
packages_chooser_dialog.hide ();
}
[GtkCallback]
public void on_preferences_item_activate () {
bool enable_aur = pamac_config.enable_aur;
bool recurse = pamac_config.recurse;
uint64 refresh_period = pamac_config.refresh_period;
preferences_dialog.enable_aur_button.set_active (enable_aur);
preferences_dialog.remove_unrequired_deps_button.set_active (recurse);
preferences_dialog.refresh_period_spin_button.set_value (refresh_period);
int response = preferences_dialog.run ();
while (Gtk.events_pending ())
Gtk.main_iteration ();
if (response == ResponseType.OK) {
HashTable<string,string> new_conf = new HashTable<string,string> (str_hash, str_equal);
enable_aur = preferences_dialog.enable_aur_button.get_active ();
recurse = preferences_dialog.remove_unrequired_deps_button.get_active ();
refresh_period = (uint64) preferences_dialog.refresh_period_spin_button.get_value ();
if (enable_aur != pamac_config.enable_aur) {
search_aur_button.set_active (enable_aur);
new_conf.insert ("EnableAUR", enable_aur.to_string ());
}
if (recurse != pamac_config.recurse)
new_conf.insert ("RemoveUnrequiredDeps", recurse.to_string ());
if (refresh_period != pamac_config.refresh_period)
new_conf.insert ("RefreshPeriod", refresh_period.to_string ());
if (new_conf.size () != 0) {
transaction.write_config (new_conf);
pamac_config.reload ();
}
}
preferences_dialog.hide ();
}
[GtkCallback]
public void on_about_item_activate () {
Gtk.show_about_dialog (
this,
"program_name", "Pamac",
"logo_icon_name", "system-software-install",
"comments", "A GTK3 frontend of libalpm",
"copyright", "Copyright © 2014 Guillaume Benoit",
"version", VERSION,
"license_type", License.GPL_3_0,
"website", "http://manjaro.org");
}
[GtkCallback]
public void on_valid_button_clicked () {
this.get_window ().set_cursor (new Gdk.Cursor (Gdk.CursorType.WATCH));
while (Gtk.events_pending ())
Gtk.main_iteration ();
if (pamac_config.recurse)
transaction.data.flags |= Alpm.TransFlag.RECURSE;
transaction.run ();
}
[GtkCallback]
public void on_cancel_button_clicked () {
transaction.clear_lists ();
set_buttons_sensitive (false);
// force a display refresh
packages_treeview.queue_draw ();
}
[GtkCallback]
public void on_refresh_button_clicked () {
transaction.refresh (0);
}
public void on_emit_trans_finished (bool error) {
if (error == false) {
set_buttons_sensitive (false);
refresh_packages_list ();
}
transaction.data.to_load.steal_all ();
this.get_window ().set_cursor (null);
}
}
}

61
src/package.vala Normal file
View File

@@ -0,0 +1,61 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
public class Package: Object {
public unowned Alpm.Package? alpm_pkg;
public unowned Json.Object? aur_json;
public string name;
public string version;
public string repo;
public uint64 size;
public string size_string;
public Package (Alpm.Package? alpm_pkg, Json.Object? aur_json) {
if (alpm_pkg != null) {
this.alpm_pkg = alpm_pkg;
this.aur_json = null;
name = alpm_pkg.name;
version = alpm_pkg.version;
if (alpm_pkg.db != null)
repo = alpm_pkg.db.name;
else
repo = "";
size = alpm_pkg.isize;
size_string = format_size (alpm_pkg.isize);
} else if (aur_json != null ) {
this.alpm_pkg = null;
this.aur_json = aur_json;
name = aur_json.get_string_member ("Name");
version = aur_json.get_string_member ("Version");
repo = "AUR";
size = 0;
size_string = "";
} else {
this.alpm_pkg = null;
this.aur_json = null;
name = dgettext (null, "No package found");
version = "";
repo = "";
size = 0;
size_string = "";
}
}
}
}

View File

@@ -0,0 +1,56 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
[GtkTemplate (ui = "/org/manjaro/pamac/manager/packages_chooser_dialog.ui")]
public class PackagesChooserDialog : Gtk.FileChooserDialog {
ManagerWindow window;
Transaction transaction;
public PackagesChooserDialog (ManagerWindow window, Transaction transaction) {
Object (transient_for: window, use_header_bar: 0);
Gtk.FileFilter package_filter = new Gtk.FileFilter ();
package_filter.set_filter_name (dgettext (null, "Packages"));
package_filter.add_pattern ("*.pkg.tar.gz");
package_filter.add_pattern ("*.pkg.tar.xz");
this.add_filter (package_filter);
this.window = window;
this.transaction = transaction;
}
[GtkCallback]
public void on_file_activated () {
SList<string> packages_paths = this.get_filenames ();
if (packages_paths.length () != 0) {
foreach (string path in packages_paths) {
transaction.data.to_load.insert (path, path);
}
window.get_window ().set_cursor (new Gdk.Cursor (Gdk.CursorType.WATCH));
this.hide ();
while (Gtk.events_pending ())
Gtk.main_iteration ();
transaction.run ();
}
}
}
}

309
src/packages_model.vala Normal file
View File

@@ -0,0 +1,309 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
public class PackagesModel : Object, Gtk.TreeModel {
private GLib.List<Pamac.Package> all_pkgs;
public ManagerWindow manager_window;
public PackagesModel (Alpm.List<Alpm.Package?>? alpm_pkgs, Json.Array? aur_pkgs, ManagerWindow manager_window) {
this.manager_window = manager_window;
all_pkgs = new GLib.List<Pamac.Package> ();
foreach (unowned Alpm.Package alpm_pkg in alpm_pkgs) {
all_pkgs.append (new Pamac.Package (alpm_pkg, null));
}
if (aur_pkgs != null) {
unowned Json.Object pkg_info;
string name;
bool found;
foreach (Json.Node node in aur_pkgs.get_elements ()) {
pkg_info = node.get_object ();
name = pkg_info.get_string_member ("Name");
// add only the packages which are not already in the list
found = false;
foreach (Pamac.Package pkg in all_pkgs) {
if (pkg.name == name) {
found = true;
break;
}
}
if (found == false)
all_pkgs.append (new Pamac.Package (null, pkg_info));
}
}
if (all_pkgs.length () == 0) {
// create a fake "No package found" package
all_pkgs.append (new Pamac.Package (null, null));
}
}
// TreeModel interface
public Type get_column_type (int index) {
switch (index) {
case 0: // name
case 2: // version
case 3: // repo
case 4: // installed size
return typeof (string);
case 1: // icon
return typeof (Gdk.Pixbuf);
default:
return Type.INVALID;
}
}
public Gtk.TreeModelFlags get_flags () {
return Gtk.TreeModelFlags.LIST_ONLY | Gtk.TreeModelFlags.ITERS_PERSIST;
}
public void get_value (Gtk.TreeIter iter, int column, out Value val) {
Pamac.Package pkg = (Pamac.Package) iter.user_data;
return_if_fail (pkg != null);
switch (column) {
case 0:
val = Value (typeof (string));
val.set_string (pkg.name);
break;
case 1:
val = Value (typeof (Object));
if (pkg.alpm_pkg != null) {
if (pkg.name in manager_window.transaction.alpm_config.holdpkg)
val.set_object (manager_window.locked_icon);
else if (pkg.repo == "local") {
if (manager_window.transaction.data.to_add.contains (pkg.name))
val.set_object (manager_window.to_reinstall_icon);
else if (manager_window.transaction.data.to_remove.contains (pkg.name))
val.set_object (manager_window.to_remove_icon);
else
val.set_object (manager_window.installed_icon);
} else if (manager_window.transaction.data.to_add.contains (pkg.name))
val.set_object (manager_window.to_install_icon);
else
val.set_object (manager_window.uninstalled_icon);
} else if (pkg.aur_json != null) {
if (manager_window.transaction.data.to_build.contains (pkg.name))
val.set_object (manager_window.to_install_icon);
else
val.set_object (manager_window.uninstalled_icon);
} else {
Object? object = null;
val.set_object (object);
}
break;
case 2:
val = Value (typeof (string));
val.set_string (pkg.version);
break;
case 3:
val = Value (typeof (string));
val.set_string (pkg.repo);
break;
case 4:
val = Value (typeof (string));
val.set_string (pkg.size_string);
break;
default:
val = Value (Type.INVALID);
break;
}
}
public bool get_iter (out Gtk.TreeIter iter, Gtk.TreePath path) {;
if (path.get_depth () != 1 || all_pkgs.length () == 0) {
return invalid_iter (out iter);
}
iter = Gtk.TreeIter ();
int pos = path.get_indices ()[0];
iter.stamp = pos;
Pamac.Package pkg = all_pkgs.nth_data((uint) pos);
iter.user_data = pkg;
return true;
}
public int get_n_columns () {
// name, icon, version, repo, isize
return 5;
}
public Gtk.TreePath? get_path (Gtk.TreeIter iter) {
return new Gtk.TreePath.from_indices (iter.stamp);
}
public int iter_n_children (Gtk.TreeIter? iter) {
return 0;
}
public bool iter_next (ref Gtk.TreeIter iter) {
int pos = (iter.stamp) + 1;
if (pos >= all_pkgs.length ()) {
return false;
}
iter.stamp = pos;
Pamac.Package pkg = all_pkgs.nth_data((uint) pos);
iter.user_data = pkg;
return true;
}
public bool iter_previous (ref Gtk.TreeIter iter) {
int pos = iter.stamp;
if (pos >= 0) {
return false;
}
iter.stamp = (--pos);
Pamac.Package pkg = all_pkgs.nth_data((uint) pos);
iter.user_data = pkg;
return true;
}
public bool iter_nth_child (out Gtk.TreeIter iter, Gtk.TreeIter? parent, int n) {
return invalid_iter (out iter);
}
public bool iter_children (out Gtk.TreeIter iter, Gtk.TreeIter? parent) {
return invalid_iter (out iter);
}
public bool iter_has_child (Gtk.TreeIter iter) {
return false;
}
public bool iter_parent (out Gtk.TreeIter iter, Gtk.TreeIter child) {
return invalid_iter (out iter);
}
private bool invalid_iter (out Gtk.TreeIter iter) {
iter = Gtk.TreeIter ();
iter.stamp = -1;
return false;
}
// custom sort functions
public void sort_by_name (Gtk.SortType order) {
CompareFunc<Pamac.Package> namecmp = (pkg_a, pkg_b) => {
return strcmp (pkg_a.name, pkg_b.name);
};
all_pkgs.sort (namecmp);
if (order == Gtk.SortType.DESCENDING)
all_pkgs.reverse ();
manager_window.name_column.sort_order = order;
manager_window.state_column.sort_indicator = false;
manager_window.name_column.sort_indicator = true;
manager_window.version_column.sort_indicator = false;
manager_window.repo_column.sort_indicator = false;
manager_window.size_column.sort_indicator = false;
manager_window.sortinfo.column_number = 0;
manager_window.sortinfo.sort_type = order;
}
public void sort_by_state (Gtk.SortType order) {
CompareFunc<Pamac.Package> statecmp = (pkg_a, pkg_b) => {
int state_a;
int state_b;
if (pkg_a.alpm_pkg != null) {
if (pkg_a.repo == "local")
state_a = 0;
else
state_a = 1;
} else
state_a = 1;
if (pkg_b.alpm_pkg != null) {
if (pkg_b.repo == "local")
state_b = 0;
else
state_b = 1;
} else
state_b = 1;
return (int) (state_a > state_b) - (int) (state_a < state_b);
};
all_pkgs.sort (statecmp);
if (order == Gtk.SortType.DESCENDING)
all_pkgs.reverse ();
manager_window.state_column.sort_order = order;
manager_window.state_column.sort_indicator = true;
manager_window.name_column.sort_indicator = false;
manager_window.version_column.sort_indicator = false;
manager_window.repo_column.sort_indicator = false;
manager_window.size_column.sort_indicator = false;
manager_window.sortinfo.column_number = 1;
manager_window.sortinfo.sort_type = order;
}
public void sort_by_version (Gtk.SortType order) {
CompareFunc<Pamac.Package> versioncmp = (pkg_a, pkg_b) => {
return Alpm.pkg_vercmp (pkg_a.version, pkg_b.version);
};
all_pkgs.sort (versioncmp);
if (order == Gtk.SortType.DESCENDING)
all_pkgs.reverse ();
manager_window.version_column.sort_order = order;
manager_window.state_column.sort_indicator = false;
manager_window.name_column.sort_indicator = false;
manager_window.version_column.sort_indicator = true;
manager_window.repo_column.sort_indicator = false;
manager_window.size_column.sort_indicator = false;
manager_window.sortinfo.column_number = 2;
manager_window.sortinfo.sort_type = order;
}
public void sort_by_repo (Gtk.SortType order) {
CompareFunc<Pamac.Package> repocmp = (pkg_a, pkg_b) => {
return strcmp (pkg_a.repo, pkg_b.repo);
};
all_pkgs.sort (repocmp);
if (order == Gtk.SortType.DESCENDING)
all_pkgs.reverse ();
manager_window.repo_column.sort_order = order;
manager_window.state_column.sort_indicator = false;
manager_window.name_column.sort_indicator = false;
manager_window.version_column.sort_indicator = false;
manager_window.repo_column.sort_indicator = true;
manager_window.size_column.sort_indicator = false;
manager_window.sortinfo.column_number = 3;
manager_window.sortinfo.sort_type = order;
}
public void sort_by_size (Gtk.SortType order) {
CompareFunc<Pamac.Package> sizecmp = (pkg_a, pkg_b) => {
uint64 size_a;
uint64 size_b;
if (pkg_a.alpm_pkg != null)
size_a = pkg_a.size;
else
size_a = 0;
if (pkg_b.alpm_pkg != null)
size_b = pkg_b.size;
else
size_b = 0;
return (int) (size_a > size_b) - (int) (size_a < size_b);
};
all_pkgs.sort (sizecmp);
if (order == Gtk.SortType.DESCENDING)
all_pkgs.reverse ();
manager_window.size_column.sort_order = order;
manager_window.state_column.sort_indicator = false;
manager_window.name_column.sort_indicator = false;
manager_window.version_column.sort_indicator = false;
manager_window.repo_column.sort_indicator = false;
manager_window.size_column.sort_indicator = true;
manager_window.sortinfo.column_number = 4;
manager_window.sortinfo.sort_type = order;
}
}
}

133
src/pamac_config.vala Normal file
View File

@@ -0,0 +1,133 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
public class Config: Object {
public uint64 refresh_period;
public bool enable_aur;
public bool recurse;
public string conf_path;
public Config (string path) {
this.conf_path = path;
// set default options
this.refresh_period = 4;
this.enable_aur = false;
this.recurse = false;
// parse conf file
this.parse_include_file (conf_path);
}
public void parse_include_file (string path) {
var file = GLib.File.new_for_path (path);
if (file.query_exists () == false)
GLib.stderr.printf ("File '%s' doesn't exist.\n", file.get_path ());
else {
try {
// Open file for reading and wrap returned FileInputStream into a
// DataInputStream, so we can read line by line
var dis = new DataInputStream (file.read ());
string line;
// Read lines until end of file (null) is reached
while ((line = dis.read_line (null)) != null) {
line = line.strip ();
if (line.length == 0) continue;
if (line[0] == '#') continue;
string[] splitted = line.split ("=");
string _key = splitted[0].strip ();
string _value = null;
if (splitted[1] != null)
_value = splitted[1].strip ();
if (_key == "RefreshPeriod")
this.refresh_period = uint64.parse (_value);
else if (_key == "EnableAUR")
this.enable_aur = true;
else if (_key == "RemoveUnrequiredDeps")
this.recurse = true;
}
} catch (GLib.Error e) {
GLib.stderr.printf("%s\n", e.message);
}
}
}
public void write (HashTable<string,string> new_conf) {
var file = GLib.File.new_for_path (this.conf_path);
if (file.query_exists () == false)
GLib.stderr.printf ("File '%s' doesn't exist.\n", file.get_path ());
else {
try {
// Open file for reading and wrap returned FileInputStream into a
// DataInputStream, so we can read line by line
var dis = new DataInputStream (file.read ());
string line;
string[] data = {};
// Read lines until end of file (null) is reached
while ((line = dis.read_line (null)) != null) {
if (line.contains ("RefreshPeriod")) {
if (new_conf.contains ("RefreshPeriod")) {
string _value = new_conf.get ("RefreshPeriod");
data += "RefreshPeriod = %s\n".printf (_value);
this.refresh_period = uint64.parse (_value);
} else
data += line + "\n";
} else if (line.contains ("EnableAUR")) {
if (new_conf.contains ("EnableAUR")) {
bool _value = bool.parse (new_conf.get ("EnableAUR"));
if (_value == true)
data += "EnableAUR\n";
else
data += "#EnableAUR\n";
this.enable_aur = _value;
} else
data += line + "\n";
} else if (line.contains ("RemoveUnrequiredDeps")) {
if (new_conf.contains ("RemoveUnrequiredDeps")) {
bool _value = bool.parse (new_conf.get ("RemoveUnrequiredDeps"));
if (_value == true)
data += "RemoveUnrequiredDeps\n";
else
data += "#RemoveUnrequiredDeps\n";
this.enable_aur = _value;
} else
data += line + "\n";
} else
data += line + "\n";
}
// delete the file before rewrite it
file.delete ();
// creating a DataOutputStream to the file
var dos = new DataOutputStream (file.create (FileCreateFlags.REPLACE_DESTINATION));
foreach (string new_line in data) {
// writing a short string to the stream
dos.put_string (new_line);
}
} catch (GLib.Error e) {
GLib.stderr.printf("%s\n", e.message);
}
}
}
public void reload () {
this.enable_aur = false;
this.recurse = false;
this.parse_include_file (this.conf_path);
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
[GtkTemplate (ui = "/org/manjaro/pamac/preferences/preferences_dialog.ui")]
public class PreferencesDialog : Gtk.Dialog {
[GtkChild]
public Gtk.Switch enable_aur_button;
[GtkChild]
public Gtk.Switch remove_unrequired_deps_button;
[GtkChild]
public Gtk.SpinButton refresh_period_spin_button;
[GtkChild]
public Gtk.Label refresh_period_label;
public PreferencesDialog (Gtk.ApplicationWindow window) {
Object (transient_for: window, use_header_bar: 0);
refresh_period_label.set_markup (dgettext (null, "How often to check for updates, value in hours") +":");
}
}
}

61
src/progress_window.vala Normal file
View File

@@ -0,0 +1,61 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
[GtkTemplate (ui = "/org/manjaro/pamac/transaction/progress_window.ui")]
public class ProgressWindow : Gtk.Window {
[GtkChild]
public Gtk.ProgressBar progressbar;
[GtkChild]
public Gtk.Label action_label;
[GtkChild]
public Gtk.Button cancel_button;
[GtkChild]
public Gtk.Button close_button;
[GtkChild]
public Gtk.Expander expander;
Transaction transaction;
public ProgressWindow (Transaction transaction, Gtk.ApplicationWindow? window) {
Object (transient_for: window);
this.transaction = transaction;
}
[GtkCallback]
public void on_close_button_clicked () {
this.hide ();
while (Gtk.events_pending ())
Gtk.main_iteration ();
}
[GtkCallback]
public void on_cancel_button_clicked () {
transaction.cancel ();
transaction.clear_lists ();
transaction.finished (false);
this.hide ();
while (Gtk.events_pending ())
Gtk.main_iteration ();
}
}
}

899
src/transaction.vala Normal file
View File

@@ -0,0 +1,899 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Gtk;
using Vte;
using Alpm;
namespace Pamac {
[DBus (name = "org.manjaro.pamac")]
public interface Daemon : Object {
public abstract void write_config (HashTable<string,string> new_conf) throws IOError;
public abstract async void refresh (int force, bool emit_signal) throws IOError;
public abstract ErrorInfos trans_init (TransFlag transflags) throws IOError;
public abstract ErrorInfos trans_sysupgrade (int enable_downgrade) throws IOError;
public abstract ErrorInfos trans_add_pkg (string pkgname) throws IOError;
public abstract ErrorInfos trans_remove_pkg (string pkgname) throws IOError;
public abstract ErrorInfos trans_load_pkg (string pkgpath) throws IOError;
public abstract async void trans_prepare () throws IOError;
public abstract void choose_provider (int provider) throws IOError;
public abstract UpdatesInfos[] trans_to_add () throws IOError;
public abstract UpdatesInfos[] trans_to_remove () throws IOError;
public abstract async void trans_commit () throws IOError;
public abstract void trans_release () throws IOError;
public abstract void trans_cancel () throws IOError;
[DBus (no_reply = true)]
public abstract void quit () throws IOError;
public signal void emit_event (uint event, string msg);
public signal void emit_providers (string depend, string[] providers);
public signal void emit_progress (uint progress, string action, string pkgname, int percent, uint n_targets, uint current_target);
public signal void emit_download (string filename, uint64 xfered, uint64 total);
public signal void emit_totaldownload (uint64 total);
public signal void emit_log (uint level, string msg);
public signal void emit_refreshed (ErrorInfos error);
public signal void emit_trans_prepared (ErrorInfos error);
public signal void emit_trans_committed (ErrorInfos error);
}
public class Transaction: Object {
public Daemon daemon;
public Alpm.Config alpm_config;
public Pamac.Config pamac_config;
public TransactionData data;
public Mode mode;
uint64 total_download;
uint64 already_downloaded;
string previous_label;
string previous_textbar;
double previous_percent;
string previous_filename;
uint build_timeout_id;
bool sysupgrade_after_trans;
bool sysupgrade_after_build;
Terminal term;
//dialogs
ChooseProviderDialog choose_provider_dialog;
TransactionSumDialog transaction_sum_dialog;
TransactionInfoDialog transaction_info_dialog;
ProgressWindow progress_window;
//parent window
ApplicationWindow? window;
public signal void finished (bool error);
public Transaction (ApplicationWindow? window, Pamac.Config pamac_config) {
alpm_config = new Alpm.Config ("/etc/pacman.conf");
this.pamac_config = pamac_config;
mode = Mode.MANAGER;
data = TransactionData ();
data.flags = Alpm.TransFlag.CASCADE;
data.to_add = new HashTable<string, string> (str_hash, str_equal);
data.to_remove = new HashTable<string, string> (str_hash, str_equal);
data.to_load = new HashTable<string, string> (str_hash, str_equal);
data.to_build = new HashTable<string, string> (str_hash, str_equal);
connecting_dbus_signals ();
//creating dialogs
this.window = window;
choose_provider_dialog = new ChooseProviderDialog (window);
transaction_sum_dialog = new TransactionSumDialog (window);
transaction_info_dialog = new TransactionInfoDialog (window);
progress_window = new ProgressWindow (this, window);
//creating terminal
term = new Terminal ();
term.scroll_on_output = false;
term.expand = true;
term.height_request = 200;
term.set_visible (true);
// add term in a grid with a scrollbar
var grid = new Grid ();
grid.expand = true;
grid.set_visible (true);
var sb = new Scrollbar (Orientation.VERTICAL, term.vadjustment);
sb.set_visible (true);
grid.attach (term, 0, 0, 1, 1);
grid.attach (sb, 1, 0, 1, 1);
progress_window.expander.add (grid);
// progress data
total_download = 0;
already_downloaded = 0;
previous_label = "";
previous_textbar = "";
previous_percent = 0.0;
previous_filename = "";
sysupgrade_after_trans = false;
sysupgrade_after_build = false;
}
public void write_config (HashTable<string,string> new_conf) {
try {
daemon.write_config (new_conf);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
}
public void refresh_alpm_config () {
alpm_config = new Alpm.Config ("/etc/pacman.conf");
}
public void refresh (int force) {
string action = dgettext ("pacman", "Synchronizing package databases...\n").replace ("\n", "");
try {
term.reset (true, true);
term.spawn_sync (PtyFlags.DEFAULT, "~/", {"/usr/bin/echo", action}, {}, SpawnFlags.DO_NOT_REAP_CHILD, null, null);
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
progress_window.action_label.set_text (action);
progress_window.progressbar.set_fraction (0);
progress_window.progressbar.set_text ("");
progress_window.cancel_button.visible = true;
progress_window.close_button.visible = false;
progress_window.show ();
daemon.refresh.begin (force, true, (obj, res) => {
try {
daemon.refresh.end (res);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
});
}
public void sysupgrade_simple (int enable_downgrade) {
print("simple sysupgrade\n");
progress_window.progressbar.set_fraction (0);
progress_window.cancel_button.visible = true;
ErrorInfos err = ErrorInfos ();
try {
err = daemon.trans_init (0);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
if (err.str != "") {
finished (true);
handle_error (err);
} else {
try {
err = daemon.trans_sysupgrade (enable_downgrade);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
if (err.str == "") {
progress_window.show ();
while (Gtk.events_pending ())
Gtk.main_iteration ();
daemon.trans_prepare.begin ((obj, res) => {
try {
daemon.trans_prepare.end (res);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
});
} else {
release ();
finished (true);
handle_error (err);
}
}
}
public void sysupgrade (int enable_downgrade) {
string action = dgettext ("pacman", "Starting full system upgrade...\n").replace ("\n", "");
try {
term.spawn_sync (PtyFlags.DEFAULT, "~/", {"/usr/bin/echo", action}, {}, SpawnFlags.DO_NOT_REAP_CHILD, null, null);
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
progress_window.action_label.set_text (action);
progress_window.progressbar.set_fraction (0);
progress_window.progressbar.set_text ("");
progress_window.cancel_button.visible = true;
progress_window.close_button.visible = false;
while (Gtk.events_pending ())
Gtk.main_iteration ();
// sysupgrade
print("get syncfirst\n");
// get syncfirst updates
UpdatesInfos[] syncfirst_updates = get_syncfirst_updates (alpm_config);
if (syncfirst_updates.length != 0) {
clear_lists ();
if (mode == Mode.MANAGER)
sysupgrade_after_trans = true;
foreach (UpdatesInfos infos in syncfirst_updates)
data.to_add.insert (infos.name, infos.name);
// run as a standard transaction
run ();
} else {
if (pamac_config.enable_aur) {
print("get aur updates\n");
string[] ignore_pkgs = get_ignore_pkgs (alpm_config);
UpdatesInfos[] aur_updates = get_aur_updates (alpm_config, ignore_pkgs);
if (aur_updates.length != 0) {
clear_lists ();
sysupgrade_after_build = true;
foreach (UpdatesInfos infos in aur_updates)
data.to_build.insert (infos.name, infos.name);
}
}
sysupgrade_simple (enable_downgrade);
}
}
public void clear_lists () {
data.to_add.steal_all ();
data.to_remove.steal_all ();
data.to_build.steal_all ();
}
public void run () {
string action = dgettext (null,"Preparing") + "...";
try {
term.reset (true, true);
term.spawn_sync (PtyFlags.DEFAULT, "~/", {"/usr/bin/echo", action}, {}, SpawnFlags.DO_NOT_REAP_CHILD, null, null);
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
progress_window.action_label.set_text (action);
progress_window.progressbar.set_fraction (0);
progress_window.progressbar.set_text ("");
progress_window.cancel_button.visible = true;
progress_window.close_button.visible = false;
progress_window.show ();
while (Gtk.events_pending ())
Gtk.main_iteration ();
// run
ErrorInfos err = ErrorInfos ();
if (data.to_add.size () == 0
&& data.to_remove.size () == 0
&& data.to_load.size () == 0
&& data.to_build.size () != 0) {
// there only AUR packages to build so no need to prepare transaction
on_emit_trans_prepared (err);
} else {
try {
err = daemon.trans_init (data.flags);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
if (err.str != "") {
finished (true);
handle_error (err);
} else {
foreach (string name in data.to_add.get_keys ()) {
try {
err = daemon.trans_add_pkg (name);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
if (err.str != "")
break;
}
foreach (string name in data.to_remove.get_keys ()) {
try {
err = daemon.trans_remove_pkg (name);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
if (err.str != "")
break;
}
foreach (string path in data.to_load.get_keys ()) {
try {
err = daemon.trans_load_pkg (path);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
if (err.str != "")
break;
}
if (err.str == "") {
daemon.trans_prepare.begin ((obj, res) => {
try {
daemon.trans_prepare.end (res);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
});
} else {
release ();
finished (true);
handle_error (err);
}
}
}
}
public void choose_provider (string depend, string[] providers) {
int len = providers.length;
choose_provider_dialog.label.set_markup ("<b>%s</b>".printf (dgettext (null, "Choose a provider for %s:").printf (depend, len)));
choose_provider_dialog.comboboxtext.remove_all ();
foreach (string provider in providers)
choose_provider_dialog.comboboxtext.append_text (provider);
choose_provider_dialog.comboboxtext.active = 0;
choose_provider_dialog.run ();
choose_provider_dialog.hide ();
while (Gtk.events_pending ())
Gtk.main_iteration ();
try {
daemon.choose_provider (choose_provider_dialog.comboboxtext.active);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
}
public int set_transaction_sum () {
// return 1 if transaction_sum is empty, 0 otherwise
int ret = 1;
uint64 dsize = 0;
UpdatesInfos[] prepared_to_add = {};
UpdatesInfos[] prepared_to_remove = {};
string[] to_downgrade = {};
string[] to_install = {};
string[] to_reinstall = {};
string[] to_update = {};
string[] to_build = {};
TreeIter iter;
transaction_sum_dialog.top_label.set_markup ("<big><b>%s</b></big>".printf (dgettext (null, "Transaction Summary")));
transaction_sum_dialog.sum_list.clear ();
try {
prepared_to_add = daemon.trans_to_add ();
prepared_to_remove = daemon.trans_to_remove ();
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
foreach (UpdatesInfos pkg_info in prepared_to_add) {
dsize += pkg_info.download_size;
unowned Alpm.Package? local_pkg = alpm_config.handle.localdb.get_pkg (pkg_info.name);
if (local_pkg == null) {
to_install += "%s %s".printf (pkg_info.name, pkg_info.version);
} else {
int cmp = pkg_vercmp (pkg_info.version, local_pkg.version);
if (cmp == 1)
to_update += "%s %s".printf (pkg_info.name, pkg_info.version);
else if (cmp == 0)
to_reinstall += "%s %s".printf (pkg_info.name, pkg_info.version);
else
to_downgrade += "%s %s".printf (pkg_info.name, pkg_info.version);
}
}
foreach (string name in data.to_build.get_keys ())
to_build += name;
int len = prepared_to_remove.length;
int i;
if (len != 0) {
ret = 0;
transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
0, dgettext (null, "To remove") + ":",
1, "%s %s".printf (prepared_to_remove[0].name, prepared_to_remove[0].version));
i = 1;
while (i < len) {
transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
1, "%s %s".printf (prepared_to_remove[i].name, prepared_to_remove[i].version));
i++;
}
}
len = to_downgrade.length;
if (len != 0) {
ret = 0;
transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
0, dgettext (null, "To downgrade") + ":",
1, to_downgrade[0]);
i = 1;
while (i < len) {
transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
1, to_downgrade[i]);
i++;
}
}
len = to_build.length;
if (len != 0) {
ret = 0;
transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
0, dgettext (null, "To build") + ":",
1, to_build[0]);
i = 1;
while (i < len) {
transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
1, to_build[i]);
i++;
}
}
len = to_install.length;
if (len != 0) {
ret = 0;
transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
0, dgettext (null, "To install") + ":",
1, to_install[0]);
i = 1;
while (i < len) {
transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
1, to_install[i]);
i++;
}
}
len = to_reinstall.length;
if (len != 0) {
ret = 0;
transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
0, dgettext (null, "To reinstall") + ":",
1, to_reinstall[0]);
i = 1;
while (i < len) {
transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
1, to_reinstall[i]);
i++;
}
}
if (mode == Mode.MANAGER) {
len = to_update.length;
if (len != 0) {
ret = 0;
transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
0, dgettext (null, "To update") + ":",
1, to_update[0]);
i = 1;
while (i < len) {
transaction_sum_dialog.sum_list.insert_with_values (out iter, -1,
1, to_update[i]);
i++;
}
}
}
if (dsize == 0)
transaction_sum_dialog.bottom_label.set_visible (false);
else {
transaction_sum_dialog.bottom_label.set_markup ("<b>%s %s</b>".printf (dgettext (null, "Total download size:"), format_size (dsize)));
transaction_sum_dialog.bottom_label.set_visible (true);
}
return ret;
}
public void commit () {
progress_window.cancel_button.visible = false;
daemon.trans_commit.begin ((obj, res) => {
try {
daemon.trans_commit.end (res);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
});
}
public void build_aur_packages () {
string[] cmds = {"/usr/bin/yaourt", "-S"};
foreach (string name in data.to_build.get_keys ())
cmds += name;
string action = dgettext (null,"Building packages") + "...";
try {
term.reset (true, true);
term.spawn_sync (PtyFlags.DEFAULT, "~/", {"/usr/bin/echo", action}, {}, SpawnFlags.DO_NOT_REAP_CHILD, null, null);
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
progress_window.action_label.set_text (action);
progress_window.progressbar.set_fraction (0);
progress_window.progressbar.set_text ("");
progress_window.cancel_button.visible = false;
progress_window.close_button.visible = false;
progress_window.expander.set_expanded (true);
progress_window.width_request = 700;
term.child_exited.connect (on_term_child_exited);
term.grab_focus ();
build_timeout_id = Timeout.add (500, (GLib.SourceFunc) progress_window.progressbar.pulse);
try {
Pid child_pid;
term.spawn_sync (PtyFlags.DEFAULT, "~/", cmds, {}, SpawnFlags.DO_NOT_REAP_CHILD, null, out child_pid);
//term.watch_child (child_pid);
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
}
public void cancel () {
try {
daemon.trans_cancel ();
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
}
public void release () {
try {
daemon.trans_release ();
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
}
public void stop_daemon () {
try {
daemon.quit ();
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
}
void on_emit_event (uint event, string msg) {
switch (event) {
case Event.CHECKDEPS_START:
break;
case Event.FILECONFLICTS_START:
break;
case Event.RESOLVEDEPS_START:
break;
case Event.INTERCONFLICTS_START:
break;
case Event.ADD_START:
progress_window.cancel_button.visible = false;
break;
case Event.ADD_DONE:
break;
case Event.REMOVE_START:
progress_window.cancel_button.visible = false;
break;
case Event.REMOVE_DONE:
break;
case Event.UPGRADE_START:
break;
case Event.UPGRADE_DONE:
break;
case Event.DOWNGRADE_START:
break;
case Event.DOWNGRADE_DONE:
break;
case Event.REINSTALL_START:
break;
case Event.REINSTALL_DONE:
break;
case Event.INTEGRITY_START:
break;
case Event.KEYRING_START:
break;
//~ case Event.KEY_DOWNLOAD_START:
//~ break;
case Event.LOAD_START:
break;
//~ case Event.DELTA_INTEGRITY_START:
//~ break;
//~ case Event.DELTA_PATCHES_START:
//~ break;
//~ case Event.DELTA_PATCH_START:
//~ break;
//~ case Event.DELTA_PATCH_DONE:
//~ break;
//~ case Event.DELTA_PATCH_FAILED:
//~ break;
case Event.SCRIPTLET_INFO:
progress_window.expander.set_expanded (true);
break;
case Event.RETRIEVE_START:
progress_window.action_label.set_text (msg.replace ("\n", ""));
break;
case Event.DISKSPACE_START:
break;
//~ case Event.OPTDEP_REQUIRED:
//~ break;
//~ case Event.DATABASE_MISSING:
//~ break;
case Event.FILECONFLICTS_DONE:
case Event.CHECKDEPS_DONE:
case Event.RESOLVEDEPS_DONE:
case Event.INTERCONFLICTS_DONE:
case Event.INTEGRITY_DONE:
case Event.KEYRING_DONE:
case Event.KEY_DOWNLOAD_DONE:
case Event.LOAD_DONE:
case Event.DELTA_INTEGRITY_DONE:
case Event.DELTA_PATCHES_DONE:
case Event.DISKSPACE_DONE:
break;
default:
break;
}
try {
term.spawn_sync (PtyFlags.DEFAULT, "~/", {"/usr/bin/echo", "-n", msg}, {}, SpawnFlags.DO_NOT_REAP_CHILD, null, null);
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
}
void on_emit_providers (string depend, string[] providers) {
choose_provider (depend, providers);
}
void on_emit_progress (uint progress, string action, string pkgname, int percent, uint n_targets, uint current_target) {
double fraction;
switch (progress) {
case Progress.ADD_START:
case Progress.UPGRADE_START:
case Progress.DOWNGRADE_START:
case Progress.REINSTALL_START:
case Progress.REMOVE_START:
fraction = ((float) (current_target-1)/n_targets)+((float) percent/(100*n_targets));
break;
case Progress.CONFLICTS_START:
case Progress.DISKSPACE_START:
case Progress.INTEGRITY_START:
case Progress.KEYRING_START:
case Progress.LOAD_START:
default:
fraction = (float) percent/100;
break;
}
string label;
if (pkgname != "")
label = "%s %s...".printf (action, pkgname);
else
label = "%s...".printf (action);
if (label != previous_label) {
previous_label = label;
progress_window.action_label.set_text (label);
}
string textbar = "%lu/%lu".printf (current_target, n_targets);
if (textbar != previous_textbar) {
previous_textbar = textbar;
progress_window.progressbar.set_text (textbar);
}
if (fraction != previous_percent) {
previous_percent = fraction;
progress_window.progressbar.set_fraction (fraction);
}
while (Gtk.events_pending ())
Gtk.main_iteration ();
}
void on_emit_download (string filename, uint64 xfered, uint64 total) {
string label;
string textbar;
double fraction;
if (filename != previous_filename) {
previous_filename = filename;
if (filename.has_suffix (".db")) {
label = dgettext (null, "Refreshing {repo}").replace ("{repo}", filename.replace (".db", "")) + "...";
} else {
label = dgettext (null, "Downloading {pkgname}").replace ("{pkgname}", filename.replace (".pkg.tar.xz", "")) + "...";
}
if (label != previous_label) {
previous_label = label;
progress_window.action_label.set_text (label);
try {
term.spawn_sync (PtyFlags.DEFAULT, "~/", {"/usr/bin/echo", label}, {}, SpawnFlags.DO_NOT_REAP_CHILD, null, null);
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
}
}
if (total_download > 0) {
fraction = (float) (xfered + already_downloaded) / total_download;
textbar = "%s/%s".printf (format_size (xfered + already_downloaded), format_size (total_download));
} else {
fraction = (float) xfered / total;
textbar = "%s/%s".printf (format_size (xfered), format_size (total));
}
if (fraction != previous_percent) {
previous_percent = fraction;
progress_window.progressbar.set_fraction (fraction);
}
if (textbar != previous_textbar) {
previous_textbar = textbar;
progress_window.progressbar.set_text (textbar);
}
if (xfered == total)
already_downloaded += total;
}
void on_emit_totaldownload (uint64 total) {
total_download = total;
}
void on_emit_log (uint level, string msg) {
// msg ends with \n
string? line = null;
TextIter end_iter;
if ((Alpm.LogLevel) level == Alpm.LogLevel.WARNING) {
line = dgettext (null, "Warning") + ": " + msg;
transaction_info_dialog.textbuffer.get_end_iter (out end_iter);
transaction_info_dialog.textbuffer.insert (ref end_iter, msg, msg.length);
} else if ((Alpm.LogLevel) level == Alpm.LogLevel.ERROR) {
line = dgettext (null, "Error") + ": " + msg;
}
if (line != null) {
progress_window.expander.set_expanded (true);
try {
term.spawn_sync (PtyFlags.DEFAULT, "~/", {"/usr/bin/echo", "-n", line}, {}, SpawnFlags.DO_NOT_REAP_CHILD, null, null);
} catch (Error e) {
stderr.printf ("Error: %s\n", e.message);
}
}
}
public void handle_warning () {
if (transaction_info_dialog.textbuffer.text != "") {
transaction_info_dialog.set_title (dgettext (null, "Warning"));
transaction_info_dialog.label.set_visible (false);
transaction_info_dialog.expander.set_visible (true);
transaction_info_dialog.expander.set_expanded (true);
transaction_info_dialog.run ();
transaction_info_dialog.hide ();
TextIter start_iter;
TextIter end_iter;
transaction_info_dialog.textbuffer.get_start_iter (out start_iter);
transaction_info_dialog.textbuffer.get_end_iter (out end_iter);
transaction_info_dialog.textbuffer.delete (ref start_iter, ref end_iter);
}
}
public void handle_error (ErrorInfos error) {
TextIter start_iter;
TextIter end_iter;
transaction_info_dialog.set_title (dgettext (null, "Error"));
transaction_info_dialog.label.set_visible (true);
transaction_info_dialog.label.set_markup (error.str.replace ("\n", ""));
transaction_info_dialog.textbuffer.get_start_iter (out start_iter);
transaction_info_dialog.textbuffer.get_end_iter (out end_iter);
transaction_info_dialog.textbuffer.delete (ref start_iter, ref end_iter);
if (error.details.length != 0) {
foreach (string detail in error.details) {
transaction_info_dialog.textbuffer.get_end_iter (out end_iter);
transaction_info_dialog.textbuffer.insert (ref end_iter, detail, detail.length);
}
transaction_info_dialog.expander.set_visible (true);
} else
transaction_info_dialog.expander.set_visible (false);
transaction_info_dialog.run ();
transaction_info_dialog.hide ();
progress_window.hide ();
while (Gtk.events_pending ())
Gtk.main_iteration ();
}
public void on_emit_refreshed (ErrorInfos error) {
print("transaction refreshed\n");
refresh_alpm_config ();
if (error.str == "") {
if (mode == Mode.UPDATER) {
progress_window.hide ();
finished (false);
} else {
sysupgrade (0);
}
} else {
handle_error (error);
finished (true);
}
}
public void on_emit_trans_prepared (ErrorInfos error) {
print ("transaction prepared\n");
if (error.str == "") {
handle_warning ();
int ret = set_transaction_sum ();
if (ret == 0) {
if (data.to_add.size () == 0
&& data.to_remove.size () == 0
&& data.to_load.size () == 0
&& data.to_build.size () != 0) {
// there only AUR packages to build or we update AUR packages first
release ();
if (transaction_sum_dialog.run () == ResponseType.OK) {
transaction_sum_dialog.hide ();
while (Gtk.events_pending ())
Gtk.main_iteration ();
ErrorInfos err = ErrorInfos ();
on_emit_trans_committed (err);
} else {
progress_window.hide ();
transaction_sum_dialog.hide ();
finished (true);
}
} else if (sysupgrade_after_build) {
print("sysupgrade_after_build\n");
sysupgrade_after_build = false;
commit ();
} else if (transaction_sum_dialog.run () == ResponseType.OK) {
transaction_sum_dialog.hide ();
while (Gtk.events_pending ())
Gtk.main_iteration ();
commit ();
} else {
progress_window.hide ();
transaction_sum_dialog.hide ();
release ();
finished (true);
}
} else if (mode == Mode.UPDATER) {
commit ();
} else {
//ErrorInfos err = ErrorInfos ();
//err.str = dgettext (null, "Nothing to do") + "\n";
progress_window.hide ();
release ();
clear_lists ();
finished (false);
//handle_error (err);
}
} else {
finished (true);
handle_error (error);
}
}
public void on_emit_trans_committed (ErrorInfos error) {
print("transaction committed\n");
term.child_exited.disconnect (on_term_child_exited);
if (error.str == "") {
if (data.to_build.size () != 0) {
build_aur_packages ();
} else {
//progress_window.action_label.set_text (dgettext (null, "Transaction successfully finished"));
//progress_window.close_button.set_visible (true);
clear_lists ();
handle_warning ();
refresh_alpm_config ();
if (sysupgrade_after_trans) {
sysupgrade_after_trans = false;
sysupgrade (0);
} else if (sysupgrade_after_build) {
sysupgrade_simple (0);
} else {
progress_window.hide ();
finished (false);
}
}
} else {
finished (true);
handle_error (error);
}
total_download = 0;
already_downloaded = 0;
}
void on_term_child_exited (int status) {
Source.remove (build_timeout_id);
data.to_build.steal_all ();
ErrorInfos err = ErrorInfos ();
on_emit_trans_committed (err);
}
void connecting_dbus_signals () {
try {
daemon = Bus.get_proxy_sync (BusType.SYSTEM, "org.manjaro.pamac",
"/org/manjaro/pamac");
// Connecting to signals
daemon.emit_event.connect (on_emit_event);
daemon.emit_providers.connect (on_emit_providers);
daemon.emit_progress.connect (on_emit_progress);
daemon.emit_download.connect (on_emit_download);
daemon.emit_totaldownload.connect (on_emit_totaldownload);
daemon.emit_log.connect (on_emit_log);
daemon.emit_refreshed.connect (on_emit_refreshed);
daemon.emit_trans_prepared.connect (on_emit_trans_prepared);
daemon.emit_trans_committed.connect (on_emit_trans_committed);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
[GtkTemplate (ui = "/org/manjaro/pamac/transaction/transaction_info_dialog.ui")]
public class TransactionInfoDialog : Gtk.Dialog {
[GtkChild]
public Gtk.Label label;
[GtkChild]
public Gtk.Expander expander;
[GtkChild]
public Gtk.TextView textview;
public Gtk.TextBuffer textbuffer;
public TransactionInfoDialog (Gtk.ApplicationWindow? window) {
Object (transient_for: window, use_header_bar: 0);
textbuffer = textview.get_buffer ();
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
[GtkTemplate (ui = "/org/manjaro/pamac/transaction/transaction_sum_dialog.ui")]
public class TransactionSumDialog : Gtk.Dialog {
[GtkChild]
public Gtk.Label top_label;
[GtkChild]
public Gtk.Label bottom_label;
[GtkChild]
public Gtk.TreeView treeview;
public Gtk.ListStore sum_list;
public TransactionSumDialog (Gtk.ApplicationWindow? window) {
Object (transient_for: window, use_header_bar: 0);
sum_list = new Gtk.ListStore (2, typeof (string), typeof (string));
treeview.set_model (sum_list);
}
}
}

256
src/tray.vala Normal file
View File

@@ -0,0 +1,256 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// i18n
const string GETTEXT_PACKAGE = "pamac";
const string update_icon_name = "pamac-tray-update";
const string update_info = _("{number} available updates");
const string one_update_info = _("1 available update");
const string noupdate_icon_name = "pamac-tray-no-update";
const string noupdate_info = _("Your system is up-to-date");
namespace Pamac {
[DBus (name = "org.manjaro.pamac")]
public interface Daemon : Object {
public abstract async void refresh (int force, bool emit_signal) throws IOError;
public abstract UpdatesInfos[] get_updates () throws IOError;
[DBus (no_reply = true)]
public abstract void quit () throws IOError;
}
public class TrayIcon: Gtk.Application {
Notify.Notification notification;
Daemon daemon;
Pamac.Config pamac_config;
bool locked;
uint refresh_timeout_id;
Gtk.StatusIcon status_icon;
Gtk.Menu menu;
public TrayIcon () {
application_id = "org.manjaro.pamac.tray";
flags = ApplicationFlags.FLAGS_NONE;
}
void start_daemon () {
try {
daemon = Bus.get_proxy_sync (BusType.SYSTEM, "org.manjaro.pamac",
"/org/manjaro/pamac");
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
}
void stop_daemon () {
try {
daemon.quit ();
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
}
// Create menu for right button
void create_menu () {
menu = new Gtk.Menu ();
Gtk.MenuItem item;
item = new Gtk.MenuItem.with_label (_("Update Manager"));
item.activate.connect (execute_updater);
menu.append (item);
item = new Gtk.MenuItem.with_label (_("Package Manager"));
item.activate.connect (execute_manager);
menu.append (item);
item = new Gtk.MenuItem.with_label (_("Quit"));
item.activate.connect (this.release);
menu.append (item);
menu.show_all ();
}
// Show popup menu on right button
void menu_popup (uint button, uint time) {
menu.popup (null, null, null, button, time);
}
void left_clicked () {
if (status_icon.icon_name == "pamac-tray-update")
execute_updater ();
}
void execute_updater () {
try {
Process.spawn_async(null, new string[]{"/usr/bin/pamac-updater"}, null, SpawnFlags.SEARCH_PATH, null, null);
} catch (Error e) {
print(e.message);
}
}
void execute_manager () {
try {
Process.spawn_async(null, new string[]{"/usr/bin/pamac-manager"}, null, SpawnFlags.SEARCH_PATH, null, null);
} catch (Error e) {
print(e.message);
}
}
public void update_icon (string icon, string info) {
status_icon.set_from_icon_name (icon);
status_icon.set_tooltip_markup (info);
}
bool refresh () {
start_daemon ();
daemon.refresh.begin (1, false, (obj, res) => {
try {
daemon.refresh.end (res);
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
});
return true;
}
void check_updates () {
UpdatesInfos[] updates = {};
bool pamac_run = check_pamac_running ();
try {
updates = daemon.get_updates ();
} catch (IOError e) {
stderr.printf ("IOError: %s\n", e.message);
}
uint updates_nb = updates.length;
if (updates_nb == 0) {
this.update_icon (noupdate_icon_name, noupdate_info);
} else if (updates_nb == 1) {
this.update_icon (update_icon_name, one_update_info);
if (pamac_run == false)
show_notification (one_update_info);
} else {
// workaround to use python format string
string info = update_info.replace ("{number}", updates_nb.to_string ());
this.update_icon (update_icon_name, info);
if (pamac_run == false)
show_notification (info);
}
if (pamac_run == false)
stop_daemon ();
}
void show_notification (string info) {
//~ notification = new Notification (_("Update Manager"));
//~ Gtk.IconTheme icon_theme = Gtk.IconTheme.get_default ();
//~ Gdk.Pixbuf icon = icon_theme.load_icon ("system-software-update", 32, 0);
//~ notification.set_icon (icon);
//~ notification.set_body (info);
//~ var action = new SimpleAction ("update", null);
//~ action.activate.connect (execute_updater);
//~ this.add_action (action);
//~ notification.add_button (_("Show available updates"), "app.update");
//~ this.send_notification (_("Update Manager"), notification);
try {
notification = new Notify.Notification (_("Update Manager"), info, "system-software-update");
notification.add_action ("update", _("Show available updates"), execute_updater);
notification.show ();
} catch (Error e) {
stderr.printf ("Notify Error: %s", e.message);
}
}
bool check_pamac_running () {
Application app;
bool run = false;
app = new Application ("org.manjaro.pamac.manager", 0);
try {
app.register ();
} catch (GLib.Error e) {
stderr.printf ("%s\n", e.message);
}
run = app.get_is_remote ();
if (run)
return run;
else {
app = new Application ("org.manjaro.pamac.updater", 0);
try {
app.register ();
} catch (GLib.Error e) {
stderr.printf ("%s\n", e.message);
}
run = app.get_is_remote ();
return run;
}
}
bool check_pacman_running () {
GLib.File lockfile = GLib.File.new_for_path ("/var/lib/pacman/db.lck");
if (locked) {
if (lockfile.query_exists () == false) {
locked = false;
check_updates ();
}
} else {
if (lockfile.query_exists () == true) {
locked = true;
}
}
return true;
}
void launch_refresh_timeout (string? msg = null) {
if (refresh_timeout_id != 0) {
pamac_config.reload ();
Source.remove (refresh_timeout_id);
}
refresh_timeout_id = Timeout.add_seconds ((uint) pamac_config.refresh_period*3600, refresh);
}
public override void startup () {
// i18n
Intl.textdomain ("pamac");
Intl.setlocale (LocaleCategory.ALL, "");
base.startup ();
pamac_config = new Pamac.Config ("/etc/pamac.conf");
locked = false;
refresh_timeout_id = 0;
status_icon = new Gtk.StatusIcon ();
status_icon.set_visible (true);
status_icon.activate.connect (left_clicked);
create_menu ();
status_icon.popup_menu.connect (menu_popup);
Notify.init(_("Update Manager"));
refresh ();
launch_refresh_timeout ();
Timeout.add (500, check_pacman_running);
this.hold ();
}
public override void activate () {
// nothing to do
}
public static int main (string[] args) {
var tray_icon = new TrayIcon();
return tray_icon.run (args);
}
}
}

55
src/updater.vala Normal file
View File

@@ -0,0 +1,55 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Pamac {
public class Updater : Gtk.Application {
UpdaterWindow updater_window;
public Updater () {
application_id = "org.manjaro.pamac.updater";
flags = ApplicationFlags.FLAGS_NONE;
}
public override void startup () {
// i18n
Intl.textdomain ("pamac");
Intl.setlocale (LocaleCategory.ALL, "");
base.startup ();
updater_window = new UpdaterWindow (this);
}
public override void activate () {
updater_window.present ();
}
public override void shutdown () {
base.shutdown ();
updater_window.transaction.stop_daemon ();
}
}
public static int main (string[] args) {
var updater = new Updater ();
return updater.run (args);
}
}

178
src/updater_window.vala Normal file
View File

@@ -0,0 +1,178 @@
/*
* pamac-vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a get of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Gtk;
namespace Pamac {
[GtkTemplate (ui = "/org/manjaro/pamac/updater/updater_window.ui")]
public class UpdaterWindow : Gtk.ApplicationWindow {
[GtkChild]
public Label top_label;
[GtkChild]
public TreeView updates_treeview;
[GtkChild]
public Label bottom_label;
[GtkChild]
public Button apply_button;
public ListStore updates_list;
public Pamac.Config pamac_config;
public Pamac.Transaction transaction;
PreferencesDialog preferences_dialog;
public UpdaterWindow (Gtk.Application application) {
Object (application: application);
pamac_config = new Pamac.Config ("/etc/pamac.conf");
updates_list = new Gtk.ListStore (2, typeof (string), typeof (string));
updates_treeview.set_model (updates_list);
transaction = new Transaction (this as ApplicationWindow, pamac_config);
transaction.mode = Mode.UPDATER;
transaction.finished.connect (on_emit_trans_finished);
preferences_dialog = new PreferencesDialog (this as ApplicationWindow);
top_label.set_markup("<b>%s</b>".printf (dgettext (null, "Your system is up-to-date")));
bottom_label.set_visible (false);
apply_button.set_sensitive (false);
transaction.refresh (0);
}
[GtkCallback]
public void on_preferences_button_clicked () {
bool enable_aur = pamac_config.enable_aur;
bool recurse = pamac_config.recurse;
uint64 refresh_period = pamac_config.refresh_period;
preferences_dialog.enable_aur_button.set_active (enable_aur);
preferences_dialog.remove_unrequired_deps_button.set_active (recurse);
preferences_dialog.refresh_period_spin_button.set_value (refresh_period);
int response = preferences_dialog.run ();
while (Gtk.events_pending ())
Gtk.main_iteration ();
if (response == ResponseType.OK) {
HashTable<string,string> new_conf = new HashTable<string,string> (str_hash, str_equal);
enable_aur = preferences_dialog.enable_aur_button.get_active ();
recurse = preferences_dialog.remove_unrequired_deps_button.get_active ();
refresh_period = (uint64) preferences_dialog.refresh_period_spin_button.get_value ();
if (enable_aur != pamac_config.enable_aur) {
new_conf.insert ("EnableAUR", enable_aur.to_string ());
}
if (recurse != pamac_config.recurse)
new_conf.insert ("RemoveUnrequiredDeps", recurse.to_string ());
if (refresh_period != pamac_config.refresh_period)
new_conf.insert ("RefreshPeriod", refresh_period.to_string ());
if (new_conf.size () != 0) {
transaction.write_config (new_conf);
pamac_config.reload ();
}
}
preferences_dialog.hide ();
}
[GtkCallback]
public void on_apply_button_clicked () {
this.get_window ().set_cursor (new Gdk.Cursor (Gdk.CursorType.WATCH));
while (Gtk.events_pending ())
Gtk.main_iteration ();
transaction.sysupgrade (0);
}
[GtkCallback]
public void on_refresh_button_clicked () {
this.get_window ().set_cursor (new Gdk.Cursor (Gdk.CursorType.WATCH));
while (Gtk.events_pending ())
Gtk.main_iteration ();
transaction.refresh (0);
}
[GtkCallback]
public void on_close_button_clicked () {
this.application.quit ();
}
public void on_emit_trans_finished (bool error) {
if (error == false) {
set_updates_list ();
}
this.get_window ().set_cursor (null);
}
public void set_updates_list () {
TreeIter iter;
string name;
string size;
uint64 dsize = 0;
uint updates_nb = 0;
updates_list.clear ();
// get syncfirst updates
UpdatesInfos[] syncfirst_updates = get_syncfirst_updates (transaction.alpm_config);
if (syncfirst_updates.length != 0) {
updates_nb = syncfirst_updates.length;
foreach (UpdatesInfos infos in syncfirst_updates) {
name = infos.name + " " + infos.version;
size = format_size (infos.download_size);
dsize += infos.download_size;
updates_list.insert_with_values (out iter, -1, 0, name, 1, size);
}
} else {
string[] ignore_pkgs = get_ignore_pkgs (transaction.alpm_config);
UpdatesInfos[] updates = get_repos_updates (transaction.alpm_config, ignore_pkgs);
foreach (UpdatesInfos infos in updates) {
name = infos.name + " " + infos.version;
size = format_size (infos.download_size);
dsize += infos.download_size;
updates_list.insert_with_values (out iter, -1, 0, name, 1, size);
}
updates_nb += updates.length;
if (pamac_config.enable_aur) {
UpdatesInfos[] aur_updates = get_aur_updates (transaction.alpm_config, ignore_pkgs);
updates_nb += aur_updates.length;
foreach (UpdatesInfos infos in aur_updates) {
name = infos.name + " " + infos.version;
size = format_size (infos.download_size);
dsize += infos.download_size;
updates_list.insert_with_values (out iter, -1, 0, name, 1, size);
}
}
}
if (updates_nb == 0) {
top_label.set_markup("<b>%s</b>".printf (dgettext (null, "Your system is up-to-date")));
apply_button.set_sensitive (false);
} else if (updates_nb == 1) {
top_label.set_markup("<b>%s</b>".printf (dgettext (null, "1 available update")));
apply_button.set_sensitive (true);
} else {
top_label.set_markup("<b>%s</b>".printf (dgettext (null, "{number} available updates").replace ("{number}", updates_nb.to_string ())));
apply_button.set_sensitive (true);
}
if (dsize == 0)
bottom_label.set_visible (false);
else {
bottom_label.set_markup("<b>%s %s</b>".printf (dgettext (null, "Total download size:"), format_size(dsize)));
bottom_label.set_visible (true);
}
}
}
}