Browse Source

Pamac 2.0

- complete rewrite in vala
- it now directly depends on libalpm so it is easier to maintain
- it is faster and uses less memory
- alpm bindings for vala, other people could be interested
- a DBus daemon which can perform every tasks which need root access using polkit to check authorization, it can be used by any other program.
- pamac-manager and pamac-updater as you know before but with some new design, try them !
- the progress dialog now includes a terminal, it permits to launch yaourt which is used now to build packages from AUR.
- reinstall a package
- install optional dependencies of a package
- mark a package as explicitly installed
tags/v5.1.2
Philip 5 years ago
parent
commit
b8153ea474
100 changed files with 24995 additions and 25444 deletions
  1. +11
    -3
      .gitignore
  2. +2
    -2
      .tx/config
  3. +49
    -0
      Makefile
  4. +11
    -0
      README
  5. +1
    -1
      data/applications/pamac-install.desktop
  6. BIN
      data/icons/16x16/actions/package-available-locked.png
  7. BIN
      data/icons/16x16/actions/package-broken.png
  8. BIN
      data/icons/16x16/actions/package-downgrade.png
  9. BIN
      data/icons/16x16/actions/package-installed-outdated.png
  10. BIN
      data/icons/16x16/actions/package-new.png
  11. BIN
      data/icons/16x16/actions/package-purge.png
  12. BIN
      data/icons/16x16/actions/package-supported.png
  13. BIN
      data/icons/16x16/actions/package-upgrade.png
  14. BIN
      data/icons/24x24/status/pamac-add.png
  15. BIN
      data/icons/24x24/status/pamac-cleanup.png
  16. BIN
      data/icons/24x24/status/pamac-delete.png
  17. BIN
      data/icons/24x24/status/pamac-download.png
  18. BIN
      data/icons/24x24/status/pamac-refresh.png
  19. BIN
      data/icons/24x24/status/pamac-search.png
  20. BIN
      data/icons/24x24/status/pamac-setup.png
  21. BIN
      data/icons/24x24/status/pamac-update.png
  22. BIN
      data/icons/24x24/status/pamac-wait.png
  23. +8
    -0
      data/mime/x-alpm-package.xml
  24. +0
    -8
      data/polkit/org.manjaro.pamac.policy.in
  25. +278
    -0
      examples/pactree.vala
  26. +0
    -10
      files_to_translate
  27. +0
    -721
      gui/dialogs.ui
  28. +0
    -40
      pamac-check_updates.py
  29. +0
    -833
      pamac-daemon.py
  30. +0
    -170
      pamac-install.py
  31. +0
    -1045
      pamac-manager.py
  32. +0
    -56
      pamac-refresh.py
  33. +0
    -152
      pamac-tray.py
  34. +0
    -229
      pamac-updater.py
  35. +0
    -551
      pamac.pot
  36. +0
    -0
      pamac/__init__.py
  37. +0
    -221
      pamac/aur.py
  38. +0
    -74
      pamac/common.py
  39. +0
    -376
      pamac/config.py
  40. +0
    -864
      pamac/transaction.py
  41. +12
    -0
      po/Makefile
  42. +538
    -394
      po/ar.po
  43. +538
    -393
      po/ast.po
  44. +539
    -394
      po/bg.po
  45. +0
    -553
      po/bn.po
  46. +0
    -553
      po/ca-ES.po
  47. +541
    -394
      po/ca.po
  48. +0
    -0
      po/create_pot_file.sh
  49. +542
    -394
      po/cs.po
  50. +541
    -394
      po/da.po
  51. +541
    -394
      po/de.po
  52. +536
    -393
      po/el.po
  53. +531
    -393
      po/en_GB.po
  54. +469
    -376
      po/eo.po
  55. +538
    -392
      po/es.po
  56. +504
    -395
      po/et.po
  57. +0
    -554
      po/eu.po
  58. +516
    -397
      po/fa-IR.po
  59. +501
    -394
      po/fa.po
  60. +535
    -392
      po/fi.po
  61. +26
    -0
      po/files_to_translate
  62. +334
    -293
      po/fo.po
  63. +528
    -396
      po/fr.po
  64. +537
    -394
      po/he.po
  65. +531
    -393
      po/hi.po
  66. +460
    -376
      po/hr.po
  67. +533
    -393
      po/hu.po
  68. +540
    -394
      po/id.po
  69. +541
    -394
      po/it.po
  70. +541
    -394
      po/ja.po
  71. +0
    -553
      po/ka.po
  72. +343
    -301
      po/ko.po
  73. +526
    -394
      po/ms.po
  74. +538
    -394
      po/nb.po
  75. +536
    -394
      po/nl.po
  76. +590
    -0
      po/pamac.pot
  77. +544
    -395
      po/pl.po
  78. +4
    -2
      po/pot_head
  79. +541
    -394
      po/pt_BR.po
  80. +536
    -393
      po/pt_PT.po
  81. +540
    -395
      po/ro.po
  82. +539
    -395
      po/ru.po
  83. +365
    -317
      po/si.po
  84. +537
    -392
      po/sk.po
  85. +537
    -394
      po/sl.po
  86. +326
    -286
      po/sr.po
  87. +539
    -395
      po/sr@latin.po
  88. +535
    -392
      po/sv.po
  89. +533
    -394
      po/tr.po
  90. +530
    -392
      po/uk.po
  91. +5
    -0
      po/update_po_files.sh
  92. +323
    -285
      po/ur-PK.po
  93. +525
    -393
      po/uz.po
  94. +530
    -393
      po/vi.po
  95. +534
    -392
      po/zh-CN.po
  96. +322
    -285
      po/zh.po
  97. +531
    -392
      po/zh_TW.po
  98. +45
    -0
      resources/Makefile
  99. +109
    -0
      resources/choose_dep_dialog.ui
  100. +79
    -0
      resources/choose_provider_dialog.ui

+ 11
- 3
.gitignore View File

@@ -1,3 +1,11 @@
__pycache__
refresh-sources.sh
*~
pkgbuild
resources/*.c
src/pamac-daemon
src/pamac-tray
src/pamac-manager
src/pamac-install
src/pamac-updater
data/polkit/org.manjaro.pamac.policy
po/*.mo
po/*~
po/locale

+ 2
- 2
.tx/config View File

@@ -1,8 +1,8 @@
[main]
host = https://www.transifex.com
lang_map = af_ZA: af-ZA, am_ET: am-ET, ar_AE: ar-AE, ar_BH: ar-BH, ar_DZ: ar-DZ, ar_EG: ar-EG, ar_IQ: ar-IQ, ar_JO: ar-JO, ar_KW: ar-KW, ar_LB: ar-LB, ar_LY: ar-LY, ar_MA: ar-MA, ar_OM: ar-OM, ar_QA: ar-QA, ar_SA: ar-SA, ar_SY: ar-SY, ar_TN: ar-TN, ar_YE: ar-YE, arn_CL: arn-CL, as_IN: as-IN, az_AZ: az-AZ, ba_RU: ba-RU, be_BY: be-BY, bg_BG: bg-BG, bn_BD: bn-BD, bn_IN: bn-IN, bo_CN: bo-CN, br_FR: br-FR, bs_BA: bs-BA, ca_ES: ca-ES, co_FR: co-FR, cs_CZ: cs-CZ, cy_GB: cy-GB, da_DK: da-DK, de_AT: de-AT, de_CH: de-CH, de_DE: de-DE, de_LI: de-LI, de_LU: de-LU, dsb_DE: dsb-DE, dv_MV: dv-MV, el_GR: el-GR, en_AU: en-AU, en_BZ: en-BZ, en_CA: en-CA, en_GB: en-GB, en_IE: en-IE, en_IN: en-IN, en_JM: en-JM, en_MY: en-MY, en_NZ: en-NZ, en_PH: en-PH, en_SG: en-SG, en_TT: en-TT, en_US: en-US, en_ZA: en-ZA, en_ZW: en-ZW, es_AR: es-AR, es_BO: es-BO, es_CL: es-CL, es_CO: es-CO, es_CR: es-CR, es_DO: es-DO, es_EC: es-EC, es_ES: es-ES, es_GT: es-GT, es_HN: es-HN, es_MX: es-MX, es_NI: es-NI, es_PA: es-PA, es_PE: es-PE, es_PR: es-PR, es_PY: es-PY, es_SV: es-SV, es_US: es-US, es_UY: es-UY, es_VE: es-VE, et_EE: et-EE, eu_ES: eu-ES, fa_IR: fa-IR, fi_FI: fi-FI, fil_PH: fil-PH, fo_FO: fo-FO, fr_BE: fr-BE, fr_CA: fr-CA, fr_CH: fr-CH, fr_FR: fr-FR, fr_LU: fr-LU, fr_MC: fr-MC, fy_NL: fy-NL, ga_IE: ga-IE, gd_GB: gd-GB, gl_ES: gl-ES, gsw_FR: gsw-FR, gu_IN: gu-IN, ha_NG: ha-NG, he_IL: he-IL, hi_IN: hi-IN, hr_BA: hr-BA, hr_HR: hr-HR, hsb_DE: hsb-DE, hu_HU: hu-HU, hy_AM: hy-AM, id_ID: id-ID, ig_NG: ig-NG, ii_CN: ii-CN, is_IS: is-IS, it_CH: it-CH, it_IT: it-IT, iu_CA: iu-CA, ja_JP: ja-JP, ka_GE: ka-GE, kk_KZ: kk-KZ, kl_GL: kl-GL, km_KH: km-KH, kn_IN: kn-IN, ko_KR: ko-KR, kok_IN: kok-IN, ky_KG: ky-KG, lb_LU: lb-LU, lo_LA: lo-LA, lt_LT: lt-LT, lv_LV: lv-LV, mi_NZ: mi-NZ, mk_MK: mk-MK, ml_IN: ml-IN, mn_CN: mn-CN, mn_MN: mn-MN, moh_CA: moh-CA, mr_IN: mr-IN, ms_BN: ms-BN, ms_MY: ms-MY, mt_MT: mt-MT, nb_NO: nb-NO, ne_NP: ne-NP, nl_BE: nl-BE, nl_NL: nl-NL, nn_NO: nn-NO, nso_ZA: nso-ZA, oc_FR: oc-FR, or_IN: or-IN, pa_IN: pa-IN, pl_PL: pl-PL, prs_AF: prs-AF, ps_AF: ps-AF, pt_BR: pt-BR, pt_PT: pt-PT, qut_GT: qut-GT, quz_BO: quz-BO, quz_EC: quz-EC, quz_PE: quz-PE, rm_CH: rm-CH, ro_RO: ro-RO, ru_RU: ru-RU, rw_RW: rw-RW, sa_IN: sa-IN, sah_RU: sah-RU, se_FI: se-FI, se_NO: se-NO, se_SE: se-SE, si_LK: si-LK, sk_SK: sk-SK, sl_SI: sl-SI, sma_NO: sma-NO, sma_SE: sma-SE, smj_NO: smj-NO, smj_SE: smj-SE, smn_FI: smn-FI, sms_FI: sms-FI, sq_AL: sq-AL, sr_BA: sr-BA, sr_CS: sr-CS, sr_ME: sr-ME, sr_RS: sr-RS, sv_FI: sv-FI, sv_SE: sv-SE, sw_KE: sw-KE, syr_SY: syr-SY, ta_IN: ta-IN, te_IN: te-IN, tg_TJ: tg-TJ, th_TH: th-TH, tk_TM: tk-TM, tn_ZA: tn-ZA, tr_TR: tr-TR, tt_RU: tt-RU, tzm_DZ: tzm-DZ, ug_CN: ug-CN, uk_UA: uk-UA, ur_PK: ur-PK, uz_UZ: uz-UZ, vi_VN: vi-VN, wo_SN: wo-SN, xh_ZA: xh-ZA, yo_NG: yo-NG, zh_CN: zh-CN, zh_HK: zh-HK, zh_MO: zh-MO, zh_SG: zh-SG, zh_TW: zh-TW, zu_ZA: zu-ZA

[manjaro-pamac.pamacpot]
file_filter = po/<lang>.po
source_file = po/pamac.pot
source_lang = en
type = PO

+ 49
- 0
Makefile View File

@@ -0,0 +1,49 @@

all:
cd resources; make resources
cd src; make binaries
cd po; make gettext

clean:
rm -f src/*.c src/pamac-daemon src/pamac-tray src/pamac-updater src/pamac-manager src/pamac-install
rm -r resources/*.c
rm -rf po/locale
rm -f po/*.mo
rm -f data/polkit/org.manjaro.pamac.policy

install:
mkdir -p /usr/share/icons/hicolor
cp -r data/icons/* /usr/share/icons/hicolor
cp -r po/locale /usr/share
install -Dm744 src/pamac-daemon /usr/bin/pamac-daemon
install -Dm755 src/pamac-tray /usr/bin/pamac-tray
install -Dm755 src/pamac-manager /usr/bin/pamac-manager
install -Dm755 src/pamac-updater /usr/bin/pamac-updater
install -Dm755 src/pamac-install /usr/bin/pamac-install
#install -Dm755 src/pamac-refresh /usr/bin/pamac-refresh
install -Dm755 src/pamac-install /usr/bin/pamac-install
install -Dm644 data/applications/pamac-tray.desktop /etc/xdg/autostart/pamac-tray.desktop
install -Dm644 data/applications/pamac-manager.desktop /usr/share/applications/pamac-manager.desktop
install -Dm644 data/applications/pamac-updater.desktop /usr/share/applications/pamac-updater.desktop
install -Dm644 data/applications/pamac-install.desktop /usr/share/applications/pamac-install.desktop
install -Dm644 data/config/pamac.conf /etc/pamac.conf
install -Dm644 data/dbus/org.manjaro.pamac.conf /etc/dbus-1/system.d/org.manjaro.pamac.conf
install -Dm644 data/dbus/org.manjaro.pamac.service /usr/share/dbus-1/system-services/org.manjaro.pamac.service
install -Dm644 data/systemd/pamac.service /usr/lib/systemd/system/pamac.service
#install -Dm744 data/networkmanager/99_update_pamac_tray /etc/NetworkManager/dispatcher.d/99_update_pamac_tray
install -Dm644 data/polkit/org.manjaro.pamac.policy /usr/share/polkit-1/actions/org.manjaro.pamac.policy

uninstall:
rm -f /usr/share/icons/16x16/apps/system-software-install.png
rm -f /usr/share/icons/24x24/status/pamac-tray-no-update.png
rm -f /usr/share/icons/24x24/status/pamac-tray-update.png
rm -f /usr/share/icons/32x32/apps/system-software-install.png
rm -f /usr/share/locale/*/LC_MESSAGES/pamac.mo
rm -f /usr/bin/pamac-daemon /usr/bin/pamac-updater /usr/bin/pamac-tray /usr/bin/pamac-manager /usr/bin/pamac-install
rm -f /etc/xdg/autostart/pamac-tray.desktop
rm -f /usr/share/applications/pamac-manager.desktop /usr/share/applications/pamac-updater.desktop /usr/share/applications/pamac-install.desktop
rm -f /etc/pamac.conf
rm -f /etc/dbus-1/system.d/org.manjaro.pamac.conf
rm -f /usr/share/dbus-1/system-services/org.manjaro.pamac.service
rm -f /usr/lib/systemd/system/pamac.service
rm -f /usr/share/polkit-1/actions/org.manjaro.pamac.policy

+ 11
- 0
README View File

@@ -1 +1,12 @@
A DBus daemon and Gtk3 frontend for libalpm written in Vala

Features:
- Alpm bindings for Vala
- a DBus daemon to perform every tasks with root access using polkit to check authorizations
- a Gtk3 Package Manager
- a Gtk3 Updates Manager
- a Tray icon with configurable periodic refresh and updates notifications
- a complete AUR support:
* multiple words search capability
* Enable/Disable check updates from AUR
* Build and update your AUR packages in a integrated terminal using yaourt

+ 1
- 1
data/applications/pamac-install.desktop View File

@@ -128,4 +128,4 @@ Type=Application
Icon=system-software-install
StartupNotify=true
NoDisplay=true
MimeType=application/x-xz-compressed-tar;
MimeType=application/x-alpm-package;

BIN
data/icons/16x16/actions/package-available-locked.png View File

Before After
Width: 16  |  Height: 16  |  Size: 411B

BIN
data/icons/16x16/actions/package-broken.png View File

Before After
Width: 16  |  Height: 16  |  Size: 431B

BIN
data/icons/16x16/actions/package-downgrade.png View File

Before After
Width: 16  |  Height: 16  |  Size: 488B

BIN
data/icons/16x16/actions/package-installed-outdated.png View File

Before After
Width: 16  |  Height: 16  |  Size: 372B

BIN
data/icons/16x16/actions/package-new.png View File

Before After
Width: 16  |  Height: 16  |  Size: 598B

BIN
data/icons/16x16/actions/package-purge.png View File

Before After
Width: 16  |  Height: 16  |  Size: 619B

BIN
data/icons/16x16/actions/package-supported.png View File

Before After
Width: 16  |  Height: 16  |  Size: 745B

BIN
data/icons/16x16/actions/package-upgrade.png View File

Before After
Width: 16  |  Height: 16  |  Size: 501B

BIN
data/icons/24x24/status/pamac-add.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.2KB

BIN
data/icons/24x24/status/pamac-cleanup.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.4KB

BIN
data/icons/24x24/status/pamac-delete.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.4KB

BIN
data/icons/24x24/status/pamac-download.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.4KB

BIN
data/icons/24x24/status/pamac-refresh.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.5KB

BIN
data/icons/24x24/status/pamac-search.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.4KB

BIN
data/icons/24x24/status/pamac-setup.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.3KB

BIN
data/icons/24x24/status/pamac-update.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.5KB

BIN
data/icons/24x24/status/pamac-wait.png View File

Before After
Width: 24  |  Height: 24  |  Size: 1.2KB

+ 8
- 0
data/mime/x-alpm-package.xml View File

@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
<mime-type type="application/x-alpm-package">
<generic-icon name="package-x-generic"/>
<comment>Alpm Package</comment>
<glob pattern="*.pkg.tar.xz"/>
</mime-type>
</mime-info>

data/polkit/org.manjaro.pamac.policy → data/polkit/org.manjaro.pamac.policy.in View File

@@ -14,12 +14,4 @@
<allow_active>auth_admin_keep</allow_active>
</defaults>
</action>
<action id="org.manjaro.pamac.write_config">
<message>Authentication is required</message>
<defaults>
<allow_any>no</allow_any>
<allow_inactive>no</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
</action>
</policyconfig>

+ 278
- 0
examples/pactree.vala View File

@@ -0,0 +1,278 @@
/*
* pactree.vala - a simple dependency tree viewer translated in Vala
*
* Copyright (C) 2014 Guillaume Benoit <guillaume@manjaro.org>
* Copyright (c) 2010-2011 Pacman Development Team <pacman-dev@archlinux.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 copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

// Compile with: valac --pkg=libalpm --vapidir=../vapi --Xcc=-I../util ../util/alpm-util.c pactree.vala -o pactree

using Alpm;

/* output */
string provides;
string unresolvable;
string branch_tip1;
string branch_tip2;
int indent_size;

/* color */
string branch1_color;
string branch2_color;
string leaf1_color;
string leaf2_color;
string color_off;

/* globals */
Handle handle;
unowned DB localdb;
Alpm.List<string?> walked = null;
Alpm.List<string?> provisions = null;

/* options */
bool color;
bool graphviz;
bool linear;
int max_depth;
bool reverse;
bool unique;
string dbpath;

const OptionEntry[] options = {
{ "dbpath", 'b', 0, OptionArg.STRING, ref dbpath, "set an alternate database location", "path" },
{ "color", 'c', 0, OptionArg.NONE, ref color, "colorize output", null },
{ "depth", 'd', 0, OptionArg.INT, ref max_depth, "limit the depth of recursion", "number" },
{ "graph", 'g', 0, OptionArg.NONE, ref graphviz, "generate output for graphviz", null },
{ "linear", 'l', 0, OptionArg.NONE, ref linear, "enable linear output", null },
{ "reverse", 'r', 0, OptionArg.NONE, ref reverse, "show reverse dependencies", null },
{ "unique", 'u', 0, OptionArg.NONE, ref unique, "show dependencies with no duplicates (implies -l)", null },
{ null }
};

static void init_options() {
/* initialize options */
color = false;
graphviz = false;
linear = false;
max_depth = -1;
reverse = false;
unique = false;
dbpath = "/var/lib/pacman";

/* output */
provides = " provides";
unresolvable = " [unresolvable]";
branch_tip1 = "|--";
branch_tip2 = "+--";
indent_size = 3;

/* color */
branch1_color = "\033[0;33m"; /* yellow */
branch2_color = "\033[0;37m"; /* white */
leaf1_color = "\033[1;32m"; /* bold green */
leaf2_color = "\033[0;32m"; /* green */
color_off = "\033[0m";
}

static int parse_options(ref unowned string[] args) {
var opts = new OptionContext("");
opts.set_help_enabled(true);
opts.add_main_entries(options, null);

try {
bool b = opts.parse(ref args);
if (!b) {
stderr.puts(opts.get_help(false, null));
return 1;
}
}
catch (OptionError e)
{
stderr.puts("Unable to parse options : " + e.message + "\n");
return 1;
}
/* there must be (at least) one argument left */
if (args.length == 1) return 1;
/* unique implies linear */
if (unique) linear = true;

/* no color */
if (!color) {
branch1_color = branch2_color = "";
leaf1_color = leaf2_color = "";
color_off = "";
}

/* linear */
if (linear) {
provides = "";
branch_tip1 = branch_tip2 = "";
indent_size = 0;
}
return 0;
}

static void local_init() {
Alpm.Errno error;
handle = new Handle ("/", dbpath, out error);
assert (error == 0);
localdb = handle.localdb;
assert (localdb != null);
}

static int main (string[] args) {
init_options();
int ret = parse_options(ref args);
if (ret != 0) return ret;

local_init();
string? target_name = args[1];

unowned Package? pkg = find_satisfier(localdb.pkgcache, target_name);
if (pkg == null) {
stderr.printf("Error: package '%s' not found\n", target_name);
return 1;
}

/* begin writing */
print_start(pkg.name, target_name);
if(reverse)
walk_reverse_deps(pkg, 1);
else
walk_deps(pkg, 1);

print_end();
return 0;
}

static void print_text(string? pkg, string? provision, int depth)
{
int indent_sz = (depth + 1) * indent_size;

if ((pkg == null) && (provision == null)) return;

if (pkg == null) {
/* we failed to resolve provision */
stdout.printf("%s%*s%s%s%s%s%s\n", branch1_color, indent_sz, branch_tip1,
leaf1_color, provision, branch1_color, unresolvable, color_off);
} else if ((provision != null) && (provision != pkg)) {
/* pkg provides provision */
stdout.printf("%s%*s%s%s%s%s %s%s%s\n", branch2_color, indent_sz, branch_tip2,
leaf1_color, pkg, leaf2_color, provides, leaf1_color, provision,
color_off);
} else {
/* pkg is a normal package */
stdout.printf("%s%*s%s%s%s\n", branch1_color, indent_sz, branch_tip1, leaf1_color,
pkg, color_off);
}
}

/**
* walk dependencies in reverse, showing packages which require the target
*/
static void walk_reverse_deps(Package pkg, int depth) {
if((max_depth >= 0) && (depth > max_depth)) return;

walked.add(pkg.name);
unowned Alpm.List<string?> required_by = pkg.compute_requiredby ();

foreach(string? i in required_by) {
string pkgname = i;
if (walked.find_str(pkgname) != null) {
/* if we've already seen this package, don't print in "unique" output
* and don't recurse */
if (!unique) print(pkg.name, pkgname, null, depth);
} else {
print(pkg.name, pkgname, null, depth);
walk_reverse_deps(localdb.get_pkg(pkgname), depth + 1);
}
}
}

/**
* walk dependencies, showing dependencies of the target
*/
static void walk_deps(Package pkg, int depth)
{
if((max_depth >= 0) && (depth > max_depth)) return;

walked.add(pkg.name);

foreach (unowned Depend depend in pkg.depends) {
string depname = depend.name;
unowned Package? provider = find_satisfier (localdb.pkgcache, depname);

if (provider != null) {
string provname = provider.name;

if (walked.find_str (provname) != null) {
/* if we've already seen this package, don't print in "unique" output
* and don't recurse */
if (!unique) {
print (pkg.name, provname, depname, depth);
}
} else {
print (pkg.name, provname, depname, depth);
walk_deps(provider, depth + 1);
}
} else {
/* unresolvable package */
print(pkg.name, null, depname, depth);
}
}
}

static void print_graph(string parentname, string? pkgname, string? depname)
{
if(depname != null) {
stdout.printf("\"%s\" -> \"%s\" [color=chocolate4];\n", parentname, depname);
if((pkgname != null) && (depname != pkgname) && (provisions.find_str(depname) != null)) {
stdout.printf("\"%s\" -> \"%s\" [arrowhead=none, color=grey];\n", depname, pkgname);
provisions.add(depname);
}
} else if(pkgname != null) {
stdout.printf("\"%s\" -> \"%s\" [color=chocolate4];\n", parentname, pkgname);
}
}

/* parent depends on dep which is satisfied by pkg */
static void print(string? parentname, string? pkgname, string? depname, int depth)
{
if(graphviz) {
print_graph(parentname, pkgname, depname);
} else {
print_text(pkgname, depname, depth);
}
}

static void print_start(string pkgname, string provname)
{
if(graphviz) {
stdout.printf("digraph G { START [color=red, style=filled];\n" +
"node [style=filled, color=green];\n" +
" \"START\" -> \"%s\";\n", pkgname);
} else {
print_text(pkgname, provname, 0);
}
}

static void print_end()
{
if(graphviz) {
/* close graph output */
stdout.printf("}\n");
}
}

+ 0
- 10
files_to_translate View File

@@ -1,10 +0,0 @@
./pamac-daemon.py
./pamac-manager.py
./pamac-updater.py
./pamac-tray.py
./pamac-install.py
./pamac/transaction.py
./pamac/common.py
./gui/manager.ui
./gui/updater.ui
./gui/dialogs.ui

+ 0
- 721
gui/dialogs.ui View File

@@ -1,721 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.6"/>
<object class="GtkMessageDialog" id="ErrorDialog">
<property name="can_focus">False</property>
<property name="resizable">False</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="icon_name">system-software-install</property>
<property name="type_hint">dialog</property>
<property name="urgency_hint">True</property>
<property name="has_resize_grip">False</property>
<property name="message_type">error</property>
<property name="buttons">ok</property>
<child internal-child="vbox">
<object class="GtkBox" id="messagedialog-vbox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="messagedialog-action_area">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
<object class="GtkMessageDialog" id="InfoDialog">
<property name="can_focus">False</property>
<property name="resizable">False</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="icon_name">system-software-install</property>
<property name="type_hint">dialog</property>
<property name="urgency_hint">True</property>
<property name="has_resize_grip">False</property>
<property name="buttons">ok</property>
<child internal-child="vbox">
<object class="GtkBox" id="messagedialog-vbox9">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="messagedialog-action_area9">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkWindow" id="ProgressWindow">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Progress</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="default_width">450</property>
<property name="icon_name">system-software-install</property>
<property name="type_hint">dialog</property>
<property name="deletable">False</property>
<child>
<object class="GtkBox" id="box8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkBox" id="box9">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
<object class="GtkImage" id="action_icon">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="progresslabel2">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkProgressBar" id="progressbar2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pulse_step">0.050000000000000003</property>
<property name="show_text">True</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkExpander" id="progress_expander">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="resize_toplevel">True</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow11">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="window_placement">bottom-left</property>
<property name="shadow_type">in</property>
<property name="min_content_width">400</property>
<property name="min_content_height">200</property>
<child>
<object class="GtkTextView" id="progress_textview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
<property name="wrap_mode">word</property>
<property name="cursor_visible">False</property>
<signal name="size-allocate" handler="on_progress_textview_size_allocate" swapped="no"/>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">details</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="buttonbox3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="ProgressCancelButton">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_ProgressCancelButton_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ProgressCloseButton">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_ProgressCloseButton_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkMessageDialog" id="QuestionDialog">
<property name="can_focus">False</property>
<property name="resizable">False</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="icon_name">system-software-install</property>
<property name="type_hint">dialog</property>
<property name="urgency_hint">True</property>
<property name="has_resize_grip">False</property>
<property name="message_type">question</property>
<property name="buttons">yes-no</property>
<child internal-child="vbox">
<object class="GtkBox" id="messagedialog-vbox8">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="messagedialog-action_area8">
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
<object class="GtkMessageDialog" id="WarningDialog">
<property name="can_focus">False</property>
<property name="resizable">False</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="type_hint">dialog</property>
<property name="urgency_hint">True</property>
<property name="has_resize_grip">False</property>
<property name="message_type">warning</property>
<property name="buttons">ok</property>
<child internal-child="vbox">
<object class="GtkBox" id="messagedialog-vbox7">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="messagedialog-action_area7">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
<object class="GtkAdjustment" id="adjustment1">
<property name="lower">1</property>
<property name="upper">10000</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkWindow" id="PreferencesWindow">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Pamac Preferences</property>
<property name="window_position">center</property>
<property name="default_width">300</property>
<property name="default_height">250</property>
<property name="icon_name">system-software-install</property>
<signal name="delete-event" handler="on_PreferencesWindow_delete_event" swapped="no"/>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkNotebook" id="notebook1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkCheckButton" id="EnableAURButton">
<property name="label" translatable="yes">Enable AUR support</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Allow Pamac to search and install packages from AUR</property>
<property name="focus_on_click">False</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="RemoveUnrequiredDepsButton">
<property name="label" translatable="yes">Remove unrequired dependencies</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">When removing a package, also remove those dependencies that are not required by other packages</property>
<property name="focus_on_click">False</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel" id="RefreshPeriodLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">3</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="RefreshPeriodSpinButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">How often to check for updates, value in hours</property>
<property name="margin_right">3</property>
<property name="caps_lock_warning">False</property>
<property name="input_purpose">number</property>
<property name="adjustment">adjustment1</property>
<property name="numeric">True</property>
<property name="update_policy">if-valid</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<child type="tab">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Options</property>
</object>
<packing>
<property name="tab_fill">False</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="buttonbox2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">5</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="PreferencesValidButton">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_PreferencesValidButton_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="PreferencesCloseButton">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_PreferencesCloseButton_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkListStore" id="choose_list">
<columns>
<!-- column-name gboolean1 -->
<column type="gboolean"/>
<!-- column-name gchararray1 -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkDialog" id="ChooseDialog">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Choose</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="icon_name">system-software-install</property>
<property name="type_hint">dialog</property>
<property name="deletable">False</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area1">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="ChooseButton">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_ChooseButton_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="choose_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow5">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="min_content_width">300</property>
<property name="min_content_height">250</property>
<child>
<object class="GtkTreeView" id="treeview5">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">choose_list</property>
<property name="headers_visible">False</property>
<property name="headers_clickable">False</property>
<property name="enable_search">False</property>
<property name="show_expanders">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection5">
<property name="mode">none</property>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="treeviewcolumn1">
<property name="sizing">autosize</property>
<child>
<object class="GtkCellRendererToggle" id="choose_renderertoggle">
<signal name="toggled" handler="on_choose_renderertoggle_toggled" swapped="no"/>
</object>
<attributes>
<attribute name="active">0</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererText" id="choose_renderertext"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="0">ChooseButton</action-widget>
</action-widgets>
</object>
<object class="GtkListStore" id="transaction_sum">
<columns>
<!-- column-name action -->
<column type="gchararray"/>
<!-- column-name packages -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkWindow" id="ConfDialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Summary</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="icon_name">system-software-install</property>
<property name="type_hint">dialog</property>
<property name="deletable">False</property>
<child>
<object class="GtkBox" id="box7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel" id="sum_top_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="shadow_type">in</property>
<property name="min_content_width">330</property>
<property name="min_content_height">250</property>
<child>
<object class="GtkTreeView" id="treeview4">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="model">transaction_sum</property>
<property name="headers_visible">False</property>
<property name="headers_clickable">False</property>
<property name="enable_search">False</property>
<property name="show_expanders">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection">
<property name="mode">none</property>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="_action">
<property name="sizing">autosize</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext5">
<property name="yalign">0</property>
<property name="weight">600</property>
</object>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="_packages">
<property name="sizing">autosize</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext6"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="sum_bottom_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="buttonbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">7</property>
<property name="homogeneous">True</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="TransCancelButton">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="is_focus">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_TransCancelButton_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="TransValidButton">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_TransValidButton_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

+ 0
- 40
pamac-check_updates.py View File

@@ -1,40 +0,0 @@
#! /usr/bin/python3
# -*- coding:utf-8 -*-

# pamac - A Python implementation of alpm
# Copyright (C) 2013 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 copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

from gi.repository import GObject
from pamac import common, transaction
import dbus

def handle_updates(updates):
transaction.StopDaemon()
loop.quit()

loop = GObject.MainLoop()

if not common.pid_file_exists():
bus = dbus.SystemBus()
bus.add_signal_receiver(handle_updates, dbus_interface = "org.manjaro.pamac", signal_name = "EmitAvailableUpdates")
transaction.get_dbus_methods()
try:
transaction.CheckUpdates()
except:
pass
else:
loop.run()

+ 0
- 833
pamac-daemon.py View File

@@ -1,833 +0,0 @@
#! /usr/bin/python3
# -*- coding:utf-8 -*-

# pamac - A Python implementation of alpm
# Copyright (C) 2013-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 copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

import dbus
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GObject
import re

import pyalpm
from multiprocessing import Process
from pamac import config, common, aur

# i18n
import locale
locale.setlocale(locale.LC_ALL, '')
import gettext
gettext.bindtextdomain('pamac', '/usr/share/locale')
gettext.textdomain('pamac')
_ = gettext.gettext

def format_error(data):
errstr = data[0].strip('\n')
errno = data[1]
detail = data[2]
if detail:
# detail is a list of '\n' terminated strings
return '{}:\n'.format(errstr) + ''.join(i for i in detail)
else:
return errstr

class PamacDBusService(dbus.service.Object):
def __init__(self):
bus = dbus.SystemBus()
bus_name = dbus.service.BusName('org.manjaro.pamac', bus)
dbus.service.Object.__init__(self, bus_name, '/org/manjaro/pamac')
self.t = None
self.task = None
self.error = ''
self.warning = ''
self.providers = []
self.previous_action = ''
self.previous_action_long = ''
self.previous_icon = ''
self.previous_target = ''
self.previous_percent = 0
self.total_size = 0
self.already_transferred = 0
self.local_packages = set()
self.aur_updates_checked = False
self.aur_updates_pkgs = []
self.localdb = None
self.syncdbs = None
self.get_handle()

def get_handle(self):
self.handle = config.handle()
self.localdb = self.handle.get_localdb()
self.syncdbs = self.handle.get_syncdbs()
self.handle.dlcb = self.cb_dl
self.handle.totaldlcb = self.totaldlcb
self.handle.eventcb = self.cb_event
self.handle.questioncb = self.cb_question
self.handle.progresscb = self.cb_progress
self.handle.logcb = self.cb_log

def get_local_packages(self):
self.local_packages = set()
sync_pkg = None
for pkg in self.localdb.pkgcache:
for db in self.syncdbs:
sync_pkg = db.get_pkg(pkg.name)
if sync_pkg:
break
if not sync_pkg:
self.local_packages.add(pkg.name)

def check_finished_commit(self):
if self.task.is_alive():
return True
else:
self.get_handle()
return False

@dbus.service.signal('org.manjaro.pamac')
def EmitAction(self, action):
pass

@dbus.service.signal('org.manjaro.pamac')
def EmitActionLong(self, action):
pass

@dbus.service.signal('org.manjaro.pamac')
def EmitNeedDetails(self, need):
pass

@dbus.service.signal('org.manjaro.pamac')
def EmitIcon(self, icon):
pass

@dbus.service.signal('org.manjaro.pamac')
def EmitTarget(self, target):
pass

@dbus.service.signal('org.manjaro.pamac')
def EmitPercent(self, percent):
pass

@dbus.service.signal('org.manjaro.pamac')
def EmitLogError(self, message):
pass

@dbus.service.signal('org.manjaro.pamac')
def EmitLogWarning(self, message):
pass

@dbus.service.signal('org.manjaro.pamac', signature = '(ba(ssssu))')
def EmitAvailableUpdates(self, updates):
pass

@dbus.service.signal('org.manjaro.pamac')
def EmitTransactionStart(self, message):
pass

@dbus.service.signal('org.manjaro.pamac')
def EmitTransactionDone(self, message):
pass

@dbus.service.signal('org.manjaro.pamac')
def EmitTransactionError(self, message):
pass

@dbus.service.signal('org.manjaro.pamac')
def EmitReloadConfig(self, message):
# recheck aur updates next time
self.aur_updates_checked = False
# reload config
config.pamac_conf.reload()

def cb_event(self, event, tupel):
action = self.previous_action
action_long = self.previous_action_long
icon = self.previous_icon
if event == 'ALPM_EVENT_CHECKDEPS_START':
action = _('Checking dependencies')+'...'
action_long = action+'\n'
icon = 'pamac-search'
elif event == 'ALPM_EVENT_CHECKDEPS_DONE':
if self.warning:
self.EmitLogWarning(self.warning)
self.warning = ''
elif event == 'ALPM_EVENT_FILECONFLICTS_START':
action = _('Checking file conflicts')+'...'
action_long = action+'\n'
icon = 'pamac-search'
elif event == 'ALPM_EVENT_FILECONFLICTS_DONE':
pass
elif event == 'ALPM_EVENT_RESOLVEDEPS_START':
action = _('Resolving dependencies')+'...'
action_long = action+'\n'
icon = 'pamac-setup'
elif event == 'ALPM_EVENT_RESOLVEDEPS_DONE':
if self.warning:
self.EmitLogWarning(self.warning)
self.warning = ''
elif event == 'ALPM_EVENT_INTERCONFLICTS_START':
action = _('Checking inter conflicts')+'...'
action_long = action+'\n'
icon = 'pamac-search'
elif event == 'ALPM_EVENT_INTERCONFLICTS_DONE':
if self.warning:
self.EmitLogWarning(self.warning)
self.warning = ''
elif event == 'ALPM_EVENT_ADD_START':
string = _('Installing {pkgname}').format(pkgname = tupel[0].name)
action = string+'...'
action_long = '{} ({})...\n'.format(string, tupel[0].version)
icon = 'pamac-add'
elif event == 'ALPM_EVENT_ADD_DONE':
formatted_event = 'Installed {pkgname} ({pkgversion})'.format(pkgname = tupel[0].name, pkgversion = tupel[0].version)
common.write_log_file(formatted_event)
elif event == 'ALPM_EVENT_REMOVE_START':
string = _('Removing {pkgname}').format(pkgname = tupel[0].name)
action = string+'...'
action_long = '{} ({})...\n'.format(string, tupel[0].version)
icon = 'pamac-delete'
elif event == 'ALPM_EVENT_REMOVE_DONE':
formatted_event = 'Removed {pkgname} ({pkgversion})'.format(pkgname = tupel[0].name, pkgversion = tupel[0].version)
common.write_log_file(formatted_event)
elif event == 'ALPM_EVENT_UPGRADE_START':
string = _('Upgrading {pkgname}').format(pkgname = tupel[1].name)
action = string+'...'
action_long = '{} ({} => {})...\n'.format(string, tupel[1].version, tupel[0].version)
icon = 'pamac-update'
elif event == 'ALPM_EVENT_UPGRADE_DONE':
formatted_event = 'Upgraded {pkgname} ({oldversion} -> {newversion})'.format(pkgname = tupel[1].name, oldversion = tupel[1].version, newversion = tupel[0].version)
common.write_log_file(formatted_event)
elif event == 'ALPM_EVENT_DOWNGRADE_START':
string = _('Downgrading {pkgname}').format(pkgname = tupel[1].name)
action = string+'...'
action_long = '{} ({} => {})...\n'.format(string, tupel[1].version, tupel[0].version)
icon = 'pamac-add'
elif event == 'ALPM_EVENT_DOWNGRADE_DONE':
formatted_event = 'Downgraded {pkgname} ({oldversion} -> {newversion})'.format(pkgname = tupel[1].name, oldversion = tupel[1].version, newversion = tupel[0].version)
common.write_log_file(formatted_event)
elif event == 'ALPM_EVENT_REINSTALL_START':
string = _('Reinstalling {pkgname}').format(pkgname = tupel[0].name)
action = string+'...'
action_long = '{} ({})...\n'.format(string, tupel[0].version)
icon = 'pamac-add'
elif event == 'ALPM_EVENT_REINSTALL_DONE':
formatted_event = 'Reinstalled {pkgname} ({pkgversion})'.format(pkgname = tupel[0].name, pkgversion = tupel[0].version)
common.write_log_file(formatted_event)
elif event == 'ALPM_EVENT_INTEGRITY_START':
action = _('Checking integrity')+'...'
action_long = action+'\n'
icon = 'pamac-search'
self.already_transferred = 0
elif event == 'ALPM_EVENT_INTEGRITY_DONE':
pass
elif event == 'ALPM_EVENT_LOAD_START':
action = _('Loading packages files')+'...'
action_long = action+'\n'
icon = 'pamac-search'
elif event == 'ALPM_EVENT_LOAD_DONE':
pass
elif event == 'ALPM_EVENT_DELTA_INTEGRITY_START':
action = _('Checking delta integrity')+'...'
action_long = action+'\n'
icon = 'pamac-search'
elif event == 'ALPM_EVENT_DELTA_INTEGRITY_DONE':
pass
elif event == 'ALPM_EVENT_DELTA_PATCHES_START':
action = _('Applying deltas')+'...'
action_long = action+'\n'
icon = 'pamac-setup'
elif event == 'ALPM_EVENT_DELTA_PATCHES_DONE':
pass
elif event == 'ALPM_EVENT_DELTA_PATCH_START':
action = _('Generating {} with {}').format(tupel[0], tupel[1])+'...'
action_long = action+'\n'
icon = 'pamac-setup'
elif event == 'ALPM_EVENT_DELTA_PATCH_DONE':
action = _('Generation succeeded!')
action_long = action+'\n'
elif event == 'ALPM_EVENT_DELTA_PATCH_FAILED':
action = _('Generation failed.')
action_long = action+'\n'
elif event == 'ALPM_EVENT_SCRIPTLET_INFO':
action =_('Configuring {pkgname}').format(pkgname = self.previous_target)+'...'
action_long = tupel[0]
icon = 'pamac-setup'
self.EmitNeedDetails(True)
elif event == 'ALPM_EVENT_RETRIEVE_START':
action = _('Downloading')+'...'
action_long = action+'\n'
icon = 'pamac-download'
elif event == 'ALPM_EVENT_DISKSPACE_START':
action = _('Checking available disk space')+'...'
action_long = action+'\n'
icon = 'pamac-search'
elif event == 'ALPM_EVENT_OPTDEP_REQUIRED':
print('Optionnal deps exist')
elif event == 'ALPM_EVENT_DATABASE_MISSING':
#action =_('Database file for {} does not exist').format(tupel[0])+'...'
#action_long = action
pass
elif event == 'ALPM_EVENT_KEYRING_START':
action = _('Checking keyring')+'...'
action_long = action+'\n'
icon = 'pamac-search'
elif event == 'ALPM_EVENT_KEYRING_DONE':
pass
elif event == 'ALPM_EVENT_KEY_DOWNLOAD_START':
action = _('Downloading required keys')+'...'
action_long = action+'\n'
elif event == 'ALPM_EVENT_KEY_DOWNLOAD_DONE':
pass
if action != self.previous_action:
self.previous_action = action
self.EmitAction(action)
if action_long != self.previous_action_long:
self.previous_action_long != action_long
self.EmitActionLong(action_long)
if icon != self.previous_icon:
self.previous_icon = icon
self.EmitIcon(icon)
print(event)

def cb_question(self, event, data_tupel, extra_data):
if event == 'ALPM_QUESTION_INSTALL_IGNOREPKG':
return 0 # Do not install package in IgnorePkg/IgnoreGroup
if event == 'ALPM_QUESTION_REPLACE_PKG':
self.warning += _('{pkgname1} will be replaced by {pkgname2}').format(pkgname1 = data_tupel[0].name, pkgname2 = data_tupel[1].name)+'\n'
return 1 # Auto-remove conflicts in case of replaces
if event == 'ALPM_QUESTION_CONFLICT_PKG':
self.warning += _('{pkgname1} conflicts with {pkgname2}').format(pkgname1 = data_tupel[0], pkgname2 = data_tupel[1])+'\n'
return 1 # Auto-remove conflicts
if event == 'ALPM_QUESTION_CORRUPTED_PKG':
return 1 # Auto-remove corrupted pkgs in cache
if event == 'ALPM_QUESTION_REMOVE_PKGS':
return 1 # Do not upgrade packages which have unresolvable dependencies
if event == 'ALPM_QUESTION_SELECT_PROVIDER':
## In this case we populate providers with different choices
## the client will have to release transaction and re-init one
## with the chosen package added to it
self.providers.append(([pkg.name for pkg in data_tupel[0]], data_tupel[1]))
return 0 # return the first choice, this is not important because the transaction will be released
if event == 'ALPM_QUESTION_IMPORT_KEY':
## data_tupel = (revoked(int), length(int), pubkey_algo(string), fingerprint(string), uid(string), created_time(int))
if data_tupel[0] is 0: # not revoked
return 1 # Auto get not revoked key
if data_tupel[0] is 1: # revoked
return 0 # Do not get revoked key

def cb_log(self, level, line):
_logmask = pyalpm.LOG_ERROR | pyalpm.LOG_WARNING
if not (level & _logmask):
return
if level & pyalpm.LOG_ERROR:
#self.EmitLogError(line)
_error = _('Error: ')+line
self.EmitActionLong(_error)
self.EmitNeedDetails(True)
print(line)
elif level & pyalpm.LOG_WARNING:
self.warning += line
_warning = _('Warning: ')+line
self.EmitActionLong(_warning)
elif level & pyalpm.LOG_DEBUG:
line = "DEBUG: " + line
print(line)
elif level & pyalpm.LOG_FUNCTION:
line = "FUNC: " + line
print(line)

def totaldlcb(self, _total_size):
self.total_size = _total_size

def cb_dl(self, _target, _transferred, _total):
if _target.endswith('.db'):
action = _('Refreshing {repo}').format(repo = _target.replace('.db', ''))+'...'
action_long = ''
icon = 'pamac-refresh'
else:
action = _('Downloading {pkgname}').format(pkgname = _target.replace('.pkg.tar.xz', ''))+'...'
action_long = action+'\n'
icon = 'pamac-download'
if self.total_size > 0:
percent = round((_transferred+self.already_transferred)/self.total_size, 2)
if _transferred+self.already_transferred <= self.total_size:
target = '{transferred}/{size}'.format(transferred = common.format_size(_transferred+self.already_transferred), size = common.format_size(self.total_size))
else:
target = ''
else:
percent = round(_transferred/_total, 2)
target = ''
if action != self.previous_action:
self.previous_action = action
self.EmitAction(action)
if action_long != self.previous_action_long:
self.previous_action_long = action_long
self.EmitActionLong(action_long)
if icon != self.previous_icon:
self.previous_icon = icon
self.EmitIcon(icon)
if target != self.previous_target:
self.previous_target = target
self.EmitTarget(target)
if percent != self.previous_percent:
self.previous_percent = percent
self.EmitPercent(percent)
elif _transferred == _total:
self.already_transferred += _total

def cb_progress(self, event, target, _percent, n, i):
if event in ('ALPM_PROGRESS_ADD_START', 'ALPM_PROGRESS_UPGRADE_START', 'ALPM_PROGRESS_DOWNGRADE_START', 'ALPM_PROGRESS_REINSTALL_START', 'ALPM_PROGRESS_REMOVE_START'):
percent = round(((i-1)/n)+(_percent/(100*n)), 2)
else:
percent = round(_percent/100, 2)
if percent == 0:
self.EmitTransactionStart('')
if target != self.previous_target:
self.previous_target = target
if percent != self.previous_percent:
self.EmitTarget('{}/{}'.format(str(i), str(n)))
self.previous_percent = percent
self.EmitPercent(percent)

def policykit_test(self, sender, connexion, action):
bus = dbus.SystemBus()
proxy_dbus = connexion.get_object('org.freedesktop.DBus','/org/freedesktop/DBus/Bus', False)
dbus_info = dbus.Interface(proxy_dbus,'org.freedesktop.DBus')
sender_pid = dbus_info.GetConnectionUnixProcessID(sender)
proxy_policykit = bus.get_object('org.freedesktop.PolicyKit1','/org/freedesktop/PolicyKit1/Authority',False)
policykit_authority = dbus.Interface(proxy_policykit,'org.freedesktop.PolicyKit1.Authority')

Subject = ('unix-process', {'pid': dbus.UInt32(sender_pid, variant_level=1),
'start-time': dbus.UInt64(0, variant_level=1)})
# We would like an infinite timeout, but dbus-python won't allow it.
# Pass the longest timeout dbus-python will accept
(is_authorized,is_challenge,details) = policykit_authority.CheckAuthorization(Subject, action, {'': ''}, dbus.UInt32(1), '',timeout=2147483)
return is_authorized

@dbus.service.method('org.manjaro.pamac', 'si', 's', sender_keyword='sender', connection_keyword='connexion')
def SetPkgReason(self, pkgname, reason, sender=None, connexion=None):
try:
authorized = self.policykit_test(sender,connexion,'org.manjaro.pamac.commit')
except dbus.exceptions.DBusException as e:
return _('Authentication failed')
else:
if authorized:
error = ''
try:
pkg = self.localdb.get_pkg(pkgname)
if pkg:
self.handle.set_pkgreason(pkg, reason)
except Exception as e:
error = format_error(e.args)
return error
else :
return _('Authentication failed')

@dbus.service.method('org.manjaro.pamac', '', 's', async_callbacks=('success', 'nosuccess'))
def CheckUpdates(self, success, nosuccess):
success('')
syncfirst = False
updates = []
_ignorepkgs = set()
self.get_handle()
for group in self.handle.ignoregrps:
db = self.localdb
grp = db.read_grp(group)
if grp:
name, pkg_list = grp
for pkg in pkg_list:
_ignorepkgs.add(pkg.name)
for name in self.handle.ignorepkgs:
pkg = self.localdb.get_pkg(name)
if pkg:
_ignorepkgs.add(pkg.name)
if config.syncfirst:
for name in config.syncfirst:
pkg = self.localdb.get_pkg(name)
if pkg:
candidate = pyalpm.sync_newversion(pkg, self.syncdbs)
if candidate:
syncfirst = True
updates.append((candidate.name, candidate.version, candidate.db.name, '', candidate.download_size))
if not updates:
if config.enable_aur:
if not self.aur_updates_checked:
self.get_local_packages()
self.local_packages -= _ignorepkgs
for pkg in self.localdb.pkgcache:
if not pkg.name in _ignorepkgs:
candidate = pyalpm.sync_newversion(pkg, self.syncdbs)
if candidate:
updates.append((candidate.name, candidate.version, candidate.db.name, '', candidate.download_size))
self.local_packages.discard(pkg.name)
if config.enable_aur:
if not self.aur_updates_checked:
if self.local_packages:
self.aur_updates_pkgs = aur.multiinfo(self.local_packages)
self.aur_updates_checked = True
for aur_pkg in self.aur_updates_pkgs:
if self.localdb.get_pkg(aur_pkg.name):
comp = pyalpm.vercmp(aur_pkg.version, self.localdb.get_pkg(aur_pkg.name).version)
if comp == 1:
updates.append((aur_pkg.name, aur_pkg.version, aur_pkg.db.name, aur_pkg.tarpath, aur_pkg.download_size))
self.EmitAvailableUpdates((syncfirst, updates))

@dbus.service.method('org.manjaro.pamac', 'b', '')
def Refresh(self, force_update):
def refresh():
self.target = ''
self.percent = 0
error = ''
for db in self.syncdbs:
try:
self.t = self.handle.init_transaction()
db.update(force = bool(force_update))
self.t.release()
except pyalpm.error as e:
print(e)
error += format_error(e.args)
break
if error:
self.EmitTransactionError(error)
else:
self.EmitTransactionDone('')
self.task = Process(target=refresh)
self.task.start()
GObject.timeout_add(100, self.check_finished_commit)

@dbus.service.method('org.manjaro.pamac', 'a{sb}', 's')
def Init(self, options):
error = ''
try:
self.t = self.handle.init_transaction(**options)
print('Init:',self.t.flags)
except pyalpm.error as e:
error = format_error(e.args)
finally:
return error

@dbus.service.method('org.manjaro.pamac', 'b', 's')
def Sysupgrade(self, downgrade):
error = ''
try:
self.t.sysupgrade(downgrade = bool(downgrade))
except pyalpm.error as e:
error = format_error(e.args)
self.t.release()
finally:
return error

@dbus.service.method('org.manjaro.pamac', 's', 's')
def Remove(self, pkgname):
error = ''
try:
pkg = self.localdb.get_pkg(pkgname)
if pkg is not None:
self.t.remove_pkg(pkg)
except pyalpm.error as e:
error = format_error(e.args)
finally:
return error

@dbus.service.method('org.manjaro.pamac', 's', 's')
def Add(self, pkgname):
error = ''
try:
for db in self.syncdbs:
# this is a security, in case of virtual package it will
# choose the first provider, the choice should have been
# done by the client
pkg = pyalpm.find_satisfier(db.pkgcache, pkgname)
if pkg:
self.t.add_pkg(pkg)
break
except pyalpm.error as e:
error = format_error(e.args)
finally:
return error

@dbus.service.method('org.manjaro.pamac', 's', 's')
def Load(self, tarball_path):
error = ''
try:
pkg = self.handle.load_pkg(tarball_path)
if pkg:
self.t.add_pkg(pkg)
except pyalpm.error:
error = _('{pkgname} is not a valid path or package name').format(pkgname = tarball_path)
finally:
return error

def check_extra_modules(self):
to_add = set(pkg.name for pkg in self.t.to_add)
to_remove = set(pkg.name for pkg in self.t.to_remove)
to_check = [pkg for pkg in self.t.to_add]
already_checked = set(pkg.name for pkg in to_check)
depends = [to_check]
# get installed kernels and modules
pkgs = self.localdb.search('linux')
installed_kernels = set()
installed_modules = set()
for pkg in pkgs:
match = re.match("(linux[0-9]{2,3})(.*)", pkg.name)
if match:
installed_kernels.add(match.group(1))
if match.group(2):
installed_modules.add(match.group(2))
for pkg in self.t.to_add:
match = re.match("(linux[0-9]{2,3})(.*)", pkg.name)
if match:
installed_kernels.add(match.group(1))
if match.group(2):
installed_modules.add(match.group(2))
# check in to_remove if there is a kernel and if so, auto-remove the corresponding modules
for pkg in self.t.to_remove:
match = re.match("(linux[0-9]{2,3})(.*)", pkg.name)
if match:
if not match.group(2):
installed_kernels.discard(match.group(1))
for module in installed_modules:
pkgname = match.group(1)+module
if not pkgname in to_remove:
_pkg = self.localdb.get_pkg(pkgname)
if _pkg:
# Check we won't remove a third party kernel
third_party = False
for provide in _pkg.provides:
if 'linux=' in provide:
third_party = True
if not third_party:
to_remove.add(pkgname)
self.t.remove_pkg(_pkg)
# start loops to check pkgs
i = 0
while depends[i]:
# add a empty list for new pkgs to check next loop
depends.append([])
# start to check one pkg
for pkg in depends[i]:
# check if the current pkg is a kernel and if so, check if a module is required to install
match = re.match("(linux[0-9]{2,3})(.*)", pkg.name)
if match:
if not match.group(2): # match pkg is a kernel
for module in installed_modules:
pkgname = match.group(1) + module
if not self.localdb.get_pkg(pkgname):
for db in self.syncdbs:
_pkg = db.get_pkg(pkgname)
if _pkg:
if not _pkg.name in already_checked:
depends[i+1].append(_pkg)
already_checked.add(_pkg.name)
if not _pkg.name in to_add | to_remove:
to_add.add(_pkg.name)
self.t.add_pkg(_pkg)
break
# check if the current pkg is a kernel module and if so, install it for all installed kernels
match = re.match("(linux[0-9]{2,3})(.*-modules)", pkg.name)
if match:
for kernel in installed_kernels:
pkgname = kernel + match.group(2)
if not self.localdb.get_pkg(pkgname):
for db in self.syncdbs:
_pkg = db.get_pkg(pkgname)
if _pkg:
if not _pkg.name in already_checked:
depends[i+1].append(_pkg)
already_checked.add(_pkg.name)
if not _pkg.name in to_add | to_remove:
to_add.add(_pkg.name)
self.t.add_pkg(_pkg)
break
for depend in pkg.depends:
found_depend = pyalpm.find_satisfier(self.localdb.pkgcache, depend)
if not found_depend:
for db in self.syncdbs:
found_depend = pyalpm.find_satisfier(db.pkgcache, depend)
if found_depend:
break
if found_depend:
# add the dep in list to check its deps in next loop
if not found_depend.name in already_checked:
depends[i+1].append(found_depend)
already_checked.add(found_depend.name)
i += 1
# end of the loop

@dbus.service.method('org.manjaro.pamac', '', 'a(ass)')
def Prepare(self):
error = ''
self.providers.clear()
self.check_extra_modules()
try:
self.t.prepare()
except pyalpm.error as e:
error = format_error(e.args)
self.t.release()
else:
for pkg in self.t.to_remove:
if pkg.name in config.holdpkg:
error = _('The transaction cannot be performed because it needs to remove {pkgname1} which is a locked package').format(pkgname1 = pkg.name)
self.t.release()
break
finally:
try:
summ = len(self.t.to_add) + len(self.t.to_remove)
except pyalpm.error:
return [((), error)]
if summ == 0:
self.t.release()
return [((), _('Nothing to do'))]
elif error:
return [((), error)]
elif self.providers:
return self.providers
else:
return [((), '')]

@dbus.service.method('org.manjaro.pamac', '', 'a(ss)')
def To_Remove(self):
_list = []
try:
for pkg in self.t.to_remove:
_list.append((pkg.name, pkg.version))
except:
pass
return _list

@dbus.service.method('org.manjaro.pamac', '', 'a(ssi)')
def To_Add(self):
_list = []
try:
for pkg in self.t.to_add:
_list.append((pkg.name, pkg.version, pkg.download_size))
except:
pass
return _list

@dbus.service.method('org.manjaro.pamac', '', '')
def Interrupt(self):
def interrupt():
try:
self.t.interrupt()
except:
pass
try:
self.t.release()
except:
pass
finally:
common.rm_lock_file()