Merge lp:ubuntu/precise-proposed/aptdaemon into lp:ubuntu/precise/aptdaemon

Proposed by Steve Langasek on 2012-08-11
Status: Merged
Merge reported by: Steve Langasek
Merged at revision: not available
Proposed branch: lp:ubuntu/precise-proposed/aptdaemon
Merge into: lp:ubuntu/precise/aptdaemon
Diff against target: 11606 lines (+11326/-22)
25 files modified
.pc/.quilt_patches (+1/-0)
.pc/.quilt_series (+1/-0)
.pc/.version (+1/-0)
.pc/applied-patches (+5/-0)
.pc/fix-lp-900982.patch/aptdaemon/enums.py (+698/-0)
.pc/fix-lp-932581.patch/aptdaemon/pkcompat.py (+2937/-0)
.pc/fix-lp-971748.patch/aptdaemon/networking.py (+262/-0)
.pc/fix-lp-971748.patch/aptdaemon/pkcompat.py (+2940/-0)
.pc/fix-lp-981124.patch/aptdaemon/client.py (+1697/-0)
.pc/fix_gettext_return_value_type.patch/aptdaemon/core.py (+2201/-0)
.pc/fix_gettext_return_value_type.patch/aptdaemon/utils.py (+88/-0)
aptdaemon/client.py (+8/-6)
aptdaemon/core.py (+20/-8)
aptdaemon/enums.py (+1/-1)
aptdaemon/networking.py (+11/-4)
aptdaemon/pkcompat.py (+10/-2)
aptdaemon/utils.py (+7/-1)
debian/changelog (+29/-0)
debian/patches/fix-lp-900982.patch (+19/-0)
debian/patches/fix-lp-932581.patch (+20/-0)
debian/patches/fix-lp-971748.patch (+87/-0)
debian/patches/fix-lp-981124.patch (+44/-0)
debian/patches/fix_gettext_return_value_type.patch (+171/-0)
debian/patches/series (+5/-0)
tests/regressions/test_lp768691.py (+63/-0)
To merge this branch: bzr merge lp:ubuntu/precise-proposed/aptdaemon
Reviewer Review Type Date Requested Status
Colin Watson 2012-08-11 Approve on 2012-08-11
Review via email: mp+119222@code.launchpad.net

Description of the change

proposed fix for bug #1034806. test case isn't perfect; we can't easily
test the format string from the original bug because we would have to
reference gettext catalogs from two separate directories on the filesystem,
but we can at least test that get_localised_name() is giving us unicode.

To post a comment you must log in.
Colin Watson (cjwatson) wrote :

A bit less cruft in the changes to the quilt patch ('quilt refresh --no-timestamps -p ab') would be nice, and given that precise has Python 2.7 you should be able to use self.assertIsInstance(...) rather than self.assertTrue(isinstance(...)). Otherwise looks OK.

review: Approve
lp:ubuntu/precise-proposed/aptdaemon updated on 2012-08-11
100. By Steve Langasek on 2012-08-11

refresh the patch to minimize delta

101. By Steve Langasek on 2012-08-11

releasing version 0.43+bzr805-0ubuntu4

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '.pc'
2=== added file '.pc/.quilt_patches'
3--- .pc/.quilt_patches 1970-01-01 00:00:00 +0000
4+++ .pc/.quilt_patches 2012-08-11 01:29:19 +0000
5@@ -0,0 +1,1 @@
6+debian/patches
7
8=== added file '.pc/.quilt_series'
9--- .pc/.quilt_series 1970-01-01 00:00:00 +0000
10+++ .pc/.quilt_series 2012-08-11 01:29:19 +0000
11@@ -0,0 +1,1 @@
12+series
13
14=== added file '.pc/.version'
15--- .pc/.version 1970-01-01 00:00:00 +0000
16+++ .pc/.version 2012-08-11 01:29:19 +0000
17@@ -0,0 +1,1 @@
18+2
19
20=== added file '.pc/applied-patches'
21--- .pc/applied-patches 1970-01-01 00:00:00 +0000
22+++ .pc/applied-patches 2012-08-11 01:29:19 +0000
23@@ -0,0 +1,5 @@
24+fix-lp-932581.patch
25+fix-lp-971748.patch
26+fix-lp-981124.patch
27+fix-lp-900982.patch
28+fix_gettext_return_value_type.patch
29
30=== added directory '.pc/fix-lp-900982.patch'
31=== added directory '.pc/fix-lp-900982.patch/aptdaemon'
32=== added file '.pc/fix-lp-900982.patch/aptdaemon/enums.py'
33--- .pc/fix-lp-900982.patch/aptdaemon/enums.py 1970-01-01 00:00:00 +0000
34+++ .pc/fix-lp-900982.patch/aptdaemon/enums.py 2012-08-11 01:29:19 +0000
35@@ -0,0 +1,698 @@
36+#!/usr/bin/env python
37+# -*- coding: utf-8 -*-
38+"""enums - Enumerates for apt daemon dbus messages"""
39+# Copyright (C) 2008-2009 Sebastian Heinlein <devel@glatzor.de>
40+#
41+# This program is free software; you can redistribute it and/or modify
42+# it under the terms of the GNU General Public License as published by
43+# the Free Software Foundation; either version 2 of the License, or
44+# any later version.
45+#
46+# This program is distributed in the hope that it will be useful,
47+# but WITHOUT ANY WARRANTY; without even the implied warranty of
48+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49+# GNU General Public License for more details.
50+#
51+# You should have received a copy of the GNU General Public License along
52+# with this program; if not, write to the Free Software Foundation, Inc.,
53+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
54+
55+__author__ = "Sebastian Heinlein <devel@glatzor.de>"
56+
57+import gettext
58+def _(msg):
59+ return gettext.dgettext("aptdaemon", msg)
60+
61+__all__ = ("PKGS_INSTALL", "PKGS_REINSTALL", "PKGS_REMOVE", "PKGS_PURGE",
62+ "PKGS_UPGRADE", "PKGS_DOWNGRADE", "PKGS_KEEP",
63+ "EXIT_SUCCESS", "EXIT_CANCELLED", "EXIT_FAILED", "EXIT_UNFINISHED",
64+ "ERROR_PACKAGE_DOWNLOAD_FAILED", "ERROR_REPO_DOWNLOAD_FAILED",
65+ "ERROR_DEP_RESOLUTION_FAILED",
66+ "ERROR_KEY_NOT_INSTALLED", "ERROR_KEY_NOT_REMOVED", "ERROR_NO_LOCK",
67+ "ERROR_NO_CACHE", "ERROR_NO_PACKAGE", "ERROR_PACKAGE_UPTODATE",
68+ "ERROR_PACKAGE_NOT_INSTALLED", "ERROR_PACKAGE_ALREADY_INSTALLED",
69+ "ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE", "ERROR_DAEMON_DIED",
70+ "ERROR_PACKAGE_MANAGER_FAILED", "ERROR_CACHE_BROKEN",
71+ "ERROR_PACKAGE_UNAUTHENTICATED", "ERROR_INCOMPLETE_INSTALL",
72+ "ERROR_UNREADABLE_PACKAGE_FILE", "ERROR_INVALID_PACKAGE_FILE",
73+ "ERROR_SYSTEM_ALREADY_UPTODATE", "ERROR_NOT_SUPPORTED",
74+ "ERROR_LICENSE_KEY_INSTALL_FAILED",
75+ "ERROR_LICENSE_KEY_DOWNLOAD_FAILED",
76+ "ERROR_UNKNOWN",
77+ "STATUS_SETTING_UP", "STATUS_WAITING", "STATUS_WAITING_MEDIUM",
78+ "STATUS_WAITING_CONFIG_FILE_PROMPT", "STATUS_WAITING_LOCK",
79+ "STATUS_RUNNING", "STATUS_LOADING_CACHE", "STATUS_DOWNLOADING",
80+ "STATUS_COMMITTING", "STATUS_CLEANING_UP", "STATUS_RESOLVING_DEP",
81+ "STATUS_FINISHED", "STATUS_CANCELLING", "STATUS_QUERY",
82+ "STATUS_DOWNLOADING_REPO",
83+ "ROLE_UNSET", "ROLE_INSTALL_PACKAGES", "ROLE_INSTALL_FILE",
84+ "ROLE_UPGRADE_PACKAGES", "ROLE_UPGRADE_SYSTEM", "ROLE_UPDATE_CACHE",
85+ "ROLE_REMOVE_PACKAGES", "ROLE_COMMIT_PACKAGES",
86+ "ROLE_ADD_VENDOR_KEY_FILE", "ROLE_ADD_VENDOR_KEY_FROM_KEYSERVER",
87+ "ROLE_REMOVE_VENDOR_KEY", "ROLE_FIX_INCOMPLETE_INSTALL",
88+ "ROLE_FIX_BROKEN_DEPENDS", "ROLE_ADD_REPOSITORY",
89+ "ROLE_ENABLE_DISTRO_COMP", "ROLE_CLEAN", "ROLE_RECONFIGURE",
90+ "ROLE_PK_QUERY", "ROLE_ADD_LICENSE_KEY",
91+ "DOWNLOAD_DONE", "DOWNLOAD_AUTH_ERROR", "DOWNLOAD_ERROR",
92+ "DOWNLOAD_FETCHING", "DOWNLOAD_IDLE", "DOWNLOAD_NETWORK_ERROR",
93+ "PKG_INSTALLING", "PKG_CONFIGURING", "PKG_REMOVING",
94+ "PKG_PURGING", "PKG_UPGRADING", "PKG_RUNNING_TRIGGER",
95+ "PKG_DISAPPEARING", "PKG_PREPARING_REMOVE", "PKG_PREPARING_INSTALL",
96+ "PKG_PREPARING_PURGE", "PKG_PREPARING_PURGE", "PKG_INSTALLED",
97+ "PKG_REMOVED", "PKG_PURGED", "PKG_UNPACKING", "PKG_UNKNOWN",
98+ "get_status_icon_name_from_enum", "get_role_icon_name_from_enum",
99+ "get_status_animation_name_from_enum",
100+ "get_package_status_from_enum",
101+ "get_role_localised_past_from_enum", "get_exit_string_from_enum",
102+ "get_role_localised_present_from_enum", "get_role_error_from_enum",
103+ "get_error_description_from_enum", "get_error_string_from_enum",
104+ "get_status_string_from_enum", "get_download_status_from_enum")
105+
106+# PACKAGE GROUP INDEXES
107+#: Index of the list of to be installed packages in the :attr:`dependencies`
108+#: and :attr:`packages` property of :class:`~aptdaemon.client.AptTransaction`.
109+PKGS_INSTALL = 0
110+#: Index of the list of to be re-installed packages in the :attr:`dependencies`
111+#: and :attr:`packages` property of :class:`~aptdaemon.client.AptTransaction`.
112+PKGS_REINSTALL = 1
113+#: Index of the list of to be removed packages in the :attr:`dependencies`
114+#: and :attr:`packages` property of :class:`~aptdaemon.client.AptTransaction`.
115+PKGS_REMOVE = 2
116+#: Index of the list of to be purged packages in the :attr:`dependencies`
117+#: and :attr:`packages` property of :class:`~aptdaemon.client.AptTransaction`.
118+PKGS_PURGE = 3
119+#: Index of the list of to be upgraded packages in the :attr:`dependencies`
120+#: and :attr:`packages` property of :class:`~aptdaemon.client.AptTransaction`.
121+PKGS_UPGRADE = 4
122+#: Index of the list of to be downgraded packages in the :attr:`dependencies`
123+#: and :attr:`packages` property of :class:`~aptdaemon.client.AptTransaction`.
124+PKGS_DOWNGRADE = 5
125+#: Index of the list of to be keept packages in the :attr:`dependencies`
126+#: property of :class:`~aptdaemon.client.AptTransaction`.
127+PKGS_KEEP = 6
128+
129+# FINISH STATES
130+#: The transaction was successful.
131+EXIT_SUCCESS = "exit-success"
132+#: The transaction has been cancelled by the user.
133+EXIT_CANCELLED = "exit-cancelled"
134+#: The transaction has failed.
135+EXIT_FAILED = "exit-failed"
136+#: The transaction failed since a previous one in a chain failed.
137+EXIT_PREVIOUS_FAILED = "exit-previous-failed"
138+#: The transaction is still being queued or processed.
139+EXIT_UNFINISHED = "exit-unfinished"
140+
141+# ERROR CODES
142+#: Failed to download package files which should be installed.
143+ERROR_PACKAGE_DOWNLOAD_FAILED = "error-package-download-failed"
144+#: Failed to download package information (index files) from the repositories
145+ERROR_REPO_DOWNLOAD_FAILED = "error-repo-download-failed"
146+#: Failed to satisfy the dependencies or conflicts of packages.
147+ERROR_DEP_RESOLUTION_FAILED = "error-dep-resolution-failed"
148+#: The requested vendor key is not installed.
149+ERROR_KEY_NOT_INSTALLED = "error-key-not-installed"
150+#: The requested vendor could not be removed.
151+ERROR_KEY_NOT_REMOVED = "error-key-not-removed"
152+#: The package management system could not be locked. Eventually another
153+#: package manager is running.
154+ERROR_NO_LOCK = "error-no-lock"
155+#: The package cache could not be opened. This indicates a serious problem
156+#: on the system.
157+ERROR_NO_CACHE = "error-no-cache"
158+#: The requested package is not available.
159+ERROR_NO_PACKAGE = "error-no-package"
160+#: The package could not be upgraded since it is already up-to-date.
161+ERROR_PACKAGE_UPTODATE = "error-package-uptodate"
162+#: The package which was requested to install is already installed.
163+ERROR_PACKAGE_ALREADY_INSTALLED = "error-package-already-installed"
164+#: The package could not be removed since it is not installed.
165+ERROR_PACKAGE_NOT_INSTALLED = "error-package-not-installed"
166+#: It is not allowed to remove an essential system package.
167+ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE = "error-not-remove-essential"
168+#: The aptdaemon crashed or could not be connected to on the D-Bus.
169+ERROR_DAEMON_DIED = "error-daemon-died"
170+#: On of the maintainer scripts during the dpkg call failed.
171+ERROR_PACKAGE_MANAGER_FAILED = "error-package-manager-failed"
172+#: There are packages with broken dependencies installed on the system.
173+#: This has to fixed before performing another transaction.
174+ERROR_CACHE_BROKEN = "error-cache-broken"
175+#: It is not allowed to install an unauthenticated packages. Packages are
176+#: authenticated by installing the vendor key.
177+ERROR_PACKAGE_UNAUTHENTICATED = "error-package-unauthenticated"
178+#: A previous installation has been aborted and is now incomplete.
179+#: Should be fixed by `dpkg --configure -a` or the :func:`FixIncomplete()`
180+#: transaction.
181+ERROR_INCOMPLETE_INSTALL = "error-incomplete-install"
182+#: Failed to open and read the package file
183+ERROR_UNREADABLE_PACKAGE_FILE = "error-unreadable-package-file"
184+#: The package file violates the Debian/Ubuntu policy
185+ERROR_INVALID_PACKAGE_FILE = "error-invalid-package-file"
186+#: The requested feature is not supported yet (mainly used by PackageKit
187+ERROR_NOT_SUPPORTED = "error-not-supported"
188+#: The license key download failed
189+ERROR_LICENSE_KEY_DOWNLOAD_FAILED = "error-license-key-download-failed"
190+#: The license key is invalid
191+ERROR_LICENSE_KEY_INSTALL_FAILED = "error-license-key-install-failed"
192+#: The system is already up-to-date and don't needs any upgrades
193+ERROR_SYSTEM_ALREADY_UPTODATE = "error-system-already-uptodate"
194+#: An unknown error occured. In most cases these are programming ones.
195+ERROR_UNKNOWN = "error-unknown"
196+
197+# TRANSACTION STATES
198+#: The transaction was created, but hasn't been queued.
199+STATUS_SETTING_UP = "status-setting-up"
200+#: The transaction performs a query
201+STATUS_QUERY = "status-query"
202+#: The transaction is waiting in the queue.
203+STATUS_WAITING = "status-waiting"
204+#: The transaction is paused and waits until a required medium is inserted.
205+#: See :func:`ProvideMedium()`.
206+STATUS_WAITING_MEDIUM = "status-waiting-medium"
207+#: The transaction is paused and waits for the user to resolve a configuration
208+#: file conflict. See :func:`ResolveConfigFileConflict()`.
209+STATUS_WAITING_CONFIG_FILE_PROMPT = "status-waiting-config-file-prompt"
210+#: Wait until the package management system can be locked. Most likely
211+#: another package manager is running currently.
212+STATUS_WAITING_LOCK = "status-waiting-lock"
213+#: The processing of the transaction has started.
214+STATUS_RUNNING = "status-running"
215+#: The package cache is opened.
216+STATUS_LOADING_CACHE = "status-loading-cache"
217+#: The information about available packages is downloaded
218+STATUS_DOWNLOADING_REPO = "status-downloading-repo"
219+#: The required package files to install are getting downloaded.
220+STATUS_DOWNLOADING = "status-downloading"
221+#: The actual installation/removal takes place.
222+STATUS_COMMITTING = "status-committing"
223+#: The package management system is cleaned up.
224+STATUS_CLEANING_UP = "status-cleaning-up"
225+#: The dependecies and conflicts are now getting resolved.
226+STATUS_RESOLVING_DEP = "status-resolving-dep"
227+#: The transaction has been completed.
228+STATUS_FINISHED = "status-finished"
229+#: The transaction has been cancelled.
230+STATUS_CANCELLING = "status-cancelling"
231+#: The transaction waits for authentication
232+STATUS_AUTHENTICATING = "status-authenticating"
233+
234+# PACKAGE STATES
235+#: The package gets unpacked
236+PKG_UNPACKING = "pkg-unpacking"
237+#: The installation of the package gets prepared
238+PKG_PREPARING_INSTALL = "pkg-preparing-install"
239+#: The package is installed
240+PKG_INSTALLED = "pkg-installed"
241+#: The package gets installed
242+PKG_INSTALLING = "pkg-installing"
243+#: The configuration of the package gets prepared
244+PKG_PREPARING_CONFIGURE = "pkg-preparing-configure"
245+#: The package gets configured
246+PKG_CONFIGURING = "pkg-configuring"
247+#: The removal of the package gets prepared
248+PKG_PREPARING_REMOVE = "pkg-preparing-removal"
249+#: The package gets removed
250+PKG_REMOVING = "pkg-removing"
251+#: The package is removed
252+PKG_REMOVED = "pkg-removed"
253+#: The purging of the package gets prepared
254+PKG_PREPARING_PURGE = "pkg-preparing-purge"
255+#: The package gets purged
256+PKG_PURGING = "pkg-purging"
257+#: The package was completely removed
258+PKG_PURGED = "pkg-purged"
259+#: The post installation trigger of the package is processed
260+PKG_RUNNING_TRIGGER = "pkg-running-trigger"
261+#: The package disappered - very rare
262+PKG_DISAPPEARING = "pkg-disappearing"
263+#: The package gets upgraded
264+PKG_UPGRADING = "pkg-upgrading"
265+#: Failed to get a current status of the package
266+PKG_UNKNOWN = "pkg-unknown"
267+
268+# TRANSACTION ROLES
269+#: The role of the transaction has not been specified yet.
270+ROLE_UNSET = "role-unset"
271+#: The transaction performs a query compatible to the PackageKit interface
272+ROLE_PK_QUERY = "role-pk-query"
273+#: The transaction will install one or more packages.
274+ROLE_INSTALL_PACKAGES = "role-install-packages"
275+#: The transaction will install a local package file.
276+ROLE_INSTALL_FILE = "role-install-file"
277+#: The transaction will upgrade one or more packages.
278+ROLE_UPGRADE_PACKAGES = "role-upgrade-packages"
279+#: The transaction will perform a system upgrade.
280+ROLE_UPGRADE_SYSTEM = "role-upgrade-system"
281+#: The transaction will update the package cache.
282+ROLE_UPDATE_CACHE = "role-update-cache"
283+#: The transaction will remove one or more packages.
284+ROLE_REMOVE_PACKAGES = "role-remove-packages"
285+#: The transaction will perform a combined install, remove, upgrade or
286+#: downgrade action.
287+ROLE_COMMIT_PACKAGES = "role-commit-packages"
288+#: The transaction will add a local vendor key file to authenticate packages.
289+ROLE_ADD_VENDOR_KEY_FILE = "role-add-vendor-key-file"
290+#: The transaction will download vendor key to authenticate packages from
291+#: a keyserver.
292+ROLE_ADD_VENDOR_KEY_FROM_KEYSERVER = "role-add-vendor-key-from-keyserver"
293+#: The transaction will remove a vendor key which was used to authenticate
294+#: packages.
295+ROLE_REMOVE_VENDOR_KEY = "role-remove-vendor-key"
296+#: The transaction will try to finish a previous aborted installation.
297+ROLE_FIX_INCOMPLETE_INSTALL = "role-fix-incomplete-install"
298+#: The transaction will to resolve broken dependencies of already installed
299+#: packages.
300+ROLE_FIX_BROKEN_DEPENDS = "role-fix-broken-depends"
301+#: The transaction will enable a repository to download software from.
302+ROLE_ADD_REPOSITORY = "role-add-repository"
303+#: The transaction will enable a component in the distro repositories,
304+#: e.g main or universe
305+ROLE_ENABLE_DISTRO_COMP = "role-enable-distro-comp"
306+#: The transaction will reconfigure the given already installed packages
307+ROLE_RECONFIGURE = "role-reconfigure"
308+#: The transaction will remove all downloaded package files.
309+ROLE_CLEAN = "role-clean"
310+#: The transaction will add a license key to the system
311+ROLE_ADD_LICENSE_KEY = "role-add-license-key"
312+
313+# DOWNLOAD STATES
314+#: The download has been completed.
315+DOWNLOAD_DONE = "download-done"
316+#: The file could not be downloaded since the authentication for the repository
317+#: failed.
318+DOWNLOAD_AUTH_ERROR = "download-auth-error"
319+#: There file could not be downloaded, e.g. because it is not available (404).
320+DOWNLOAD_ERROR = "download-error"
321+#: The file is currently being downloaded.
322+DOWNLOAD_FETCHING = "download-fetching"
323+#: The download is currently idling.
324+DOWNLOAD_IDLE = "download-idle"
325+#: The download failed since there seem to be a networking problem.
326+DOWNLOAD_NETWORK_ERROR = "download-network-error"
327+
328+_ICONS_STATUS = {
329+ STATUS_CANCELLING: 'aptdaemon-cleanup',
330+ STATUS_CLEANING_UP: 'aptdaemon-cleanup',
331+ STATUS_RESOLVING_DEP: 'aptdaemon-resolve',
332+ STATUS_COMMITTING: 'aptdaemon-working',
333+ STATUS_DOWNLOADING: 'aptdaemon-download',
334+ STATUS_DOWNLOADING_REPO: 'aptdaemon-download',
335+ STATUS_FINISHED: 'aptdaemon-cleanup',
336+ STATUS_LOADING_CACHE: 'aptdaemon-update-cache',
337+ STATUS_RUNNING: 'aptdaemon-working',
338+ STATUS_SETTING_UP: 'aptdaemon-working',
339+ STATUS_WAITING: 'aptdaemon-wait',
340+ STATUS_WAITING_LOCK: 'aptdaemon-wait',
341+ STATUS_WAITING_MEDIUM: 'aptdaemon-wait',
342+ STATUS_WAITING_CONFIG_FILE_PROMPT: 'aptdaemon-wait',
343+ }
344+
345+def get_status_icon_name_from_enum(enum):
346+ """Get the icon name for a transaction status.
347+
348+ :param enum: The transaction status enum, e.g. :data:`STATUS_WAITING`.
349+ :returns: The icon name string.
350+ """
351+ try:
352+ return _ICONS_STATUS[enum]
353+ except KeyError:
354+ return "aptdaemon-working"
355+
356+_ICONS_ROLE = {
357+ ROLE_INSTALL_FILE: 'aptdaemon-add',
358+ ROLE_INSTALL_PACKAGES: 'aptdaemon-add',
359+ ROLE_UPDATE_CACHE: 'aptdaemon-update-cache',
360+ ROLE_REMOVE_PACKAGES: 'aptdaemon-delete',
361+ ROLE_UPGRADE_PACKAGES: 'aptdaemon-upgrade',
362+ ROLE_UPGRADE_SYSTEM: 'system-software-update',
363+ }
364+
365+def get_role_icon_name_from_enum(enum):
366+ """Get an icon to represent the role of a transaction.
367+
368+ :param enum: The transaction role enum, e.g. :data:`ROLE_UPDATE_CACHE`.
369+ :returns: The icon name string.
370+ """
371+ try:
372+ return _ICONS_ROLE[enum]
373+ except KeyError:
374+ return "aptdaemon-working"
375+
376+_ANIMATIONS_STATUS = {
377+ STATUS_CANCELLING: 'aptdaemon-action-cleaning-up',
378+ STATUS_CLEANING_UP: 'aptdaemon-action-cleaning-up',
379+ STATUS_RESOLVING_DEP: 'aptdaemon-action-resolving',
380+ STATUS_DOWNLOADING: 'aptdaemon-action-downloading',
381+ STATUS_DOWNLOADING_REPO: 'aptdaemon-action-downloading',
382+ STATUS_LOADING_CACHE: 'aptdaemon-action-updating-cache',
383+ STATUS_WAITING: 'aptdaemon-action-waiting',
384+ STATUS_WAITING_LOCK: 'aptdaemon-action-waiting',
385+ STATUS_WAITING_MEDIUM: 'aptdaemon-action-waiting',
386+ STATUS_WAITING_CONFIG_FILE_PROMPT: 'aptdaemon-action-waiting',
387+ }
388+
389+def get_status_animation_name_from_enum(enum):
390+ """Get an animation to represent a transaction status.
391+
392+ :param enum: The transaction status enum, e.g. :data:`STATUS_WAITING`.
393+ :returns: The animation name string.
394+ """
395+ try:
396+ return _ANIMATIONS_STATUS[enum]
397+ except KeyError:
398+ return None
399+
400+_PAST_ROLE = {
401+ ROLE_INSTALL_FILE : _("Installed file"),
402+ ROLE_INSTALL_PACKAGES : _("Installed packages"),
403+ ROLE_ADD_VENDOR_KEY_FILE: _("Added key from file"),
404+ ROLE_UPDATE_CACHE : _("Updated cache"),
405+ ROLE_PK_QUERY : _("Search done"),
406+ ROLE_REMOVE_VENDOR_KEY : _("Removed trusted key"),
407+ ROLE_REMOVE_PACKAGES : _("Removed packages"),
408+ ROLE_UPGRADE_PACKAGES : _("Updated packages"),
409+ ROLE_UPGRADE_SYSTEM : _("Upgraded system"),
410+ ROLE_COMMIT_PACKAGES : _("Applied changes"),
411+ ROLE_FIX_INCOMPLETE_INSTALL : _("Repaired incomplete installation"),
412+ ROLE_FIX_BROKEN_DEPENDS: _("Repaired broken dependencies"),
413+ ROLE_ADD_REPOSITORY: _("Added software source"),
414+ ROLE_ENABLE_DISTRO_COMP: _("Enabled component of the distribution"),
415+ ROLE_CLEAN: _("Removed downloaded package files"),
416+ ROLE_RECONFIGURE: _("Reconfigured installed packages"),
417+ ROLE_UNSET: ""
418+ }
419+
420+def get_role_localised_past_from_enum(enum):
421+ """Get the description of a completed transaction action.
422+
423+ :param enum: The transaction role enum, e.g. :data:`ROLE_UPDATE_CACHE`.
424+ :returns: The description string.
425+ """
426+ try:
427+ return _PAST_ROLE[enum]
428+ except KeyError:
429+ return None
430+
431+_STRING_EXIT = {
432+ EXIT_SUCCESS : _("Successful"),
433+ EXIT_CANCELLED : _("Canceled"),
434+ EXIT_FAILED : _("Failed")
435+ }
436+
437+def get_exit_string_from_enum(enum):
438+ """Get the description of a transaction exit status.
439+
440+ :param enum: The transaction exit status enum, e.g. :data:`EXIT_FAILED`.
441+ :returns: The description string.
442+ """
443+ try:
444+ return _STRING_EXIT[enum]
445+ except:
446+ return None
447+
448+_PRESENT_ROLE = {
449+ ROLE_INSTALL_FILE : _("Installing file"),
450+ ROLE_INSTALL_PACKAGES : _("Installing packages"),
451+ ROLE_ADD_VENDOR_KEY_FILE : _("Adding key from file"),
452+ ROLE_UPDATE_CACHE : _("Updating cache"),
453+ ROLE_REMOVE_VENDOR_KEY : _("Removing trusted key"),
454+ ROLE_REMOVE_PACKAGES : _("Removing packages"),
455+ ROLE_UPGRADE_PACKAGES : _("Updating packages"),
456+ ROLE_UPGRADE_SYSTEM : _("Upgrading system"),
457+ ROLE_COMMIT_PACKAGES : _("Applying changes"),
458+ ROLE_FIX_INCOMPLETE_INSTALL : _("Repairing incomplete installation"),
459+ ROLE_FIX_BROKEN_DEPENDS: _("Repairing installed software"),
460+ ROLE_ADD_REPOSITORY: _("Adding software source"),
461+ ROLE_ENABLE_DISTRO_COMP: _("Enabling component of the distribution"),
462+ ROLE_CLEAN: _("Removing downloaded package files"),
463+ ROLE_RECONFIGURE: _("Reconfiguring installed packages"),
464+ ROLE_PK_QUERY : _("Searching"),
465+ ROLE_UNSET : ""
466+ }
467+
468+def get_role_localised_present_from_enum(enum):
469+ """Get the description of a present transaction action.
470+
471+ :param enum: The transaction role enum, e.g. :data:`ROLE_UPDATE_CACHE`.
472+ :returns: The description string.
473+ """
474+ try:
475+ return _PRESENT_ROLE[enum]
476+ except KeyError:
477+ return None
478+
479+_ERROR_ROLE = {
480+ ROLE_INSTALL_FILE: _("Installation of the package file failed"),
481+ ROLE_INSTALL_PACKAGES: _("Installation of software failed"),
482+ ROLE_ADD_VENDOR_KEY_FILE: _("Adding the key to the list of trused "
483+ "software vendors failed"),
484+ ROLE_UPDATE_CACHE: _("Refreshing the software list failed"),
485+ ROLE_REMOVE_VENDOR_KEY: _("Removing the vendor from the list of trusted "
486+ "ones failed"),
487+ ROLE_REMOVE_PACKAGES: _("Removing software failed"),
488+ ROLE_UPGRADE_PACKAGES: _("Updating software failed"),
489+ ROLE_UPGRADE_SYSTEM: _("Upgrading the system failed"),
490+ ROLE_COMMIT_PACKAGES: _("Applying software changes failed"),
491+ ROLE_FIX_INCOMPLETE_INSTALL: _("Repairing incomplete installation failed"),
492+ ROLE_FIX_BROKEN_DEPENDS: _("Repairing broken dependencies failed"),
493+ ROLE_ADD_REPOSITORY: _("Adding software source failed"),
494+ ROLE_ENABLE_DISTRO_COMP: _("Enabling component of the distribution failed"),
495+ ROLE_CLEAN: _("Removing downloaded package files failed"),
496+ ROLE_RECONFIGURE: _("Removing downloaded package files failed"),
497+ ROLE_PK_QUERY: _("Search failed"),
498+ ROLE_ADD_LICENSE_KEY: _("Adding license key"),
499+ ROLE_UNSET: ""
500+ }
501+
502+def get_role_error_from_enum(enum):
503+ """Get the description of a failed transaction action.
504+
505+ :param enum: The transaction role enum, e.g. :data:`ROLE_UPDATE_CACHE`.
506+ :returns: The description string.
507+ """
508+ try:
509+ return _ERROR_ROLE[enum]
510+ except KeyError:
511+ return None
512+
513+_DESCS_ERROR = {
514+ ERROR_PACKAGE_DOWNLOAD_FAILED : _("Check your Internet connection."),
515+ ERROR_REPO_DOWNLOAD_FAILED : _("Check your Internet connection."),
516+ ERROR_CACHE_BROKEN : _("Check if you are using third party "
517+ "repositories. If so disable them, since "
518+ "they are a common source of problems.\n"
519+ "Furthermore run the following command in a "
520+ "Terminal: apt-get install -f"),
521+ ERROR_KEY_NOT_INSTALLED : _("The selected file may not be a GPG key file "
522+ "or it might be corrupt."),
523+ ERROR_KEY_NOT_REMOVED : _("The selected key couldn't be removed. "
524+ "Check that you provided a valid fingerprint."),
525+ ERROR_NO_LOCK : _("Check if you are currently running another "
526+ "software management tool, e.g. Synaptic or aptitude. "
527+ "Only one tool is allowed to make changes at a time."),
528+ ERROR_NO_CACHE : _("This is a serious problem. Try again later. If this "
529+ "problem appears again, please report an error to the "
530+ "developers."),
531+ ERROR_NO_PACKAGE : _("Check the spelling of the package name, and "
532+ "that the appropriate repository is enabled."),
533+ ERROR_PACKAGE_UPTODATE : _("There isn't any need for an update."),
534+ ERROR_PACKAGE_ALREADY_INSTALLED : _("There isn't any need for an "
535+ "installation"),
536+ ERROR_PACKAGE_NOT_INSTALLED : _("There isn't any need for a removal."),
537+ ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE : _("You requested to remove a package "
538+ "which is an essential part of your "
539+ "system."),
540+ ERROR_DAEMON_DIED : _("The connection to the daemon was lost. Most likely "
541+ "the background daemon crashed."),
542+ ERROR_PACKAGE_MANAGER_FAILED: _("The installation or removal of a software "
543+ "package failed."),
544+ ERROR_NOT_SUPPORTED: _("The requested feature is not supported."),
545+ ERROR_UNKNOWN : _("There seems to be a programming error in aptdaemon, "
546+ "the software that allows you to install/remove "
547+ "software and to perform other package management "
548+ "related tasks."),
549+ ERROR_DEP_RESOLUTION_FAILED: _("This error could be caused by required "
550+ "additional software packages which are "
551+ "missing or not installable. Furthermore "
552+ "there could be a conflict between software "
553+ "packages which are not allowed to be "
554+ "installed at the same time."),
555+ ERROR_PACKAGE_UNAUTHENTICATED: _("The action would require the "
556+ "installation of packages from not "
557+ "authenticated sources."),
558+ ERROR_INCOMPLETE_INSTALL: _("The installation could have failed because "
559+ "of an error in the corresponding software "
560+ "package or it was cancelled in an unfriendly "
561+ "way. "
562+ "You have to repair this before you can "
563+ "install or remove any further software."),
564+ ERROR_UNREADABLE_PACKAGE_FILE: _("Please copy the file to your local "
565+ "computer and check the file "
566+ "permissions."),
567+ ERROR_INVALID_PACKAGE_FILE: _("The installation of a package which "
568+ "violates the quality standards isn't "
569+ "allowed. This could cause serious problems "
570+ "on your computer. Please contact the person "
571+ "or organisation who provided this package "
572+ "file and include the details beneath."),
573+ ERROR_LICENSE_KEY_INSTALL_FAILED: _("The downloaded license key which is "
574+ "required to run this piece of "
575+ "software is not valid or could not "
576+ "be installed correctly.\n"
577+ "See the details for more "
578+ "information."),
579+ ERROR_SYSTEM_ALREADY_UPTODATE: _("All available upgrades have already "
580+ "been installed."),
581+ ERROR_LICENSE_KEY_DOWNLOAD_FAILED: _("The license key which allows you to "
582+ "use this piece of software could not be "
583+ "downloaded. Please check your "
584+ "network connection."),
585+ }
586+
587+def get_error_description_from_enum(enum):
588+ """Get a long description of an error.
589+
590+ :param enum: The transaction error enum, e.g. :data:`ERROR_NO_LOCK`.
591+ :returns: The description string.
592+ """
593+ try:
594+ return _DESCS_ERROR[enum]
595+ except KeyError:
596+ return None
597+
598+_STRINGS_ERROR = {
599+ ERROR_PACKAGE_DOWNLOAD_FAILED : _("Failed to download package files"),
600+ ERROR_REPO_DOWNLOAD_FAILED : _("Failed to download repository information"),
601+ ERROR_DEP_RESOLUTION_FAILED : _("Package dependencies cannot be resolved"),
602+ ERROR_CACHE_BROKEN : _("The package system is broken"),
603+ ERROR_KEY_NOT_INSTALLED : _("Key was not installed"),
604+ ERROR_KEY_NOT_REMOVED: _("Key was not removed"),
605+ ERROR_NO_LOCK : _("Failed to lock the package manager"),
606+ ERROR_NO_CACHE : _("Failed to load the package list"),
607+ ERROR_NO_PACKAGE : _("Package does not exist"),
608+ ERROR_PACKAGE_UPTODATE : _("Package is already up to date"),
609+ ERROR_PACKAGE_ALREADY_INSTALLED : _("Package is already installed"),
610+ ERROR_PACKAGE_NOT_INSTALLED : _("Package isn't installed"),
611+ ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE : _("Failed to remove essential "
612+ "system package"),
613+ ERROR_DAEMON_DIED : _("Task cannot be monitored or controlled"),
614+ ERROR_PACKAGE_MANAGER_FAILED: _("Package operation failed"),
615+ ERROR_PACKAGE_UNAUTHENTICATED: _("Requires installation of untrusted "
616+ "packages"),
617+ ERROR_INCOMPLETE_INSTALL: _("Previous installation hasn't been completed"),
618+ ERROR_INVALID_PACKAGE_FILE: _("The package is of bad quality"),
619+ ERROR_UNREADABLE_PACKAGE_FILE: _("Package file could not be opened"),
620+ ERROR_NOT_SUPPORTED: _("Not supported feature"),
621+ ERROR_LICENSE_KEY_DOWNLOAD_FAILED: _("Failed to download the license key"),
622+ ERROR_LICENSE_KEY_INSTALL_FAILED: _("Failed to install the license key"),
623+ ERROR_SYSTEM_ALREADY_UPTODATE: _("The system is already up to date"),
624+ ERROR_UNKNOWN : _("An unhandlable error occured")
625+ }
626+
627+def get_error_string_from_enum(enum):
628+ """Get a short description of an error.
629+
630+ :param enum: The transaction error enum, e.g. :data:`ERROR_NO_LOCK`.
631+ :returns: The description string.
632+ """
633+ try:
634+ return _STRINGS_ERROR[enum]
635+ except KeyError:
636+ return None
637+
638+_STRINGS_STATUS = {
639+ STATUS_SETTING_UP : _("Waiting for service to start"),
640+ STATUS_QUERY : _("Searching"),
641+ STATUS_WAITING : _("Waiting"),
642+ STATUS_WAITING_MEDIUM : _("Waiting for required medium"),
643+ STATUS_WAITING_LOCK : _("Waiting for other software managers to quit"),
644+ STATUS_WAITING_CONFIG_FILE_PROMPT : _("Waiting for configuration file "
645+ "prompt"),
646+ STATUS_RUNNING : _("Running task"),
647+ STATUS_DOWNLOADING : _("Downloading"),
648+ STATUS_DOWNLOADING_REPO : _("Querying software sources"),
649+ STATUS_CLEANING_UP : _("Cleaning up"),
650+ STATUS_RESOLVING_DEP : _("Resolving dependencies"),
651+ STATUS_COMMITTING : _("Applying changes"),
652+ STATUS_FINISHED : _("Finished"),
653+ STATUS_CANCELLING : _("Cancelling"),
654+ STATUS_LOADING_CACHE : _("Loading software list"),
655+ STATUS_AUTHENTICATING : _("Waiting for authentication"),
656+ }
657+
658+def get_status_string_from_enum(enum):
659+ """Get the description of a transaction status.
660+
661+ :param enum: The transaction status enum, e.g. :data:`STATUS_WAITING`.
662+ :returns: The description string.
663+ """
664+ try:
665+ return _STRINGS_STATUS[enum]
666+ except KeyError:
667+ return None
668+
669+STRINGS_PKG_STATUS = {
670+ #TRANSLATORS: %s is the name of a package
671+ PKG_INSTALLING: _("Installing %s"),
672+ #TRANSLATORS: %s is the name of a package
673+ PKG_CONFIGURING: _( "Configuring %s"),
674+ #TRANSLATORS: %s is the name of a package
675+ PKG_REMOVING: _( "Removing %s"),
676+ #TRANSLATORS: %s is the name of a package
677+ PKG_PURGING: _( "Completely removing %s"),
678+ #TRANSLATORS: %s is the name of a package
679+ PKG_PURGING: _( "Noting disappearance of %s"),
680+ #TRANSLATORS: %s is the name of a package
681+ PKG_RUNNING_TRIGGER: _("Running post-installation trigger %s"),
682+ #TRANSLATORS: %s is the name of a package
683+ PKG_UPGRADING: _("Upgrading %s"),
684+ #TRANSLATORS: %s is the name of a package
685+ PKG_UNPACKING: _("Unpacking %s"),
686+ #TRANSLATORS: %s is the name of a package
687+ PKG_PREPARING_INSTALL: _("Preparing installation of %s"),
688+ #TRANSLATORS: %s is the name of a package
689+ PKG_PREPARING_CONFIGURE: _("Preparing configuration of %s"),
690+ #TRANSLATORS: %s is the name of a package
691+ PKG_PREPARING_REMOVE: _("Preparing removal of %s"),
692+ #TRANSLATORS: %s is the name of a package
693+ PKG_PREPARING_PURGE: _("Preparing complete removal of %s"),
694+ #TRANSLATORS: %s is the name of a package
695+ PKG_INSTALLED: _("Installed %s"),
696+ #TRANSLATORS: %s is the name of a package
697+ PKG_PURGED: _("Completely removed %s"),
698+ #TRANSLATORS: %s is the name of a package
699+ PKG_REMOVED: _("Removed %s"),
700+ }
701+
702+def get_package_status_from_enum(enum):
703+ """Get the description of a package status.
704+
705+ :param enum: The download status enum, e.g. :data:`PKG_INSTALLING`.
706+ :returns: The description string.
707+ """
708+ try:
709+ return STRINGS_PKG_STATUS[enum]
710+ except KeyError:
711+ return _("Processing %s"),
712+
713+STRINGS_DOWNLOAD = {
714+ DOWNLOAD_DONE: _("Done"),
715+ DOWNLOAD_AUTH_ERROR: _("Authentication failed"),
716+ DOWNLOAD_ERROR: _("Failed"),
717+ DOWNLOAD_FETCHING: _("Fetching"),
718+ DOWNLOAD_IDLE: _("Idle"),
719+ DOWNLOAD_NETWORK_ERROR: _("Network isn't available"),
720+ }
721+
722+def get_download_status_from_enum(enum):
723+ """Get the description of a download status.
724+
725+ :param enum: The download status enum, e.g. :data:`DOWNLOAD_DONE`.
726+ :returns: The description string.
727+ """
728+ try:
729+ return STRINGS_DOWNLOAD[enum]
730+ except KeyError:
731+ return None
732+
733+# vim:ts=4:sw=4:et
734
735=== added directory '.pc/fix-lp-932581.patch'
736=== added directory '.pc/fix-lp-932581.patch/aptdaemon'
737=== added file '.pc/fix-lp-932581.patch/aptdaemon/pkcompat.py'
738--- .pc/fix-lp-932581.patch/aptdaemon/pkcompat.py 1970-01-01 00:00:00 +0000
739+++ .pc/fix-lp-932581.patch/aptdaemon/pkcompat.py 2012-08-11 01:29:19 +0000
740@@ -0,0 +1,2937 @@
741+#!/usr/bin/env python
742+# -*- coding: utf-8 -*-
743+"""
744+Provides a limited compatibility layer to PackageKit
745+
746+Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
747+Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
748+Copyright (C) 2008-2011 Sebastian Heinlein <glatzor@ubuntu.com>
749+
750+Licensed under the GNU General Public License Version 2
751+
752+This program is free software; you can redistribute it and/or modify
753+it under the terms of the GNU General Public License as published by
754+the Free Software Foundation; either version 2 of the License, or
755+(at your option) any later version.
756+"""
757+
758+__author__ = "Sebastian Heinlein <devel@glatzor.de>"
759+
760+import datetime
761+import glob
762+import gzip
763+import locale
764+import logging
765+import os
766+import re
767+import subprocess
768+import tempfile
769+import time
770+import traceback
771+import uuid
772+
773+import apt
774+import apt_pkg
775+from defer import inline_callbacks, return_value
776+from defer.utils import dbus_deferred_method
777+import dbus
778+from gi.repository import GObject
779+import lsb_release
780+import packagekit.enums as pk_enums
781+
782+# for optional plugin support
783+try:
784+ import pkg_resources
785+except ImportError:
786+ pkg_resources = None
787+
788+from aptdaemon import policykit1
789+import aptdaemon.core
790+from aptdaemon.core import APTDAEMON_TRANSACTION_DBUS_INTERFACE
791+import aptdaemon.enums as aptd_enums
792+from aptdaemon.errors import TransactionFailed, TransactionCancelled
793+from aptdaemon.progress import DaemonAcquireProgress
794+import aptdaemon.worker
795+import aptdaemon.networking
796+
797+GObject.threads_init()
798+
799+pklog = logging.getLogger("AptDaemon.PackageKit")
800+
801+# Check if update-manager-core is installed to get aware of the
802+# latest distro releases
803+try:
804+ from UpdateManager.Core.MetaRelease import MetaReleaseCore
805+except ImportError:
806+ META_RELEASE_SUPPORT = False
807+else:
808+ META_RELEASE_SUPPORT = True
809+
810+# Xapian database is optionally used to speed up package description search
811+XAPIAN_DB_PATH = os.environ.get("AXI_DB_PATH", "/var/lib/apt-xapian-index")
812+XAPIAN_DB = XAPIAN_DB_PATH + "/index"
813+XAPIAN_DB_VALUES = XAPIAN_DB_PATH + "/values"
814+XAPIAN_SUPPORT = False
815+try:
816+ import xapian
817+except ImportError:
818+ pass
819+else:
820+ if os.access(XAPIAN_DB, os.R_OK):
821+ pklog.debug("Use XAPIAN for the search")
822+ XAPIAN_SUPPORT = True
823+
824+# Regular expressions to detect bug numbers in changelogs according to the
825+# Debian Policy Chapter 4.4. For details see the footnote 16:
826+# http://www.debian.org/doc/debian-policy/footnotes.html#f16
827+MATCH_BUG_CLOSES_DEBIAN=r"closes:\s*(?:bug)?\#?\s?\d+(?:,\s*(?:bug)?\#?\s?\d+)*"
828+MATCH_BUG_NUMBERS=r"\#?\s?(\d+)"
829+# URL pointing to a bug in the Debian bug tracker
830+HREF_BUG_DEBIAN="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s"
831+
832+MATCH_BUG_CLOSES_UBUNTU = r"lp:\s+\#\d+(?:,\s*\#\d+)*"
833+HREF_BUG_UBUNTU = "https://bugs.launchpad.net/bugs/%s"
834+
835+# Regular expression to find cve references
836+MATCH_CVE="CVE-\d{4}-\d{4}"
837+HREF_CVE="http://web.nvd.nist.gov/view/vuln/detail?vulnId=%s"
838+
839+# Map Debian sections to the PackageKit group name space
840+SECTION_GROUP_MAP = {
841+ "admin" : pk_enums.GROUP_ADMIN_TOOLS,
842+ "base" : pk_enums.GROUP_SYSTEM,
843+ "comm" : pk_enums.GROUP_COMMUNICATION,
844+ "devel" : pk_enums.GROUP_PROGRAMMING,
845+ "doc" : pk_enums.GROUP_DOCUMENTATION,
846+ "editors" : pk_enums.GROUP_PUBLISHING,
847+ "electronics" : pk_enums.GROUP_ELECTRONICS,
848+ "embedded" : pk_enums.GROUP_SYSTEM,
849+ "games" : pk_enums.GROUP_GAMES,
850+ "gnome" : pk_enums.GROUP_DESKTOP_GNOME,
851+ "graphics" : pk_enums.GROUP_GRAPHICS,
852+ "hamradio" : pk_enums.GROUP_COMMUNICATION,
853+ "interpreters" : pk_enums.GROUP_PROGRAMMING,
854+ "kde" : pk_enums.GROUP_DESKTOP_KDE,
855+ "libdevel" : pk_enums.GROUP_PROGRAMMING,
856+ "libs" : pk_enums.GROUP_SYSTEM,
857+ "mail" : pk_enums.GROUP_INTERNET,
858+ "math" : pk_enums.GROUP_SCIENCE,
859+ "misc" : pk_enums.GROUP_OTHER,
860+ "net" : pk_enums.GROUP_NETWORK,
861+ "news" : pk_enums.GROUP_INTERNET,
862+ "oldlibs" : pk_enums.GROUP_LEGACY,
863+ "otherosfs" : pk_enums.GROUP_SYSTEM,
864+ "perl" : pk_enums.GROUP_PROGRAMMING,
865+ "python" : pk_enums.GROUP_PROGRAMMING,
866+ "science" : pk_enums.GROUP_SCIENCE,
867+ "shells" : pk_enums.GROUP_SYSTEM,
868+ "sound" : pk_enums.GROUP_MULTIMEDIA,
869+ "tex" : pk_enums.GROUP_PUBLISHING,
870+ "text" : pk_enums.GROUP_PUBLISHING,
871+ "utils" : pk_enums.GROUP_ACCESSORIES,
872+ "web" : pk_enums.GROUP_INTERNET,
873+ "x11" : pk_enums.GROUP_DESKTOP_OTHER,
874+ "unknown" : pk_enums.GROUP_UNKNOWN,
875+ "alien" : pk_enums.GROUP_UNKNOWN,
876+ "translations" : pk_enums.GROUP_LOCALIZATION,
877+ "metapackages" : pk_enums.GROUP_COLLECTIONS }
878+
879+PACKAGEKIT_DBUS_INTERFACE = "org.freedesktop.PackageKit"
880+PACKAGEKIT_DBUS_SERVICE = "org.freedesktop.PackageKit"
881+PACKAGEKIT_DBUS_PATH = "/org/freedesktop/PackageKit"
882+
883+PACKAGEKIT_TRANS_DBUS_INTERFACE = "org.freedesktop.PackageKit.Transaction"
884+PACKAGEKIT_TRANS_DBUS_SERVICE = "org.freedesktop.PackageKit.Transaction"
885+
886+MAP_EXIT_ENUM = {
887+ aptd_enums.EXIT_SUCCESS: pk_enums.EXIT_SUCCESS,
888+ aptd_enums.EXIT_CANCELLED: pk_enums.EXIT_CANCELLED,
889+ aptd_enums.EXIT_FAILED: pk_enums.EXIT_FAILED,
890+ aptd_enums.EXIT_FAILED: pk_enums.EXIT_FAILED,
891+ aptd_enums.EXIT_PREVIOUS_FAILED:
892+ pk_enums.EXIT_FAILED
893+ }
894+
895+MAP_STATUS_ENUM = {
896+ aptd_enums.STATUS_WAITING: pk_enums.STATUS_WAIT,
897+ aptd_enums.STATUS_RUNNING: pk_enums.STATUS_RUNNING,
898+ aptd_enums.STATUS_CANCELLING: pk_enums.STATUS_CANCEL,
899+ aptd_enums.STATUS_CLEANING_UP: pk_enums.STATUS_CLEANUP,
900+ aptd_enums.STATUS_COMMITTING: pk_enums.STATUS_COMMIT,
901+ aptd_enums.STATUS_DOWNLOADING: pk_enums.STATUS_DOWNLOAD,
902+ aptd_enums.STATUS_DOWNLOADING_REPO: pk_enums.STATUS_DOWNLOAD_REPOSITORY,
903+ aptd_enums.STATUS_FINISHED: pk_enums.STATUS_FINISHED,
904+ aptd_enums.STATUS_LOADING_CACHE: pk_enums.STATUS_LOADING_CACHE,
905+ aptd_enums.STATUS_RESOLVING_DEP: pk_enums.STATUS_DEP_RESOLVE,
906+ aptd_enums.STATUS_RUNNING: pk_enums.STATUS_RUNNING,
907+ aptd_enums.STATUS_WAITING_LOCK:
908+ pk_enums.STATUS_WAITING_FOR_LOCK,
909+ aptd_enums.STATUS_WAITING_MEDIUM: pk_enums.STATUS_UNKNOWN,
910+ aptd_enums.STATUS_WAITING_CONFIG_FILE_PROMPT:
911+ pk_enums.STATUS_UNKNOWN
912+}
913+
914+MAP_ERROR_ENUM = {
915+ aptd_enums.ERROR_CACHE_BROKEN: pk_enums.ERROR_NO_CACHE,
916+ aptd_enums.ERROR_DEP_RESOLUTION_FAILED:
917+ pk_enums.ERROR_DEP_RESOLUTION_FAILED,
918+ aptd_enums.ERROR_INCOMPLETE_INSTALL: pk_enums.ERROR_NO_CACHE,
919+ aptd_enums.ERROR_INVALID_PACKAGE_FILE:
920+ pk_enums.ERROR_PACKAGE_CORRUPT,
921+ aptd_enums.ERROR_KEY_NOT_INSTALLED: pk_enums.ERROR_GPG_FAILURE,
922+ aptd_enums.ERROR_KEY_NOT_REMOVED: pk_enums.ERROR_GPG_FAILURE,
923+ aptd_enums.ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE:
924+ pk_enums.ERROR_PACKAGE_FAILED_TO_REMOVE,
925+ aptd_enums.ERROR_NO_CACHE: pk_enums.ERROR_NO_CACHE,
926+ aptd_enums.ERROR_NO_LOCK: pk_enums.ERROR_CANNOT_GET_LOCK,
927+ aptd_enums.ERROR_NO_PACKAGE: pk_enums.ERROR_PACKAGE_NOT_FOUND,
928+ aptd_enums.ERROR_PACKAGE_ALREADY_INSTALLED:
929+ pk_enums.ERROR_PACKAGE_ALREADY_INSTALLED,
930+ aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED:
931+ pk_enums.ERROR_PACKAGE_DOWNLOAD_FAILED,
932+ aptd_enums.ERROR_PACKAGE_MANAGER_FAILED:
933+ pk_enums.ERROR_TRANSACTION_ERROR,
934+ aptd_enums.ERROR_PACKAGE_NOT_INSTALLED:
935+ pk_enums.ERROR_PACKAGE_NOT_INSTALLED,
936+ aptd_enums.ERROR_PACKAGE_UNAUTHENTICATED:
937+ pk_enums.ERROR_BAD_GPG_SIGNATURE,
938+ aptd_enums.ERROR_PACKAGE_UPTODATE:
939+ pk_enums.ERROR_NO_PACKAGES_TO_UPDATE,
940+ aptd_enums.ERROR_REPO_DOWNLOAD_FAILED:
941+ pk_enums.ERROR_REPO_NOT_AVAILABLE,
942+ aptd_enums.ERROR_UNREADABLE_PACKAGE_FILE:
943+ pk_enums.ERROR_INVALID_PACKAGE_FILE,
944+ aptd_enums.ERROR_SYSTEM_ALREADY_UPTODATE:
945+ pk_enums.ERROR_NO_PACKAGES_TO_UPDATE,
946+ }
947+
948+MAP_PACKAGE_ENUM = {
949+ aptd_enums.PKG_CONFIGURING:
950+ pk_enums.INFO_INSTALLING,
951+ aptd_enums.PKG_DISAPPEARING:
952+ pk_enums.INFO_UNKNOWN,
953+ aptd_enums.PKG_INSTALLED:
954+ pk_enums.INFO_FINISHED,
955+ aptd_enums.PKG_INSTALLING:
956+ pk_enums.INFO_INSTALLING,
957+ aptd_enums.PKG_PREPARING_INSTALL:
958+ pk_enums.INFO_PREPARING,
959+ aptd_enums.PKG_PREPARING_PURGE:
960+ pk_enums.INFO_PREPARING,
961+ aptd_enums.PKG_PREPARING_REMOVE:
962+ pk_enums.INFO_PREPARING,
963+ aptd_enums.PKG_PURGED:
964+ pk_enums.INFO_FINISHED,
965+ aptd_enums.PKG_PURGING:
966+ pk_enums.INFO_REMOVING,
967+ aptd_enums.PKG_REMOVED:
968+ pk_enums.INFO_FINISHED,
969+ aptd_enums.PKG_REMOVING:
970+ pk_enums.INFO_REMOVING,
971+ aptd_enums.PKG_RUNNING_TRIGGER:
972+ pk_enums.INFO_CLEANUP,
973+ aptd_enums.PKG_UNKNOWN:
974+ pk_enums.INFO_UNKNOWN,
975+ aptd_enums.PKG_UNPACKING:
976+ pk_enums.INFO_DECOMPRESSING,
977+ aptd_enums.PKG_UPGRADING:
978+ pk_enums.INFO_UPDATING,
979+ }
980+
981+
982+class PackageKit(aptdaemon.core.DBusObject):
983+
984+ """Provides a limited set of the PackageKit system D-Bus API."""
985+
986+ SUPPORTED_ROLES = [pk_enums.ROLE_REFRESH_CACHE,
987+ pk_enums.ROLE_UPDATE_SYSTEM,
988+ pk_enums.ROLE_SIMULATE_UPDATE_PACKAGES,
989+ pk_enums.ROLE_UPDATE_PACKAGES,
990+ pk_enums.ROLE_SIMULATE_REMOVE_PACKAGES,
991+ pk_enums.ROLE_INSTALL_PACKAGES,
992+ pk_enums.ROLE_SIMULATE_INSTALL_PACKAGES,
993+ pk_enums.ROLE_INSTALL_PACKAGES,
994+ pk_enums.ROLE_GET_DISTRO_UPGRADES,
995+ pk_enums.ROLE_GET_UPDATES,
996+ pk_enums.ROLE_GET_UPDATE_DETAIL,
997+ pk_enums.ROLE_GET_PACKAGES,
998+ pk_enums.ROLE_GET_DETAILS,
999+ pk_enums.ROLE_GET_DEPENDS,
1000+ pk_enums.ROLE_GET_REQUIRES,
1001+ pk_enums.ROLE_SEARCH_NAME,
1002+ pk_enums.ROLE_SEARCH_DETAILS,
1003+ pk_enums.ROLE_SEARCH_GROUP,
1004+ pk_enums.ROLE_SEARCH_FILE,
1005+ pk_enums.ROLE_WHAT_PROVIDES,
1006+ pk_enums.ROLE_DOWNLOAD_PACKAGES]
1007+
1008+ SUPPORTED_FILTERS = [pk_enums.FILTER_INSTALLED,
1009+ pk_enums.FILTER_NOT_INSTALLED,
1010+ pk_enums.FILTER_FREE,
1011+ pk_enums.FILTER_NOT_FREE,
1012+ pk_enums.FILTER_GUI,
1013+ pk_enums.FILTER_NOT_GUI,
1014+ pk_enums.FILTER_COLLECTIONS,
1015+ pk_enums.FILTER_NOT_COLLECTIONS,
1016+ pk_enums.FILTER_SUPPORTED,
1017+ pk_enums.FILTER_NOT_SUPPORTED,
1018+ pk_enums.FILTER_NEWEST]
1019+
1020+ def __init__(self, queue, connect=True, bus=None):
1021+ """Initialize a new PackageKit compatibility layer.
1022+
1023+ Keyword arguments:
1024+ connect -- if the daemon should connect to the D-Bus (default is True)
1025+ bus -- the D-Bus to connect to (defaults to the system bus)
1026+ """
1027+ pklog.info("Initializing PackageKit compat layer")
1028+ bus_name = None
1029+ bus_path = None
1030+ if connect == True:
1031+ if bus is None:
1032+ bus = dbus.SystemBus()
1033+ self.bus = bus
1034+ bus_path = PACKAGEKIT_DBUS_PATH
1035+ bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, self.bus)
1036+ aptdaemon.core.DBusObject.__init__(self, bus_name, bus_path)
1037+ self._updates_changed_timeout_id = None
1038+ self._updates_changed = False
1039+ self.queue = queue
1040+ self.queue.worker.connect("transaction-done", self._on_transaction_done)
1041+ self.queue.connect("queue-changed", self._on_queue_changed)
1042+ self._distro_id = None
1043+ self.netmon = aptdaemon.networking.get_network_monitor()
1044+ self.netmon.connect("network-state-changed",
1045+ self._on_network_state_changed)
1046+ self.netmon.get_network_state()
1047+
1048+ # SIGNALS
1049+
1050+ # pylint: disable-msg=C0103,C0322
1051+ @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
1052+ signature="")
1053+ def RestartSchedule(self):
1054+ """A system restart has been sceduled."""
1055+ pass
1056+
1057+ # pylint: disable-msg=C0103,C0322
1058+ @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
1059+ signature="")
1060+ def Changed(self):
1061+ """This signal is emitted when a property on the interface changes."""
1062+ pass
1063+
1064+ # pylint: disable-msg=C0103,C0322
1065+ @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
1066+ signature="as")
1067+ def TransactionListChanged(self, transactions):
1068+ """The transaction list has changed, because either a transaction
1069+ has finished or a new transaction created.
1070+
1071+ :param transactions: A list of transaction ID's.
1072+ :type transactions: as
1073+ """
1074+ pklog.debug("Emitting TransactionListChanged signal: %s", transactions)
1075+
1076+ # pylint: disable-msg=C0103,C0322
1077+ @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
1078+ signature="")
1079+ def UpdatesChanged(self):
1080+ """This signal is emitted when the number of updates has changed."""
1081+ pklog.debug("Emitting UpdatesChanged signal")
1082+
1083+ # pylint: disable-msg=C0103,C0322
1084+ @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
1085+ signature="")
1086+ def RepoListChanged(self):
1087+ """This signal is emitted when the repository list has changed."""
1088+ pass
1089+
1090+ # pylint: disable-msg=C0103,C0322
1091+ @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
1092+ signature="")
1093+ def Changed(self):
1094+ """This signal is emitted when a property on the interface changes."""
1095+ pklog.debug("Emitting PackageKit Changed()")
1096+
1097+ # METHODS
1098+
1099+ # pylint: disable-msg=C0103,C0322
1100+ @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
1101+ in_signature="s", out_signature="s")
1102+ def CanAuthorize(self, action_id):
1103+ """Allows a client to find out if it would be allowed to authorize
1104+ an action.
1105+
1106+ :param action_id: The action ID, e.g.
1107+ org.freedesktop.packagekit.system-network-proxy-configure
1108+ :returns: The result, either yes, no or interactive.
1109+ """
1110+ #FIXME: We need to map packagekit and aptdaemon polices
1111+ return "interactive"
1112+
1113+ # pylint: disable-msg=C0103,C0322
1114+ @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
1115+ in_signature="s", out_signature="")
1116+ def StateHasChanged(self, reason):
1117+ """This method suggests to PackageKit that the package backend state
1118+ may have changed. This allows plugins to the native package manager
1119+ to suggest that PackageKit drops it's caches.
1120+
1121+ :param reason:
1122+ The reason of the state change. Valid reasons are resume or
1123+ posttrans. Resume is given a lower priority than posttrans.
1124+ """
1125+ pklog.debug("StateHasChanged() was called: %s", reason)
1126+ self._updates_changed = True
1127+ if reason == "cache-update":
1128+ self._check_updates_changed(timeout=30)
1129+ elif reason == "resume":
1130+ self._check_updates_changed(timeout=180)
1131+
1132+ # pylint: disable-msg=C0103,C0322
1133+ @dbus_deferred_method(PACKAGEKIT_DBUS_INTERFACE,
1134+ in_signature="", out_signature="s",
1135+ sender_keyword="sender")
1136+ def GetTid(self, sender):
1137+ """Gets a new transaction ID from the daemon.
1138+
1139+ :returns: The tid, e.g. 45_dafeca_checkpoint32
1140+ """
1141+ return self._get_tid(sender)
1142+
1143+ @inline_callbacks
1144+ def _get_tid(self, sender):
1145+ pid, uid, cmdline = \
1146+ yield policykit1.get_proc_info_from_dbus_name(sender, self.bus)
1147+ pktrans = PackageKitTransaction(pid, uid, cmdline, self.queue, sender)
1148+ return_value(pktrans.tid)
1149+
1150+ # pylint: disable-msg=C0103,C0322
1151+ @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
1152+ in_signature="", out_signature="as")
1153+ def GetTransactionList(self):
1154+ """Gets the transaction list of any transactions that are in
1155+ progress.
1156+
1157+ :returns: A list of transaction ID's
1158+ """
1159+ pklog.debug("GetTransactionList() was called")
1160+ return self._get_transaction_list()
1161+
1162+ # HELPERS
1163+
1164+ def _get_properties(self, iface):
1165+ """Helper to get the properties of a D-Bus interface."""
1166+ if iface == PACKAGEKIT_DBUS_INTERFACE:
1167+ return {# Claim that we are a stable version
1168+ "VersionMajor": dbus.UInt32(6),
1169+ "VersionMinor": dbus.UInt32(18),
1170+ "VersionMicro": dbus.UInt32(0),
1171+ "BackendName": dbus.String("aptdaemon"),
1172+ "BackendDescription": dbus.String("Compatibility layer"),
1173+ "BackendAuthor": dbus.String(__author__),
1174+ "Filters": dbus.String(";".join(self.SUPPORTED_FILTERS)),
1175+ "Groups": dbus.String(";".join(SECTION_GROUP_MAP.values())),
1176+ "Roles": dbus.String(";".join(self.SUPPORTED_ROLES)),
1177+ "Locked": dbus.Boolean(False),
1178+ "NetworkState": dbus.String(self.netmon.state),
1179+ "DistroId": dbus.String(self._get_distro_id()),
1180+ }
1181+ else:
1182+ return {}
1183+
1184+ def _get_distro_id(self):
1185+ """Return information about the distibution."""
1186+ if self._distro_id is None:
1187+ info = lsb_release.get_distro_information()
1188+ arch = subprocess.Popen(["dpkg", "--print-architecture"],
1189+ stdout=subprocess.PIPE).communicate()[0]
1190+ try:
1191+ self._distro_id = "%s;%s;%s" % (info["ID"], info["CODENAME"], arch)
1192+ except KeyError:
1193+ self._distro_id = "unknown;unknown;%s" % arch
1194+ return self._distro_id
1195+
1196+ def _on_network_state_changed(self, mon, state):
1197+ self.Changed()
1198+ self.PropertiesChanged(PACKAGEKIT_DBUS_INTERFACE,
1199+ {"Network": state}, [])
1200+
1201+ def _on_queue_changed(self, queue):
1202+ self.TransactionListChanged(self._get_transaction_list())
1203+ self._check_updates_changed()
1204+
1205+ def _get_transaction_list(self):
1206+ pk_transactions = []
1207+ for trans in self.queue.items:
1208+ # We currently only emit PackageKit transaction
1209+ #FIXME: Should we use MergedTransaction for all transactions and
1210+ # ROLE_UNKOWN for aptdaemon only transactions?
1211+ try:
1212+ pk_transactions.append(trans.pktrans.tid)
1213+ except AttributeError:
1214+ pass
1215+ try:
1216+ pk_transactions.append(self.queue.worker.trans.pktrans.tid)
1217+ except AttributeError:
1218+ pass
1219+ return pk_transactions
1220+
1221+ def _on_transaction_done(self, worker, trans):
1222+ # If a cache modifing transaction is completed schedule an
1223+ # UpdatesChanged signal
1224+ if trans.role in (aptd_enums.ROLE_INSTALL_FILE,
1225+ aptd_enums.ROLE_INSTALL_PACKAGES,
1226+ aptd_enums.ROLE_REMOVE_PACKAGES,
1227+ aptd_enums.ROLE_UPGRADE_PACKAGES,
1228+ aptd_enums.ROLE_COMMIT_PACKAGES,
1229+ aptd_enums.ROLE_UPGRADE_SYSTEM,
1230+ aptd_enums.ROLE_FIX_BROKEN_DEPENDS):
1231+ self._updates_changed = True
1232+ self._check_updates_changed()
1233+ elif trans.role == aptd_enums.ROLE_UPDATE_CACHE:
1234+ self._updates_changed = True
1235+ self._check_updates_changed(timeout=30)
1236+
1237+ def _check_updates_changed(self, timeout=60):
1238+ """After the queue was processed schedule a delayed UpdatesChanged
1239+ signal if required.
1240+ """
1241+ if not self.queue.items and self._updates_changed:
1242+ if self._updates_changed_timeout_id:
1243+ # If we already have a scheduled UpdatesChanged signal
1244+ # delay it even further
1245+ pklog.debug("UpdatesChanged signal re-scheduled")
1246+ GObject.source_remove(self._updates_changed_timeout_id)
1247+ else:
1248+ pklog.debug("UpdatesChanged signal scheduled")
1249+ self._updates_changed_timeout_id = \
1250+ GObject.timeout_add_seconds(timeout,
1251+ self._delayed_updates_changed)
1252+
1253+ def _delayed_updates_changed(self):
1254+ """Emit the UpdatesChanged signal and clear the timeout."""
1255+ self.UpdatesChanged()
1256+ self._updates_changed_timeout_id = None
1257+ self._updates_changed = False
1258+ return False
1259+
1260+
1261+class MergedTransaction(aptdaemon.core.Transaction):
1262+
1263+ """Overlay of an Aptdaemon transaction which also provides the
1264+ PackageKit object and its interfaces.
1265+ """
1266+
1267+ def __init__(self, pktrans, role, queue, connect=True,
1268+ bus=None, packages=None, kwargs=None):
1269+ aptdaemon.core.Transaction.__init__(self, pktrans.tid[1:], role, queue,
1270+ pktrans.pid, pktrans.uid,
1271+ pktrans.cmdline, pktrans.sender,
1272+ connect, bus, packages, kwargs)
1273+ self.pktrans = pktrans
1274+ self.run_time = 0
1275+
1276+ def _set_status(self, enum):
1277+ aptdaemon.core.Transaction._set_status(self, enum)
1278+ self.pktrans.status = get_pk_status_enum(enum)
1279+
1280+ status = property(aptdaemon.core.Transaction._get_status, _set_status)
1281+
1282+ def _set_progress(self, percent):
1283+ aptdaemon.core.Transaction._set_progress(self, percent)
1284+ self.pktrans.percentage = self._progress
1285+
1286+ progress = property(aptdaemon.core.Transaction._get_progress, _set_progress)
1287+
1288+ def _set_progress_details(self, details):
1289+ aptdaemon.core.Transaction._set_progress_details(self, details)
1290+ self.pktrans.speed = int(details[4])
1291+ self.pktrans.remaining_time = int(details[5])
1292+ self.pktrans.elapsed_time = int(time.time() - self.pktrans.start_time)
1293+
1294+ progress_details = property(aptdaemon.core.Transaction._get_progress_details,
1295+ _set_progress_details)
1296+
1297+ def _set_progress_package(self, progress):
1298+ aptdaemon.core.Transaction._set_progress_package(self, progress)
1299+ pkg_name, enum = progress
1300+ self.emit_package(get_pk_package_enum(enum),
1301+ get_pk_package_id(pkg_name),
1302+ "")
1303+
1304+ progress_package = property(aptdaemon.core.Transaction._get_progress_package,
1305+ _set_progress_package)
1306+
1307+
1308+ def _set_exit(self, enum):
1309+ aptdaemon.core.Transaction._set_exit(self, enum)
1310+ self.pktrans.exit = get_pk_exit_enum(enum)
1311+
1312+ exit = property(aptdaemon.core.Transaction._get_exit, _set_exit)
1313+
1314+ def _set_error(self, excep):
1315+ aptdaemon.core.Transaction._set_error(self, excep)
1316+ self.pktrans.ErrorCode(get_pk_error_enum(excep.code),
1317+ self._error_property[1])
1318+
1319+ error = property(aptdaemon.core.Transaction._get_error, _set_error)
1320+
1321+ def _remove_from_connection_no_raise(self):
1322+ aptdaemon.core.Transaction._remove_from_connection_no_raise(self)
1323+ self.pktrans.Destroy()
1324+ try:
1325+ self.pktrans.remove_from_connection()
1326+ except LookupError as error:
1327+ pklog.debug("remove_from_connection() raised LookupError: %s",
1328+ error)
1329+ finally:
1330+ self.pktrans.trans = None
1331+ self.pktrans = None
1332+ return False
1333+
1334+ def emit_details(self, package_id, license, group, detail, url, size):
1335+ self.pktrans.Details(package_id, license, group, detail, url, size)
1336+
1337+ def emit_files(self, id, file_list):
1338+ self.pktrans.Files(id, file_list)
1339+
1340+ def emit_package(self, info, id, summary):
1341+ self.pktrans.Package(info, id, summary)
1342+ self.pktrans.last_package = id
1343+
1344+ def emit_update_detail(self, package_id, updates, obsoletes, vendor_url,
1345+ bugzilla_url, cve_url, restart, update_text,
1346+ changelog, state, issued, updated):
1347+ self.pktrans.UpdateDetail(package_id, updates, obsoletes, vendor_url,
1348+ bugzilla_url, cve_url, restart, update_text,
1349+ changelog, state, issued, updated)
1350+
1351+
1352+class PackageKitTransaction(aptdaemon.core.DBusObject):
1353+
1354+ """Provides a PackageKit transaction object."""
1355+
1356+ def __init__(self, pid, uid, cmdline, queue, sender,
1357+ connect=True, bus=None):
1358+ pklog.info("Initializing PackageKit transaction")
1359+ bus_name = None
1360+ bus_path = None
1361+ self.tid = "/%s" % uuid.uuid4().get_hex()
1362+ if connect == True:
1363+ if bus is None:
1364+ bus = dbus.SystemBus()
1365+ self.bus = bus
1366+ bus_path = self.tid
1367+ bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, bus)
1368+ aptdaemon.core.DBusObject.__init__(self, bus_name, bus_path)
1369+ self.queue = queue
1370+ self.hints = {}
1371+ self.start_time = time.time()
1372+ self._elapsed_time = 0
1373+ self._remaining_time = 0
1374+ self._speed = 0
1375+ self._caller_active = True
1376+ self._allow_cancel = False
1377+ self._percentage = 0
1378+ self._subpercentage = 0
1379+ self._status = pk_enums.STATUS_SETUP
1380+ self._last_package = ""
1381+ self.uid = uid
1382+ self.pid = pid
1383+ self.cmdline = cmdline
1384+ self.role = pk_enums.ROLE_UNKNOWN
1385+ self.sender = sender
1386+ self.trans = None
1387+
1388+ @property
1389+ def allow_cancel(self):
1390+ return self._allow_cancel
1391+
1392+ @allow_cancel.setter
1393+ def allow_cancel(self, value):
1394+ self._allow_cancel = dbus.Boolean(value)
1395+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1396+ {"AllowCancel": self._allow_cancel}, [])
1397+ self.Changed()
1398+
1399+ @property
1400+ def last_package(self):
1401+ return self._last_package
1402+
1403+ @last_package.setter
1404+ def last_package(self, value):
1405+ self._last_package = dbus.String(value)
1406+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1407+ {"LastPackage": self._last_package}, [])
1408+ self.Changed()
1409+
1410+ @property
1411+ def caller_active(self):
1412+ return self._caller_active
1413+
1414+ @caller_active.setter
1415+ def caller_active(self, value):
1416+ self._caller_active = dbus.Boolean(value)
1417+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1418+ {"CallerActive": self._caller_active}, [])
1419+ self.Changed()
1420+
1421+ @property
1422+ def percentage(self):
1423+ return self._percentage
1424+
1425+ @percentage.setter
1426+ def percentage(self, progress):
1427+ self._percentage = dbus.UInt32(progress)
1428+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1429+ {"Percentage": self._percentage}, [])
1430+ self.Changed()
1431+
1432+ @property
1433+ def subpercentage(self):
1434+ return self._subpercentage
1435+
1436+ @subpercentage.setter
1437+ def subpercentage(self, progress):
1438+ self._subpercentage = dbus.UInt32(progress)
1439+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1440+ {"SubPercentage": self._subpercentage}, [])
1441+ self.Changed()
1442+
1443+ @property
1444+ def status(self):
1445+ return self._status
1446+
1447+ @status.setter
1448+ def status(self, enum):
1449+ self._status = dbus.String(enum)
1450+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1451+ {"Status": self._status}, [])
1452+ self.Changed()
1453+
1454+ @property
1455+ def elapsed_time(self):
1456+ return self._elapsed_time
1457+
1458+ @elapsed_time.setter
1459+ def elapsed_time(self, ela):
1460+ self._elpased_time = dbus.UInt32(ela)
1461+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1462+ {"ElapsedTime": self._elapsed_time}, [])
1463+ self.Changed()
1464+
1465+ @property
1466+ def remaining_time(self):
1467+ return self._remaining_time
1468+
1469+ @remaining_time.setter
1470+ def remaining_time(self, value):
1471+ self._elpased_time = dbus.UInt32(value)
1472+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1473+ {"RemainingTime": self._remaining_time}, [])
1474+ self.Changed()
1475+
1476+ @property
1477+ def speed(self):
1478+ return self._speed
1479+
1480+ @speed.setter
1481+ def speed(self, speed):
1482+ self._speed = dbus.UInt32(speed)
1483+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1484+ {"AllowCancel": self._speed}, [])
1485+ self.Changed()
1486+
1487+ @property
1488+ def exit(self):
1489+ return self._exit
1490+
1491+ @exit.setter
1492+ def exit(self, enum):
1493+ self._exit = exit
1494+ self.run_time = int((time.time() - self.start_time) * 1000)
1495+ # The time could go backwards ...
1496+ if self.run_time < 0:
1497+ self.run_time = 0
1498+ if enum == pk_enums.EXIT_CANCELLED:
1499+ self.ErrorCode(pk_enums.ERROR_TRANSACTION_CANCELLED, "")
1500+ self.status = pk_enums.STATUS_FINISHED
1501+ self.Finished(enum, self.run_time)
1502+
1503+
1504+ # SIGNALS
1505+
1506+ # pylint: disable-msg=C0103,C0322
1507+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
1508+ signature="ssbsusus")
1509+ def Transaction(self, old_tid, timespec, succeeded, role, duration, data,
1510+ uid, cmdline):
1511+ """This signal is sent when more details are required about a
1512+ specific transaction.
1513+
1514+ :param old_tid: The transaction ID of the old transaction.
1515+ :param timespec: The timespec of the old transaction in ISO8601 format.
1516+ :param succeeded: If the transaction succeeded.
1517+ :param role: The role enumerated type.
1518+ :param duration: The duration of the transaction in milliseconds.
1519+ :param data: Any data associated
1520+ :param uid: The user ID of the user that scheduled the action.
1521+ :param cmdline: The command line of the tool that scheduled the action,
1522+ e.g. /usr/bin/gpk-application.
1523+ """
1524+ pass
1525+
1526+ # pylint: disable-msg=C0103,C0322
1527+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
1528+ signature="ss")
1529+ def ErrorCode(self, code, details):
1530+ """This signal is used to report errors back to the session program.
1531+ Errors should only be send on fatal abort.
1532+
1533+ :param code: Enumerated type, e.g. no-network.
1534+ :param details: Long description or error, e.g. "failed to connect"
1535+
1536+ :type code: s
1537+ :type details: s
1538+ """
1539+ pass
1540+
1541+ # pylint: disable-msg=C0103,C0322
1542+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
1543+ signature="")
1544+ def Changed(self):
1545+ """This signal is emitted when a property on the interface changes."""
1546+ pklog.debug("Emitting PackageKitTransaction Changed()")
1547+
1548+ # pylint: disable-msg=C0103,C0322
1549+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
1550+ signature="")
1551+ def Destroy(self):
1552+ """This signal is sent when the transaction has been destroyed
1553+ and is no longer available for use."""
1554+ pklog.debug("Emmitting Destroy()")
1555+
1556+ # pylint: disable-msg=C0103,C0322
1557+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
1558+ signature="su")
1559+ def Finished(self, exit, runtime):
1560+ """This signal is used to signal that the transaction has finished.
1561+ :param exit: The PkExitEnum describing the exit status of the
1562+ transaction.
1563+ :param runtime: The amount of time in milliseconds that the
1564+ transaction ran for.
1565+
1566+ :type exit: s
1567+ :type runtime: u
1568+ """
1569+ pklog.debug("Emitting Finished: %s, %s", exit, runtime)
1570+ pass
1571+
1572+ # pylint: disable-msg=C0103,C0322
1573+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
1574+ signature="ssssst")
1575+ def Details(self, package_id, license, group, detail, url, size):
1576+ """This signal allows the backend to convey more details about the
1577+ package.
1578+
1579+ :param package_id: The package ID
1580+
1581+ :param license:
1582+ The license string, e.g. GPLv2+ or BSD and (MPLv1.1 or GPLv2+).
1583+ Moredetails about the correct way to format licensing strings can
1584+ be found on the Fedora packaging wiki.
1585+ :param group:
1586+ The enumerated package group description
1587+ :param detail:
1588+ The multi-line package description. If formatting is required,
1589+ then markdown syntax should be used, e.g. This is **critically**
1590+ important
1591+ :param url:
1592+ The upstream project homepage
1593+ :param size:
1594+ The size of the package in bytes. This should be the size of the
1595+ entire package file, not the size of the files installed on the
1596+ system. If the package is not installed, and already downloaded
1597+ and present in the package manager cache, then this value should
1598+ be set to zero.
1599+ """
1600+ pklog.debug("Emmitting Details signal for %s", package_id)
1601+
1602+ # pylint: disable-msg=C0103,C0322
1603+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
1604+ signature="ss")
1605+ def Files(self, package_id, file_list):
1606+ """This signal is used to push file lists from the backend to the
1607+ session.
1608+
1609+ :param package_id:
1610+ The Package ID that called the method.
1611+ :param file_list:
1612+ The file list, with each file seporated with ;.
1613+ """
1614+ pklog.debug("Emitting Files signal: %s, %s", package_id, file_list)
1615+
1616+ # pylint: disable-msg=C0103,C0322
1617+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
1618+ signature="ssssssssssss")
1619+ def UpdateDetail(self, package_id, updates, obsoletes, vendor_url,
1620+ bugzilla_url, cve_url, restart, update_text, changelog,
1621+ state, issued, updated):
1622+ """This signal is sent when more details are required about a
1623+ specific update.
1624+
1625+ :param package_id: The package ID
1626+ :param updates:
1627+ A list of package_id's that are to be updated, seporated by
1628+ &. This odd delimited was chosen as \t is already being used
1629+ in the spawned backends, and & is a banned character in a
1630+ package_id.
1631+ :param obsoletes:
1632+ A list of package_id's that are to be obsoleted, separated by &
1633+ :param vendor_url:
1634+ A URL with more details on the update, e.g. a page with more
1635+ information on the update. The format of this command should
1636+ be http://www.foo.org/page.html?4567;Update to SELinux
1637+ :param bugzilla_url:
1638+ A bugzilla URL with more details on the update. If no URL is
1639+ available then this field should be left empty.
1640+ :param cve_url:
1641+ A CVE URL with more details on the security advisory.
1642+ :param restart:
1643+ A valid restart type, e.g. system.
1644+ :param update_text:
1645+ The update text describing the update. If formatting is required,
1646+ then markdown syntax should be used, e.g. This is **critically**
1647+ important.
1648+ :param changelog:
1649+ The ChangeLog text describing the changes since the last version.
1650+ :param state:
1651+ The state of the update, e.g. stable or testing.
1652+ :param issued:
1653+ The ISO8601 encoded date that the update was issued.
1654+ :param updated:
1655+ The ISO8601 encoded date that the update was updated.
1656+ """
1657+ pklog.debug("Emmitting UpdateDetail signal for %s", package_id)
1658+
1659+ # pylint: disable-msg=C0103,C0322
1660+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
1661+ signature="sss")
1662+ def Package(self, info, package_id, summary):
1663+ """This signal allows the backend to communicate packages to the
1664+ session.
1665+
1666+ If updating, as packages are updated then emit them to the screen.
1667+ This allows a summary to be presented after the transaction.
1668+ When returning results from a search always return installed
1669+ before available for the same package name.
1670+
1671+ :param info: A valid info string enumerated type
1672+ :param package_id: This identifier is of the form
1673+ name;version;arch;data in a single string and is meant to
1674+ represent a single package unique across all local and remote
1675+ data stores. For a remote, not-installed package the data
1676+ field should be set as the repository identifier or repository
1677+ name. The data field for an installed package must be prefixed
1678+ with installed as this is used to identify which packages are
1679+ installable or installed in the client tools. As a special
1680+ extension, if the package manager is able to track which
1681+ repository a package was originally installed from, then the data
1682+ field can be set to installed:REPO-NAME which allows the frontend
1683+ client to advise the user of the package origin. The data field
1684+ for a non-installed local package must be local as this signifies
1685+ a repository name is not available and that package resides
1686+ locally on the client system rather than in any specific
1687+ repository.
1688+ :param summary: The one line package summary, e.g. Clipart for
1689+ OpenOffice
1690+ """
1691+ pklog.debug("Emmitting Package signal: info=%s id=%s summary='%s'",
1692+ info, package_id, summary[:10])
1693+
1694+ # pylint: disable-msg=C0103,C0322
1695+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
1696+ signature="sss")
1697+ def DistroUpgrade(self, type, name, summary):
1698+ """This signal allows the backend to communicate distribution upgrades
1699+ to the session.
1700+ :param type: A valid upgrade string enumerated type, e.g. stable
1701+ or unstable
1702+ :param name: The short name of the distribution, e.g. Fedora Core
1703+ 10 RC1
1704+ :param summary: The multi-line description of the release
1705+ """
1706+ pass
1707+
1708+ # pylint: disable-msg=C0103,C0322
1709+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
1710+ signature="ss")
1711+ def RequireRestart(self, restart_type, package_id):
1712+ """This signal is sent when the session client should notify the user
1713+ that a restart is required to get all changes into effect.
1714+
1715+ :param package_id:
1716+ The Package ID of the package tiggering the restart
1717+ :param file_list:
1718+ One of system, application or session
1719+ """
1720+ pklog.debug("Emitting RequireRestart signal: %s, %s",
1721+ restart_type, package_id)
1722+
1723+ # METHODS
1724+
1725+ # pylint: disable-msg=C0103,C0322
1726+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1727+ in_signature="as", out_signature="")
1728+ def SetHints(self, hints):
1729+ """This method allows the calling session to set transaction hints
1730+ for the package manager which can change as the transaction runs.
1731+
1732+ This method can be sent before the transaction has been run or
1733+ whilst it is running. There is no limit to the number of times
1734+ this method can be sent, although some backends may only use the
1735+ values that were set before the transaction was started.
1736+
1737+ Each parameter value is optional.
1738+
1739+ :param hints: The values as an array of strings, for example
1740+ ['locale=en_GB.utf8','interactive=false','cache-age=3600']
1741+ """
1742+ for hint in hints:
1743+ key, value = hint.split("=", 1)
1744+ if key not in ["locale", "idle", "background", "interactive",
1745+ "cache-age", "frontend-socket"]:
1746+ raise Exception("Invalid option %s" % key)
1747+ self.hints[key] = value
1748+
1749+ # pylint: disable-msg=C0103,C0322
1750+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1751+ in_signature="", out_signature="",
1752+ sender_keyword="sender")
1753+ def Cancel(self, sender):
1754+ """This method cancels a transaction that is already running."""
1755+ if self.trans:
1756+ return self.trans._cancel(sender)
1757+
1758+ # pylint: disable-msg=C0103,C0322
1759+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1760+ in_signature="asbb", out_signature="",
1761+ sender_keyword="sender")
1762+ def RemovePackages(self, package_ids, allow_deps, autoremove, sender):
1763+ """This method removes packages from the local system.
1764+
1765+ This method typically emits Progress, Status and Error and Package.
1766+
1767+ Package enumerated types should be downloading, updating, installing or removing.
1768+
1769+ :param package_ids: An array of package IDs.
1770+ :param allow_deps:
1771+ Either true or false. If true allow other packages to be removed
1772+ with the package, but false should cause the script to abort if
1773+ other packages are dependant on the package.
1774+ :param autoremove:
1775+ Either true or false. This option is only really interesting on
1776+ embedded devices with a limited amount of flash storage. It
1777+ suggests to the packagekit backend that dependencies installed at
1778+ the same time as the package should also be removed if they are not
1779+ required by anything else. For instance, if you install OpenOffice,
1780+ it might download libneon as a dependency. When auto_remove is set
1781+ to true, and you remove OpenOffice then libneon will also get
1782+ removed automatically.
1783+ """
1784+ pklog.debug("RemovePackages() was called")
1785+ self.role = pk_enums.ROLE_REMOVE_PACKAGES
1786+ return self._remove_packages(package_ids, allow_deps, autoremove,
1787+ sender)
1788+
1789+ @inline_callbacks
1790+ def _remove_packages(self, package_ids, allow_deps, autoremove, sender):
1791+ self.trans = self._get_merged_trans(aptd_enums.ROLE_REMOVE_PACKAGES,
1792+ pkg_ids=package_ids,
1793+ pkg_type=aptd_enums.PKGS_REMOVE)
1794+ yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
1795+ "RemoveObsoletedDepends", autoremove,
1796+ sender)
1797+ try:
1798+ yield self.trans._simulate(sender)
1799+ except aptdameon.errors.TransactionFailed:
1800+ raise StopIteration
1801+ for pkgs in self.trans.depends:
1802+ if pkgs:
1803+ error_code = packagekit.errors.ERROR_DEP_RESOLUTION_FAILED
1804+ self.trans.pktrans.ErrorCode(error_code,
1805+ "Would change additional packages")
1806+ self.trans.pktrans.exit = pk_enums.EXIT_FAILED
1807+ yield self.trans._run(sender)
1808+
1809+ # pylint: disable-msg=C0103,C0322
1810+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1811+ in_signature="asb", out_signature="",
1812+ sender_keyword="sender")
1813+ def SimulateRemovePackages(self, package_ids, autoremove, sender):
1814+ """This method simulates a package update emitting packages
1815+ required to be installed, removed, updated, reinstalled,
1816+ downgraded, obsoleted or untrusted. The latter is used to present
1817+ the user untrusted packages that are about to be installed.
1818+
1819+ This method typically emits Error and Package.
1820+
1821+ :param package_ids: An array of package IDs.
1822+ :param autoremove:
1823+ Either true or false. This option is only really interesting on
1824+ embedded devices with a limited amount of flash storage. It
1825+ suggests to the packagekit backend that dependencies installed at
1826+ the same time as the package should also be removed if they are not
1827+ required by anything else. For instance, if you install OpenOffice,
1828+ it might download libneon as a dependency. When auto_remove is set
1829+ to true, and you remove OpenOffice then libneon will also get
1830+ removed automatically.
1831+ """
1832+ pklog.debug("SimulateRemovePackages() was called")
1833+ GObject.idle_add(defer_idle, self._simulate_remove_packages,
1834+ package_ids, autoremove, sender)
1835+
1836+ @inline_callbacks
1837+ def _simulate_remove_packages(self, package_ids, autoremove, sender):
1838+ self.role = pk_enums.ROLE_SIMULATE_REMOVE_PACKAGES
1839+ self.status = pk_enums.STATUS_DEP_RESOLVE
1840+ self.trans = self._get_merged_trans(aptd_enums.ROLE_REMOVE_PACKAGES,
1841+ pkg_ids=package_ids,
1842+ pkg_type=aptd_enums.PKGS_REMOVE)
1843+ yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
1844+ "RemoveObsoletedDepends", autoremove,
1845+ sender)
1846+ yield self._simulate_and_emit_packages(sender)
1847+
1848+
1849+ # pylint: disable-msg=C0103,C0322
1850+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1851+ in_signature="bas", out_signature="",
1852+ sender_keyword="sender")
1853+ def UpdatePackages(self, only_trusted, package_ids, sender):
1854+ """This method updates existing packages on the local system.
1855+
1856+ The installer should always update extra packages automatically
1857+ to fulfil dependencies.
1858+
1859+ This should allow an application to find out what package owns a
1860+ file on the system.
1861+
1862+ This method typically emits Progress, Status and Error and Package.
1863+
1864+ :param only_trusted:
1865+ If the transaction is only allowed to install trusted packages.
1866+ Unsigned packages should not be installed if this parameter is
1867+ TRUE. If this method is can only install trusted packages, and
1868+ the packages are unsigned, then the backend will send a
1869+ ErrorCode(missing-gpg-signature). On recieving this error, the
1870+ client may choose to retry with only_trusted FALSE after
1871+ gaining further authentication.
1872+ : param package_ids: An array of package IDs.
1873+ """
1874+ pklog.debug("UpdatePackages() was called")
1875+ return self._update_packages(only_trusted, package_ids, sender)
1876+
1877+ @inline_callbacks
1878+ def _update_packages(self, only_trusted, package_ids, sender):
1879+ self.role = pk_enums.ROLE_UPDATE_PACKAGES
1880+ self.trans = self._get_merged_trans(aptd_enums.ROLE_UPGRADE_PACKAGES,
1881+ pkg_ids=package_ids,
1882+ pkg_type=aptd_enums.PKGS_UPGRADE)
1883+ yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
1884+ "AllowUnauthenticated", not only_trusted,
1885+ sender)
1886+ yield self.trans._run(sender)
1887+
1888+ # pylint: disable-msg=C0103,C0322
1889+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1890+ in_signature="as", out_signature="",
1891+ sender_keyword="sender")
1892+ def SimulateUpdatePackages(self, package_ids, sender):
1893+ """This method simulates a package update emitting packages
1894+ required to be installed, removed, updated, reinstalled,
1895+ downgraded, obsoleted or untrusted. The latter is used to present
1896+ the user untrusted packages that are about to be installed.
1897+
1898+ This method typically emits Error and Package.
1899+
1900+ :param package_ids: An array of package IDs.
1901+ """
1902+ pklog.debug("SimulateUpdatePackages() was called")
1903+ self.role = pk_enums.ROLE_SIMULATE_UPDATE_PACKAGES
1904+ GObject.idle_add(defer_idle, self._simulate_update_packages,
1905+ package_ids, sender)
1906+
1907+ @inline_callbacks
1908+ def _simulate_update_packages(self, package_ids, sender):
1909+ self.status = pk_enums.STATUS_RUNNING
1910+ self.trans = self._get_merged_trans(aptd_enums.ROLE_UPGRADE_PACKAGES,
1911+ pkg_ids=package_ids,
1912+ pkg_type=aptd_enums.PKGS_UPGRADE)
1913+ yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
1914+ "AllowUnauthenticated", True, sender)
1915+ yield self._simulate_and_emit_packages(sender)
1916+
1917+ # pylint: disable-msg=C0103,C0322
1918+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1919+ in_signature="bas", out_signature="",
1920+ sender_keyword="sender")
1921+ def InstallPackages(self, only_trusted, package_ids, sender):
1922+ """This method installs new packages on the local system.
1923+
1924+ The installer should always install extra packages automatically
1925+ as the use could call GetDepends prior to the install if a
1926+ confirmation is required in the UI.
1927+
1928+ This method typically emits Progress, Status and Error and Package.
1929+
1930+ Package enumerated types should be downloading, updating,
1931+ installing or removing.
1932+
1933+ :param only_trusted:
1934+ If the transaction is only allowed to install trusted packages.
1935+ Unsigned packages should not be installed if this parameter is
1936+ TRUE. If this method is can only install trusted packages, and
1937+ the packages are unsigned, then the backend will send a
1938+ ErrorCode(missing-gpg-signature). On recieving this error, the
1939+ client may choose to retry with only_trusted FALSE after
1940+ gaining further authentication.
1941+ : param package_ids: An array of package IDs.
1942+ """
1943+ pklog.debug("InstallPackages() was called")
1944+ self.role = pk_enums.ROLE_INSTALL_PACKAGES
1945+ return self._install_packages(only_trusted, package_ids, sender)
1946+
1947+ @inline_callbacks
1948+ def _install_packages(self, only_trusted, package_ids, sender):
1949+ self.trans = self._get_merged_trans(aptd_enums.ROLE_INSTALL_PACKAGES,
1950+ pkg_ids=package_ids,
1951+ pkg_type=aptd_enums.PKGS_INSTALL)
1952+ yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
1953+ "AllowUnauthenticated", not only_trusted,
1954+ sender)
1955+ yield self.trans._run(sender)
1956+
1957+ # pylint: disable-msg=C0103,C0322
1958+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1959+ in_signature="as", out_signature="",
1960+ sender_keyword="sender")
1961+ def SimulateInstallPackages(self, package_ids, sender):
1962+ """This method simulates a package instalation emitting packages
1963+ required to be installed, removed, updated, reinstalled, downgraded,
1964+ obsoleted or untrusted. The latter is used to present the user
1965+ untrusted packages that are about to be installed.
1966+
1967+ This method typically emits Error and Package.
1968+
1969+ :param package_ids: An array of package IDs.
1970+ """
1971+ pklog.debug("SimulateInstallPackages() was called")
1972+ self.role = pk_enums.ROLE_SIMULATE_INSTALL_PACKAGES
1973+ GObject.idle_add(defer_idle, self._simulate_install_packages,
1974+ package_ids, sender)
1975+
1976+ @inline_callbacks
1977+ def _simulate_install_packages(self, package_ids, sender):
1978+ self.status = pk_enums.STATUS_RUNNING
1979+ self.trans = self._get_merged_trans(aptd_enums.ROLE_INSTALL_PACKAGES,
1980+ pkg_ids=package_ids,
1981+ pkg_type=aptd_enums.PKGS_INSTALL)
1982+ yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
1983+ "AllowUnauthenticated", True, sender)
1984+ yield self._simulate_and_emit_packages(sender)
1985+
1986+ @inline_callbacks
1987+ def _simulate_and_emit_packages(self, sender, update_info=None):
1988+ try:
1989+ yield self.trans._simulate(sender)
1990+ except:
1991+ raise StopIteration
1992+ for pkg in self.trans.depends[aptd_enums.PKGS_INSTALL]:
1993+ self.Package(pk_enums.INFO_INSTALLING,
1994+ get_pk_package_id(pkg), "")
1995+ for pkg in self.trans.depends[aptd_enums.PKGS_REINSTALL]:
1996+ self.Package(pk_enums.INFO_REINSTALLING,
1997+ get_pk_package_id(pkg, "installed"), "")
1998+ for pkg in self.trans.depends[aptd_enums.PKGS_REMOVE]:
1999+ self.Package(pk_enums.INFO_REMOVING,
2000+ get_pk_package_id(pkg, "installed"), "")
2001+ for pkg in self.trans.depends[aptd_enums.PKGS_PURGE]:
2002+ self.Package(pk_enums.INFO_REMOVING,
2003+ get_pk_package_id(pkg, "installed"), "")
2004+ for pkg in self.trans.depends[aptd_enums.PKGS_UPGRADE]:
2005+ self.Package(update_info or pk_enums.INFO_UPDATING,
2006+ get_pk_package_id(pkg, None), "")
2007+ for pkg in self.trans.depends[aptd_enums.PKGS_DOWNGRADE]:
2008+ self.Package(pk_enums.INFO_DOWNGRADING,
2009+ get_pk_package_id(pkg), "")
2010+ for pkg in self.trans.depends[aptd_enums.PKGS_KEEP]:
2011+ self.Package(pk_enums.INFO_BLOCKED,
2012+ get_pk_package_id(pkg), "")
2013+ self.status = pk_enums.STATUS_FINISHED
2014+ self.Finished(pk_enums.EXIT_SUCCESS, 0)
2015+
2016+ # pylint: disable-msg=C0103,C0322
2017+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2018+ in_signature="b", out_signature="",
2019+ sender_keyword="sender")
2020+ def RefreshCache(self, force, sender):
2021+ """This method should fetch updated meta-data for all enabled
2022+ repositories.
2023+
2024+ When fetching each software source, ensure to emit RepoDetail for
2025+ the current source to give the user interface some extra details.
2026+ Be sure to have the "enabled" field set to true, otherwise you
2027+ wouldn't be fetching that source.
2028+
2029+ This method typically emits Progress, Error and RepoDetail.
2030+
2031+ :param force: If the caches should be cleaned and reloaded even if
2032+ there is valid, up to date data.
2033+ """
2034+ pklog.debug("RefreshCache() was called")
2035+ self.role = pk_enums.ROLE_REFRESH_CACHE
2036+ return self._refresh_cache(force, sender)
2037+
2038+ @inline_callbacks
2039+ def _refresh_cache(self, force, sender):
2040+ self.trans = self._get_merged_trans(aptd_enums.ROLE_UPDATE_CACHE,
2041+ kwargs={"sources_list": None})
2042+ yield self.trans._run(sender)
2043+
2044+ # pylint: disable-msg=C0103,C0322
2045+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2046+ in_signature="b", out_signature="",
2047+ sender_keyword="sender")
2048+ def UpdateSystem(self, only_trusted, sender):
2049+ """This method updates all packages on the system to thier newest
2050+ versions.
2051+
2052+ The installer should update all the updateable packages on the
2053+ system, including automatically installing any new packages that
2054+ are needed for dependancies.
2055+
2056+ :param only_trusted:
2057+ If the transaction is only allowed to install trusted packages.
2058+ Unsigned packages should not be installed if this parameter is
2059+ TRUE. If this method is can only install trusted packages, and
2060+ the packages are unsigned, then the backend will send a
2061+ ErrorCode(missing-gpg-signature). On recieving this error, the
2062+ client may choose to retry with only_trusted FALSE after
2063+ gaining further authentication.
2064+ : param package_ids: An array of package IDs.
2065+ """
2066+ pklog.debug("UpdateSystem() was called")
2067+ return self._update_system(only_trusted, sender)
2068+
2069+ @inline_callbacks
2070+ def _update_system(self, only_trusted, sender):
2071+ self.role = pk_enums.ROLE_UPDATE_SYSTEM
2072+ self.trans = self._get_merged_trans(aptd_enums.ROLE_UPGRADE_SYSTEM,
2073+ kwargs={"safe_mode": False})
2074+ yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
2075+ "AllowUnauthenticated", not only_trusted,
2076+ sender)
2077+ yield self.trans._run(sender)
2078+
2079+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2080+ in_signature="as", out_signature="",
2081+ sender_keyword="sender")
2082+ def GetUpdateDetail(self, package_ids, sender):
2083+ """This method returns details about a specific update.
2084+
2085+ This method typically emits UpdateDetail and Error
2086+
2087+ :param package_ids: An array of package IDs.
2088+ """
2089+ pklog.debug("GetUpdateDetail() was called")
2090+ self.role = pk_enums.ROLE_GET_UPDATE_DETAIL
2091+ kwargs = {"package_ids": package_ids}
2092+ return self._run_query(kwargs, sender)
2093+
2094+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2095+ in_signature="s", out_signature="",
2096+ sender_keyword="sender")
2097+ def GetUpdates(self, filter, sender):
2098+ """This method should return a list of packages that are installed
2099+ and are upgradable. It should only return the newest update for
2100+ each installed package.
2101+
2102+ This method typically emits Progress, Error and Package.
2103+
2104+ :param filter: A correct filter, e.g. none or installed;~devel
2105+ """
2106+ pklog.debug("GetUpdates() was called")
2107+ self.role = pk_enums.ROLE_GET_UPDATES
2108+ kwargs = {"filters": filter.split(";")}
2109+ return self._run_query(kwargs, sender)
2110+
2111+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2112+ in_signature="", out_signature="",
2113+ sender_keyword="sender")
2114+ def GetDistroUpgrades(self, sender):
2115+ """This method should return a list of distribution upgrades that are
2116+ available. It should not return updates, only major upgrades.
2117+
2118+ This method typically emits DistroUpgrade, Error
2119+ """
2120+ pklog.debug("GetDistroUpgrades() was called")
2121+ self.role = pk_enums.ROLE_GET_DISTRO_UPGRADES
2122+ self.status = pk_enums.STATUS_RUNNING
2123+ GObject.idle_add(defer_idle, self._get_distro_upgrades)
2124+
2125+ def _get_distro_upgrades(self):
2126+ #FIXME: Should go into the worker after the threading branch is merged
2127+ # It allows to run a nested loop until the download is finished
2128+ self.allow_cancel = False
2129+ self.percentage = 101
2130+ self.status = pk_enums.STATUS_DOWNLOAD_UPDATEINFO
2131+
2132+ if META_RELEASE_SUPPORT == False:
2133+ self.ErrorCode(pk_enums.ERROR_INTERNAL_ERROR,
2134+ "Please make sure that update-manager-core is"
2135+ "correctly installed.")
2136+ self.exit = pk_enums.EXIT_FAILED
2137+ return
2138+
2139+ #FIXME Evil to start the download during init
2140+ meta_release = GMetaRelease()
2141+ meta_release.connect("download-done",
2142+ self._on_distro_upgrade_download_done)
2143+
2144+ def _on_distro_upgrade_download_done(self, meta_release):
2145+ #FIXME: Add support for description
2146+ if meta_release.new_dist != None:
2147+ self.DistroUpgrade("stable",
2148+ "%s %s" % (meta_release.new_dist.name,
2149+ meta_release.new_dist.version),
2150+ "The latest stable release")
2151+ self.exit = pk_enums.EXIT_SUCCESS
2152+
2153+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2154+ in_signature="sas", out_signature="",
2155+ sender_keyword="sender")
2156+ def Resolve(self, filter, packages, sender):
2157+ """This method turns a single package name into a package_id suitable
2158+ for the other methods.
2159+
2160+ If the package is a fully formed package_id, then this should be
2161+ treated as an exact package match. This is useful to find the summary
2162+ or installed status of a package_id returned from other methods.
2163+
2164+ This method typically emits Error and Package.
2165+
2166+ Package enumerated types should be available or installed.
2167+
2168+ :param filter: A correct filter, e.g. none or installed;~devel
2169+ :param packages:
2170+ An array of package names, e.g. scribus-clipart. The package
2171+ names are case sensitive, so for instance: Resolve('Packagekit')
2172+ would not match PackageKit. As a special case, if Resolve() is
2173+ called with a name prefixed with @ then this should be treated as
2174+ a category, for example: @web-development. In this instance, a
2175+ meta-package should be emitted, for example:
2176+ web-development;;;meta with the correct installed status and
2177+ summary for the category.
2178+ """
2179+ pklog.debug("Resolve() was called")
2180+ self.role = pk_enums.ROLE_RESOLVE
2181+ kwargs = {"filters": filter.split(";"), "packages": packages}
2182+ return self._run_query(kwargs, sender)
2183+
2184+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2185+ in_signature="s", out_signature="",
2186+ sender_keyword="sender")
2187+ def GetPackages(self, filter, sender):
2188+ """This method returns all the packages without a search term.
2189+
2190+ This method typically emits Progress, Error and Package.
2191+
2192+ Package enumerated types should be available or installed.
2193+
2194+ :param filter: A correct filter, e.g. none or installed;~devel
2195+ """
2196+ pklog.debug("GetPackages() was called")
2197+ self.role = pk_enums.ROLE_GET_PACKAGES
2198+ kwargs = {"filters": filter.split(";")}
2199+ return self._run_query(kwargs, sender)
2200+
2201+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2202+ in_signature="as", out_signature="",
2203+ sender_keyword="sender")
2204+ def GetDetails(self, package_ids, sender):
2205+ """This method should return all the details about a specific
2206+ package_id.
2207+
2208+ This method typically emits Progress, Status and Error and Details.
2209+
2210+ :param package_ids: An array of package IDs.
2211+ """
2212+ pklog.debug("GetDetails() was called")
2213+ self.role = pk_enums.ROLE_GET_DETAILS
2214+ kwargs = {"package_ids": package_ids}
2215+ return self._run_query(kwargs, sender)
2216+
2217+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2218+ in_signature="as", out_signature="",
2219+ sender_keyword="sender")
2220+ def GetFiles(self, package_ids, sender):
2221+ """This method should return the file list of the package_id.
2222+
2223+ This method typically emits Progress, Status and Error and Files.
2224+
2225+ :param package_ids: An array of package IDs.
2226+ """
2227+ pklog.debug("GetFiles() was called")
2228+ self.role = pk_enums.ROLE_GET_FILES
2229+ kwargs = {"package_ids": package_ids}
2230+ return self._run_query(kwargs, sender)
2231+
2232+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2233+ in_signature="sas", out_signature="",
2234+ sender_keyword="sender")
2235+ def SearchFiles(self, filter, values, sender):
2236+ """This method searches for files on the local system and files in
2237+ available packages.
2238+
2239+ This should search for files. This should allow an application to
2240+ find out what package owns a file on the system.
2241+
2242+ This method typically emits Progress, Error and Package.
2243+
2244+ Package enumerated types should be available or installed.
2245+
2246+ :param filter: A correct filter, e.g. none or installed;~devel
2247+ :param values:
2248+ A filename or fully qualified path and filename on the system.
2249+ If the search term begins with a / it will be assumed the entire
2250+ path has been given and only packages that contain this exact
2251+ path and filename will be returned. If the search term does not
2252+ start with / then it should be treated as a single filename,
2253+ which can be in any directory. The search is case sensitive,
2254+ and should not be escaped or surrounded in quotes.
2255+ """
2256+ pklog.debug("SearchFiles() was called")
2257+ self.role = pk_enums.ROLE_SEARCH_FILE
2258+ kwargs = {"filters": filter.split(";"),
2259+ "values": values}
2260+ return self._run_query(kwargs, sender)
2261+
2262+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2263+ in_signature="sas", out_signature="",
2264+ sender_keyword="sender")
2265+ def SearchDetails(self, filter, values, sender):
2266+ """This method allows deeper searching than SearchName().
2267+
2268+ Do not refresh the package cache. This should be fast. This is very
2269+ similar to search-name. This should search as much data as possible,
2270+ including, if possible repo names, package summaries, descriptions,
2271+ licenses and URLs.
2272+
2273+ Try to emit installed before available packages first, as it allows
2274+ the client program to perform the GUI filtering and matching whilst
2275+ the daemon is running the transaction.
2276+
2277+ If the backend includes installed and available versions of the same
2278+ package when searching then the available version will have to be
2279+ filtered in the backend.
2280+
2281+ This method typically emits Progress, Error and Package.
2282+
2283+ Package enumerated types should be available or installed.
2284+
2285+ :param filter: A correct filter, e.g. none or installed;~devel
2286+ :param values:
2287+ A single word search term with no wildcard chars. The search term
2288+ can contain many words separated by spaces. In this case, the
2289+ search operator is AND. For example, search of gnome power should
2290+ returns gnome-power-manager but not gnomesword or powertop.
2291+ The search should not be treated as case sensitive.
2292+ """
2293+ pklog.debug("SearchDetails() was called")
2294+ self.role = pk_enums.ROLE_SEARCH_DETAILS
2295+ kwargs = {"filters": filter.split(";"),
2296+ "values": values}
2297+ return self._run_query(kwargs, sender)
2298+
2299+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2300+ in_signature="sas", out_signature="",
2301+ sender_keyword="sender")
2302+ def SearchGroups(self, filter, values, sender):
2303+ """This method returns packages from a given group enumerated type.
2304+
2305+ Do not refresh the package cache. This should be fast.
2306+
2307+ Try to emit installed before available packages first, as it
2308+ allows the client program to perform the GUI filtering and matching
2309+ whilst the daemon is running the transaction.
2310+
2311+ If the backend includes installed and available versions of the same
2312+ package when searching then the available version will have to be
2313+ filtered in the backend.
2314+
2315+ This method typically emits Progress, Error and Package.
2316+
2317+ Package enumerated types should be available or installed.
2318+
2319+ :param filter: A correct filter, e.g. none or installed;~devel
2320+ :param values:
2321+ An enumerated group type, or unknown. The search cannot contain
2322+ spaces. The following recommendations are made below: If the values
2323+ strings are prefixed with category: then the request is treated
2324+ as a 'category search', for example: category:web-development.
2325+ Note: the old nomenclature for a 'category search' suggested using
2326+ a @ prefix for the values options. This is still supported, and
2327+ backends should continue to support category searches like
2328+ @web-development. If the values strings are prefixed with
2329+ repo: then the request is treated as a 'repository search', for
2330+ example: repo:fedora-debuginfo. In this instance all packages that
2331+ were either installed from, or can be installed from the
2332+ fedora-debuginfo source would be returned.
2333+ """
2334+ pklog.debug("SearchGroups() was called")
2335+ self.role = pk_enums.ROLE_SEARCH_GROUP
2336+ kwargs = {"filters": filter.split(";"),
2337+ "values": values}
2338+ return self._run_query(kwargs, sender)
2339+
2340+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2341+ in_signature="sas", out_signature="",
2342+ sender_keyword="sender")
2343+ def SearchNames(self, filter, values, sender):
2344+ """This method searches the package database by package name.
2345+
2346+ Try to emit installed before available packages first, as it
2347+ allows the client program to perform the GUI filtering and matching
2348+ whilst the daemon is running the transaction.
2349+
2350+ If the backend includes installed and available versions of the same
2351+ package when searching then the available version will have to be
2352+ filtered in the backend.
2353+
2354+ The search methods should return all results in all repositories.
2355+ This may mean that multiple versions of package are returned. If this
2356+ is not what is wanted by the client program, then the newest filter
2357+ should be used.
2358+
2359+ This method typically emits Progress, Error and Package.
2360+
2361+ Package enumerated types should be available or installed.
2362+
2363+ :param filter: A correct filter, e.g. none or installed;~devel
2364+ :param values:
2365+ A single word search term with no wildcard chars. The search term
2366+ can contain many words separated by spaces. In this case, the
2367+ search operator is AND. For example, search of gnome power should
2368+ returns gnome-power-manager but not gnomesword or powertop.
2369+ The search should not be treated as case sensitive.
2370+ """
2371+ pklog.debug("SearchNames() was called")
2372+ self.role = pk_enums.ROLE_SEARCH_NAME
2373+ kwargs = {"filters": filter.split(";"),
2374+ "values": values}
2375+ return self._run_query(kwargs, sender)
2376+
2377+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2378+ in_signature="s", out_signature="",
2379+ sender_keyword="sender")
2380+ def AcceptEula(self, eula_id, sender):
2381+ """This method allows the user to accept a end user licence agreement.
2382+
2383+ :param eula_id: A valid EULA ID
2384+ """
2385+ self.role = pk_enums.ROLE_ACCEPT_EULA
2386+ GObject.idle_add(self._fail_not_implemented)
2387+
2388+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2389+ in_signature="bas", out_signature="",
2390+ sender_keyword="sender")
2391+ def DownloadPackages(self, store_in_cache, package_ids, sender):
2392+ """This method downloads packages into a temporary directory.
2393+
2394+ This method should emit one Files signal for each package that
2395+ is downloaded, with the file list set as the name of the complete
2396+ downloaded file and directory, so for example:
2397+
2398+ DownloadPackages('hal;0.1.2;i386;fedora',
2399+ 'hal-info;2009-09-07;no-arch;updates') should send two signals,
2400+ e.g. Files('hal;0.1.2;i386;fedora', '/tmp/hal-0.1.2.i386.rpm')
2401+ and Files('hal-info;2009-09-07;no-arch;updates',
2402+ '/tmp/hal-info-2009-09-07.noarch.rpm').
2403+
2404+ :param store_in_cache:
2405+ If the downloaded files should be stored in the system package
2406+ cache rather than copied into a newly created directory. See the
2407+ developer docs for more details on how this is supposed to work.
2408+ :param package_ids: An array of package IDs.
2409+ """
2410+ self.role = pk_enums.ROLE_DOWNLOAD_PACKAGES
2411+ kwargs = {"store_in_cache": store_in_cache,
2412+ "package_ids": package_ids}
2413+ return self._run_query(kwargs, sender)
2414+
2415+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2416+ in_signature="u", out_signature="",
2417+ sender_keyword="sender")
2418+ def GetOldTransactions(self, number, sender):
2419+ """This method allows a client to view details for old transactions.
2420+
2421+ :param number:
2422+ The number of past transactions, or 0 for all known transactions.
2423+ """
2424+ self.role = pk_enums.ROLE_GET_OLD_TRANSACTIONS
2425+ GObject.idle_add(self._fail_not_implemented)
2426+
2427+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2428+ in_signature="s", out_signature="",
2429+ sender_keyword="sender")
2430+ def GetRepoList(self, filter, sender):
2431+ """This method returns the list of repositories used in the system.
2432+
2433+ This method should emit RepoDetail.
2434+
2435+ :param filter: A correct filter, e.g. none or installed;~devel
2436+ """
2437+ self.role = pk_enums.ROLE_GET_REPO_LIST
2438+ GObject.idle_add(self._fail_not_implemented)
2439+
2440+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2441+ in_signature="as", out_signature="",
2442+ sender_keyword="sender")
2443+ def SimulateInstallFiles(self, full_paths, sender):
2444+ """This method simulates a package file instalation emitting packages
2445+ required to be installed, removed, updated, reinstalled, downgraded,
2446+ obsoleted or untrusted. The latter is used to present the user
2447+ untrusted packages that are about to be installed.
2448+
2449+ This method typically emits Error and Package.
2450+
2451+ :param full_paths:
2452+ An array of full path and filenames to packages.
2453+ """
2454+ self.role = pk_enums.ROLE_SIMULATE_INSTALL_FILES
2455+ GObject.idle_add(self._fail_not_implemented)
2456+
2457+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2458+ in_signature="bas", out_signature="",
2459+ sender_keyword="sender")
2460+ def InstallFiles(self, only_trusted, full_paths, sender):
2461+ """This method installs local package files onto the local system.
2462+
2463+ The installer should always install extra dependant packages
2464+ automatically.
2465+
2466+ This method typically emits Progress, Status and Error and Package.
2467+
2468+ Package enumerated types should be downloading, updating, installing
2469+ or removing.
2470+
2471+ :param only_trusted:
2472+ If the transaction is only allowed to install trusted files.
2473+ Unsigned files should not be installed if this parameter is TRUE.
2474+ If this method is can only install trusted files, and the files
2475+ are unsigned, then the backend will send a
2476+ ErrorCode(missing-gpg-signature). On recieving this error, the
2477+ client may choose to retry with only_trusted FALSE after gaining
2478+ further authentication.
2479+ :param full_paths: An array of full path and filenames to packages.
2480+ """
2481+ self.role = pk_enums.ROLE_INSTALL_FILES
2482+ GObject.idle_add(self._fail_not_implemented)
2483+
2484+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2485+ in_signature="sss", out_signature="",
2486+ sender_keyword="sender")
2487+ def InstallSignature(self, sig_type, key_id, package_id, sender):
2488+ """This method allows us to install new security keys.
2489+
2490+ :param sig_type: A key type, e.g. gpg
2491+ :param key_id: A key ID, e.g. BB7576AC
2492+ :param package_id:
2493+ A PackageID for the package that the user is trying to install
2494+ """
2495+ self.role = pk_enums.ROLE_INSTALL_SIGNATURE
2496+ GObject.idle_add(self._fail_not_implemented)
2497+
2498+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2499+ in_signature="sss", out_signature="",
2500+ sender_keyword="sender")
2501+ def RepoSetData(self, repo_id, parameter, value, sender):
2502+ """This method allows arbitary data to be passed to the repository
2503+ handler.
2504+
2505+ :param repo_id:
2506+ A repository identifier, e.g. fedora-development-debuginfo
2507+ :param parameter:
2508+ The backend specific value, e.g. set-download-url.
2509+ :param value:
2510+ The backend specific value, e.g. http://foo.bar.org/baz.
2511+ """
2512+ self.role = pk_enums.ROLE_REPO_SET_DATA
2513+ GObject.idle_add(self._fail_not_implemented)
2514+
2515+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2516+ in_signature="sb", out_signature="",
2517+ sender_keyword="sender")
2518+ def RepoEnable(self, repo_id, enabled, sender):
2519+ """This method enables the repository specified.
2520+
2521+ :param repo_id:
2522+ A repository identifier, e.g. fedora-development-debuginfo
2523+ :param enabled: true if enabled, false if disabled.
2524+ """
2525+ self.role = pk_enums.ROLE_REPO_ENABLE
2526+ GObject.idle_add(self._fail_not_implemented)
2527+
2528+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2529+ in_signature="s", out_signature="",
2530+ sender_keyword="sender")
2531+ def Rollback(self, transaction_id, sender):
2532+ """This method rolls back the package database to a previous transaction.
2533+
2534+ :param transaction_id: A valid transaction ID.
2535+ """
2536+ self.role = pk_enums.ROLE_GET_CATEGORIES
2537+ GObject.idle_add(self._fail_not_implemented)
2538+
2539+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2540+ in_signature="ssas", out_signature="",
2541+ sender_keyword="sender")
2542+ def WhatProvides(self, filter, type, values, sender):
2543+ """This method returns packages that provide the supplied attributes.
2544+ This method is useful for finding out what package(s) provide a
2545+ modalias or GStreamer codec string.
2546+
2547+ This method typically emits Progress, Status and Error and Package.
2548+
2549+ Package enumerated types should be available or installed.
2550+
2551+ :param filter:
2552+ A correct filter, e.g. none or installed;~devel
2553+ :param type:
2554+ A PkProvideType, e.g. PK_PROVIDES_ENUM_CODEC.
2555+ :param values:
2556+ The data to send to the backend to get the packages. Note: This
2557+ is backend specific.
2558+ """
2559+ self.role = pk_enums.ROLE_WHAT_PROVIDES
2560+ kwargs = {"filters": filter.split(";"),
2561+ "type": type,
2562+ "values": values}
2563+ return self._run_query(kwargs, sender)
2564+
2565+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2566+ in_signature="", out_signature="",
2567+ sender_keyword="sender")
2568+ def GetCategories(self, sender):
2569+ """This method return the collection categories"""
2570+ self.role = pk_enums.ROLE_GET_CATEGORIES
2571+ GObject.idle_add(self._fail_not_implemented)
2572+
2573+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2574+ in_signature="sasb", out_signature="",
2575+ sender_keyword="sender")
2576+ def GetRequires(self, filter, package_ids, recursive, sender):
2577+ """This method returns packages that depend on this package. This is
2578+ useful to know, as if package_id is being removed, we can warn the
2579+ user what else would be removed.
2580+
2581+ This method typically emits Progress, Status and Error and Package.
2582+
2583+ Package enumerated types should be available or installed.
2584+
2585+ :param filter: A correct filter, e.g. none or installed;~devel
2586+ :param package_ids: An array of package IDs.
2587+ :param recursive:
2588+ Either true or false. If yes then the requirements should be
2589+ returned for all packages returned. This means if
2590+ gnome-power-manager depends on NetworkManager and NetworkManager
2591+ depends on HAL, then GetRequires on HAL should return both
2592+ gnome-power-manager and NetworkManager.
2593+ """
2594+ self.role = pk_enums.ROLE_GET_REQUIRES
2595+ kwargs = {"filters": filter.split(";"),
2596+ "package_ids": package_ids,
2597+ "recursive": recursive}
2598+ return self._run_query(kwargs, sender)
2599+
2600+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2601+ in_signature="sasb", out_signature="",
2602+ sender_keyword="sender")
2603+ def GetDepends(self, filter, package_ids, recursive, sender):
2604+ """This method returns packages that this package depends on.
2605+
2606+ This method typically emits Progress, Status and Error and Package.
2607+
2608+ Package enumerated types should be available or installed.
2609+
2610+ :param filter: A correct filter, e.g. none or installed;~devel
2611+ :param package_ids: An array of package IDs.
2612+ :param recursive:
2613+ Either true or false. If yes then the requirements should be
2614+ returned for all packages returned. This means if
2615+ gnome-power-manager depends on NetworkManager and NetworkManager
2616+ depends on HAL, then GetDepends on gnome-power-manager should
2617+ return both HAL and NetworkManager.
2618+ """
2619+ self.role = pk_enums.ROLE_GET_DEPENDS
2620+ kwargs = {"filters": filter.split(";"),
2621+ "package_ids": package_ids,
2622+ "recursive": recursive}
2623+ return self._run_query(kwargs, sender)
2624+
2625+ # HELPERS
2626+
2627+ def _fail_not_implemented(self):
2628+ self.ErrorCode(pk_enums.ERROR_NOT_SUPPORTED, "")
2629+ self.exit = pk_enums.EXIT_FAILED
2630+ return False
2631+
2632+ def _get_properties(self, iface):
2633+ """Helper to get the properties of a D-Bus interface."""
2634+ if iface == PACKAGEKIT_TRANS_DBUS_INTERFACE:
2635+ return {"Role": dbus.String(self.role),
2636+ "Status": dbus.String(self.status),
2637+ "LastPackage": dbus.String(self.last_package),
2638+ "Uid": dbus.UInt32(self.uid),
2639+ "Percentage": dbus.UInt32(self.percentage),
2640+ "Subpercentage": dbus.UInt32(self.subpercentage),
2641+ "AllowCancel": dbus.Boolean(self.allow_cancel),
2642+ "CallerActive": dbus.Boolean(self.caller_active),
2643+ "ElapsedTime": dbus.UInt32(self.elapsed_time),
2644+ "RemainingTime": dbus.UInt32(self.remaining_time),
2645+ "Speed": dbus.UInt32(self.speed)
2646+ }
2647+ else:
2648+ return {}
2649+
2650+ @inline_callbacks
2651+ def _run_query(self, kwargs, sender):
2652+ self.trans = self._get_merged_trans(aptd_enums.ROLE_PK_QUERY,
2653+ kwargs=kwargs)
2654+ yield self.trans._run(sender)
2655+
2656+ def _get_merged_trans(self, role, pkg_ids=None, pkg_type=None, kwargs=None):
2657+ if pkg_ids:
2658+ packages = [[], [], [], [], [], []]
2659+ packages[pkg_type] = [get_aptd_package_id(pkg) for pkg in pkg_ids]
2660+ else:
2661+ packages = None
2662+ if self.trans:
2663+ raise Exception("%s: Transaction may only run once." % \
2664+ pk_enums.ERROR_TRANSACTION_FAILED)
2665+ trans = MergedTransaction(self, role, self.queue,
2666+ packages=packages, kwargs=kwargs)
2667+ try:
2668+ trans._set_locale(self.hints["locale"])
2669+ except (KeyError, ValueError):
2670+ # If the locale isn't vaild or supported a ValueError will be raised
2671+ pass
2672+ try:
2673+ trans._set_debconf(self.hints["frontend-socket"])
2674+ except KeyError:
2675+ pass
2676+ self.queue.limbo[trans.tid] = trans
2677+ return trans
2678+
2679+
2680+class PackageKitWorker(aptdaemon.worker.AptWorker):
2681+
2682+ _plugins = None
2683+
2684+ """Process PackageKit Query transactions."""
2685+
2686+ def query(self, trans):
2687+ """Run the worker"""
2688+ if trans.role != aptd_enums.ROLE_PK_QUERY:
2689+ raise TransactionFailed(aptd_enums.ERROR_UNKNOWN,
2690+ "The transaction doesn't seem to be "
2691+ "a query")
2692+ if trans.pktrans.role == pk_enums.ROLE_RESOLVE:
2693+ self.resolve(trans, **trans.kwargs)
2694+ elif trans.pktrans.role == pk_enums.ROLE_GET_UPDATES:
2695+ self.get_updates(trans, **trans.kwargs)
2696+ elif trans.pktrans.role == pk_enums.ROLE_GET_UPDATE_DETAIL:
2697+ self.get_update_detail(trans, **trans.kwargs)
2698+ elif trans.pktrans.role == pk_enums.ROLE_GET_PACKAGES:
2699+ self.get_packages(trans, **trans.kwargs)
2700+ elif trans.pktrans.role == pk_enums.ROLE_GET_FILES:
2701+ self.get_files(trans, **trans.kwargs)
2702+ elif trans.pktrans.role == pk_enums.ROLE_SEARCH_NAME:
2703+ self.search_names(trans, **trans.kwargs)
2704+ elif trans.pktrans.role == pk_enums.ROLE_SEARCH_GROUP:
2705+ self.search_groups(trans, **trans.kwargs)
2706+ elif trans.pktrans.role == pk_enums.ROLE_SEARCH_DETAILS:
2707+ self.search_details(trans, **trans.kwargs)
2708+ elif trans.pktrans.role == pk_enums.ROLE_SEARCH_FILE:
2709+ self.search_files(trans, **trans.kwargs)
2710+ elif trans.pktrans.role == pk_enums.ROLE_GET_DEPENDS:
2711+ self.get_depends(trans, **trans.kwargs)
2712+ elif trans.pktrans.role == pk_enums.ROLE_GET_REQUIRES:
2713+ self.get_requires(trans, **trans.kwargs)
2714+ elif trans.pktrans.role == pk_enums.ROLE_GET_DETAILS:
2715+ self.get_details(trans, **trans.kwargs)
2716+ elif trans.pktrans.role == pk_enums.ROLE_DOWNLOAD_PACKAGES:
2717+ self.download_packages(trans, **trans.kwargs)
2718+ elif trans.pktrans.role == pk_enums.ROLE_WHAT_PROVIDES:
2719+ self.what_provides(trans, **trans.kwargs)
2720+ else:
2721+ raise TransactionFailed(aptd_enums.ERROR_UNKNOWN,
2722+ "Role %s isn't supported",
2723+ trans.pktrans.role)
2724+
2725+ def search_files(self, trans, filters, values):
2726+ """Implement org.freedesktop.PackageKit.Transaction.SearchFiles()
2727+
2728+ Works only for installed file if apt-file isn't installed.
2729+ """
2730+ trans.progress = 101
2731+
2732+ result_names = set()
2733+ # Optionally make use of apt-file's Contents cache to search for not
2734+ # installed files. But still search for installed files additionally
2735+ # to make sure that we provide up-to-date results
2736+ if os.path.exists("/usr/bin/apt-file") and \
2737+ pk_enums.FILTER_INSTALLED not in filters:
2738+ #FIXME: Make use of rapt-file on Debian if the network is available
2739+ #FIXME: Show a warning to the user if the apt-file cache is several
2740+ # weeks old
2741+ pklog.debug("Using apt-file")
2742+ filenames_regex = []
2743+ for filename in values:
2744+ if filename.startswith("/"):
2745+ pattern = "^%s$" % filename[1:].replace("/", "\/")
2746+ else:
2747+ pattern = "\/%s$" % filename
2748+ filenames_regex.append(pattern)
2749+ cmd = ["/usr/bin/apt-file", "--regexp", "--non-interactive",
2750+ "--package-only", "find", "|".join(filenames_regex)]
2751+ pklog.debug("Calling: %s" % cmd)
2752+ apt_file = subprocess.Popen(cmd, stdout=subprocess.PIPE,
2753+ stderr=subprocess.PIPE)
2754+ stdout, stderr = apt_file.communicate()
2755+ if apt_file.returncode == 0:
2756+ #FIXME: Actually we should check if the file is part of the
2757+ # candidate, e.g. if unstable and experimental are
2758+ # enabled and a file would only be part of the
2759+ # experimental version
2760+ result_names.update(stdout.split())
2761+ self._emit_visible_packages_by_name(trans, filters,
2762+ result_names)
2763+ else:
2764+ raise TransactionFailed(ERROR_INTERNAL_ERROR,
2765+ "%s %s" % (stdout, stderr))
2766+ # Search for installed files
2767+ filenames_regex = []
2768+ for filename in values:
2769+ if filename.startswith("/"):
2770+ pattern = "^%s$" % filename.replace("/", "\/")
2771+ else:
2772+ pattern = ".*\/%s$" % filename
2773+ filenames_regex.append(pattern)
2774+ files_pattern = re.compile("|".join(filenames_regex))
2775+ for pkg in self._iterate_packages():
2776+ if pkg.name in result_names:
2777+ continue
2778+ for installed_file in self._get_installed_files(pkg):
2779+ if files_pattern.match(installed_file):
2780+ self._emit_visible_package(trans, filters, pkg)
2781+ break
2782+
2783+ def search_groups(self, trans, filters, values):
2784+ """Implement org.freedesktop.PackageKit.Transaction.SearchGroups()"""
2785+ #FIXME: Handle repo and category search
2786+ trans.progress = 101
2787+
2788+ for pkg in self._iterate_packages():
2789+ if self._get_package_group(pkg) in values:
2790+ self._emit_visible_package(trans, filters, pkg)
2791+
2792+ def search_names(self, trans, filters, values):
2793+ """Implement org.freedesktop.PackageKit.Transaction.SearchNames()"""
2794+ def matches(searches, text):
2795+ for search in searches:
2796+ if not search in text:
2797+ return False
2798+ return True
2799+ pklog.info("Searching for package name: %s" % values)
2800+ trans.progress = 101
2801+
2802+ for pkg_name in self._cache.keys():
2803+ if matches(values, pkg_name):
2804+ self._emit_all_visible_pkg_versions(trans, filters,
2805+ self._cache[pkg_name])
2806+
2807+ def search_details(self, trans, filters, values):
2808+ """Implement org.freedesktop.PackageKit.Transaction.SearchDetails()"""
2809+ trans.progress = 101
2810+ results = []
2811+
2812+ if XAPIAN_SUPPORT == True:
2813+ search_flags = (xapian.QueryParser.FLAG_BOOLEAN |
2814+ xapian.QueryParser.FLAG_PHRASE |
2815+ xapian.QueryParser.FLAG_LOVEHATE |
2816+ xapian.QueryParser.FLAG_BOOLEAN_ANY_CASE)
2817+ pklog.debug("Performing xapian db based search")
2818+ db = xapian.Database(XAPIAN_DB)
2819+ parser = xapian.QueryParser()
2820+ parser.set_default_op(xapian.Query.OP_AND)
2821+ query = parser.parse_query(u" ".join(values), search_flags)
2822+ enquire = xapian.Enquire(db)
2823+ enquire.set_query(query)
2824+ matches = enquire.get_mset(0, 1000)
2825+ for pkg_name in (match.document.get_data()
2826+ for match in enquire.get_mset(0,1000)):
2827+ if pkg_name in self._cache:
2828+ self._emit_visible_package(trans, filters,
2829+ self._cache[pkg_name])
2830+ else:
2831+ def matches(searches, text):
2832+ for search in searches:
2833+ if not search in text:
2834+ return False
2835+ return True
2836+ pklog.debug("Performing apt cache based search")
2837+ values = [val.lower() for val in values]
2838+ for pkg in self._iterate_packages():
2839+ txt = pkg.name
2840+ try:
2841+ txt += pkg.candidate.raw_description.lower()
2842+ txt += pkg.candidate._translated_records.long_desc.lower()
2843+ except AttributeError:
2844+ pass
2845+ if matches(values, txt):
2846+ self._emit_visible_package(trans, filters, pkg)
2847+
2848+ def get_updates(self, trans, filters):
2849+ """Only report updates which can be installed safely: Which can depend
2850+ on the installation of additional packages but which don't require
2851+ the removal of already installed packages or block any other update.
2852+ """
2853+ def succeeds_security_update(pkg):
2854+ """
2855+ Return True if an update succeeds a previous security update
2856+
2857+ An example would be a package with version 1.1 in the security
2858+ archive and 1.1.1 in the archive of proposed updates or the
2859+ same version in both archives.
2860+ """
2861+ for version in pkg.versions:
2862+ # Only check versions between the installed and the candidate
2863+ if (pkg.installed and
2864+ apt_pkg.version_compare(version.version,
2865+ pkg.installed.version) <= 0 and
2866+ apt_pkg.version_compare(version.version,
2867+ pkg.candidate.version) > 0):
2868+ continue
2869+ for origin in version.origins:
2870+ if origin.origin in ["Debian", "Ubuntu"] and \
2871+ (origin.archive.endswith("-security") or \
2872+ origin.label == "Debian-Security") and \
2873+ origin.trusted:
2874+ return True
2875+ return False
2876+ #FIXME: Implment the basename filter
2877+ pklog.info("Get updates()")
2878+ self.cancellable = False
2879+ self.progress = 101
2880+ # Start with a safe upgrade
2881+ self._cache.upgrade(dist_upgrade=True)
2882+ for pkg in self._iterate_packages():
2883+ if not pkg.is_upgradable:
2884+ continue
2885+ # This may occur on pinned packages which have been updated to
2886+ # later version than the pinned one
2887+ if not pkg.candidate.origins:
2888+ continue
2889+ if not pkg.marked_upgrade:
2890+ #FIXME: Would be nice to all show why
2891+ self._emit_package(trans, pkg, pk_enums.INFO_BLOCKED,
2892+ force_candidate=True)
2893+ continue
2894+ # The update can be safely installed
2895+ info = pk_enums.INFO_NORMAL
2896+ # Detect the nature of the upgrade (e.g. security, enhancement)
2897+ candidate_origin = pkg.candidate.origins[0]
2898+ archive = candidate_origin.archive
2899+ origin = candidate_origin.origin
2900+ trusted = candidate_origin.trusted
2901+ label = candidate_origin.label
2902+ if origin in ["Debian", "Ubuntu"] and trusted == True:
2903+ if archive.endswith("-security") or label == "Debian-Security":
2904+ info = pk_enums.INFO_SECURITY
2905+ elif succeeds_security_update(pkg):
2906+ pklog.debug("Update of %s succeeds a security update. "
2907+ "Raising its priority." % pkg.name)
2908+ info = pk_enums.INFO_SECURITY
2909+ elif archive.endswith("-backports"):
2910+ info = pk_enums.INFO_ENHANCEMENT
2911+ elif archive.endswith("-updates"):
2912+ info = pk_enums.INFO_BUGFIX
2913+ if origin in ["Backports.org archive"] and trusted == True:
2914+ info = pk_enums.INFO_ENHANCEMENT
2915+ self._emit_package(trans, pkg, info, force_candidate=True)
2916+ self._emit_require_restart(trans)
2917+
2918+ def _emit_require_restart(self, trans):
2919+ """Emit RequireRestart if required."""
2920+ # Check for a system restart
2921+ if self.is_reboot_required():
2922+ trans.pktrans.RequireRestart(pk_enums.RESTART_SYSTEM, "")
2923+
2924+ def get_update_detail(self, trans, package_ids):
2925+ """
2926+ Implement the {backend}-get-update-details functionality
2927+ """
2928+ def get_bug_urls(changelog):
2929+ """
2930+ Create a list of urls pointing to closed bugs in the changelog
2931+ """
2932+ urls = []
2933+ for r in re.findall(MATCH_BUG_CLOSES_DEBIAN, changelog,
2934+ re.IGNORECASE | re.MULTILINE):
2935+ urls.extend([HREF_BUG_DEBIAN % bug for bug in \
2936+ re.findall(MATCH_BUG_NUMBERS, r)])
2937+ for r in re.findall(MATCH_BUG_CLOSES_UBUNTU, changelog,
2938+ re.IGNORECASE | re.MULTILINE):
2939+ urls.extend([HREF_BUG_UBUNTU % bug for bug in \
2940+ re.findall(MATCH_BUG_NUMBERS, r)])
2941+ return urls
2942+
2943+ def get_cve_urls(changelog):
2944+ """
2945+ Create a list of urls pointing to cves referred in the changelog
2946+ """
2947+ return map(lambda c: HREF_CVE % c,
2948+ re.findall(MATCH_CVE, changelog, re.MULTILINE))
2949+
2950+ pklog.info("Get update details of %s" % package_ids)
2951+ trans.progress = 0
2952+ trans.cancellable = False
2953+ trans.pktrans.status = pk_enums.STATUS_DOWNLOAD_CHANGELOG
2954+ total = len(package_ids)
2955+ count = 1
2956+ old_locale = locale.getlocale(locale.LC_TIME)
2957+ locale.setlocale(locale.LC_TIME, "C")
2958+ for pkg_id in package_ids:
2959+ self._iterate_mainloop()
2960+ trans.progress = count * 100 / total
2961+ count += 1
2962+ pkg = self._get_package_by_id(pkg_id)
2963+ # FIXME add some real data
2964+ if pkg.installed.origins:
2965+ installed_origin = pkg.installed.origins[0].label
2966+ else:
2967+ installed_origin = ""
2968+ updates = "%s;%s;%s;%s" % (pkg.name, pkg.installed.version,
2969+ pkg.installed.architecture,
2970+ installed_origin)
2971+ obsoletes = ""
2972+ vendor_url = ""
2973+ restart = "none"
2974+ update_text = u""
2975+ state = ""
2976+ issued = ""
2977+ updated = ""
2978+ #FIXME: make this more configurable. E.g. a dbus update requires
2979+ # a reboot on Ubuntu but not on Debian
2980+ if pkg.name.startswith("linux-image-") or \
2981+ pkg.name in ["libc6", "dbus"]:
2982+ restart == pk_enums.RESTART_SYSTEM
2983+ changelog_dir = apt_pkg.config.find_dir("Dir::Cache::Changelogs")
2984+ if changelog_dir == "/":
2985+ changelog_dir = os.path.join(apt_pkg.config.find_dir("Dir::"
2986+ "Cache"),
2987+ "Changelogs")
2988+ filename = os.path.join(changelog_dir,
2989+ "%s_%s.gz" % (pkg.name,
2990+ pkg.candidate.version))
2991+ changelog_raw = ""
2992+ if os.path.exists(filename):
2993+ pklog.debug("Reading changelog from cache")
2994+ changelog_file = gzip.open(filename, "rb")
2995+ try:
2996+ changelog_raw = changelog_file.read().decode("UTF-8")
2997+ except:
2998+ pass
2999+ finally:
3000+ changelog_file.close()
3001+ if not changelog_raw:
3002+ pklog.debug("Downloading changelog")
3003+ changelog_raw = pkg.get_changelog()
3004+ # The internal download error string of python-apt ist not
3005+ # provided as unicode object
3006+ if not isinstance(changelog_raw, unicode):
3007+ changelog_raw = changelog_raw.decode("UTF-8")
3008+ # Cache the fetched changelog
3009+ if not os.path.exists(changelog_dir):
3010+ os.makedirs(changelog_dir)
3011+ # Remove old cached changelogs
3012+ pattern = os.path.join(changelog_dir, "%s_*" % pkg.name)
3013+ for old_changelog in glob.glob(pattern):
3014+ os.remove(os.path.join(changelog_dir, old_changelog))
3015+ changelog_file = gzip.open(filename, mode="wb")
3016+ try:
3017+ changelog_file.write(changelog_raw.encode("UTF-8"))
3018+ finally:
3019+ changelog_file.close()
3020+ # Convert the changelog to markdown syntax
3021+ changelog = u""
3022+ for line in changelog_raw.split("\n"):
3023+ if line == "":
3024+ changelog += " \n"
3025+ else:
3026+ changelog += u" %s \n" % line
3027+ if line.startswith(pkg.candidate.source_name):
3028+ match = re.match(r"(?P<source>.+) \((?P<version>.*)\) "
3029+ "(?P<dist>.+); urgency=(?P<urgency>.+)",
3030+ line)
3031+ update_text += u"%s\n%s\n\n" % (match.group("version"),
3032+ "=" * \
3033+ len(match.group("version")))
3034+ elif line.startswith(" "):
3035+ update_text += u" %s \n" % line
3036+ elif line.startswith(" --"):
3037+ #FIXME: Add %z for the time zone - requires Python 2.6
3038+ update_text += u" \n"
3039+ match = re.match("^ -- (?P<maintainer>.+) (?P<mail><.+>) "
3040+ "(?P<date>.+) (?P<offset>[-\+][0-9]+)$",
3041+ line)
3042+ if not match:
3043+ continue
3044+ try:
3045+ date = datetime.datetime.strptime(match.group("date"),
3046+ "%a, %d %b %Y "
3047+ "%H:%M:%S")
3048+ except ValueError:
3049+ continue
3050+ issued = date.isoformat()
3051+ if not updated:
3052+ updated = date.isoformat()
3053+ if issued == updated:
3054+ updated = ""
3055+ bugzilla_url = ";;".join(get_bug_urls(changelog))
3056+ cve_url = ";;".join(get_cve_urls(changelog))
3057+ trans.emit_update_detail(pkg_id, updates, obsoletes, vendor_url,
3058+ bugzilla_url, cve_url, restart,
3059+ update_text, changelog,
3060+ state, issued, updated)
3061+ locale.setlocale(locale.LC_TIME, old_locale)
3062+
3063+ def get_details(self, trans, package_ids):
3064+ """Implement org.freedesktop.PackageKit.Transaction.GetDetails()"""
3065+ trans.progress = 101
3066+
3067+ for pkg_id in package_ids:
3068+ version = self._get_version_by_id(pkg_id)
3069+ #FIXME: We need more fine grained license information!
3070+ origins = version.origins
3071+ if (origins and
3072+ origins[0].component in ["main", "universe"] and
3073+ origins[0].origin in ["Debian", "Ubuntu"]):
3074+ license = "free"
3075+ else:
3076+ license = "unknown"
3077+ group = self._get_package_group(version.package)
3078+ trans.emit_details(pkg_id, license, group, version.description,
3079+ version.homepage, version.size)
3080+
3081+ def get_packages(self, trans, filters):
3082+ """Implement org.freedesktop.PackageKit.Transaction.GetPackages()"""
3083+ pklog.info("Get all packages")
3084+ self.progress = 101
3085+
3086+ for pkg in self._iterate_packages():
3087+ if self._is_package_visible(pkg, filters):
3088+ self._emit_package(trans, pkg)
3089+
3090+ def resolve(self, trans, filters, packages):
3091+ """Implement org.freedesktop.PackageKit.Transaction.Resolve()"""
3092+ pklog.info("Resolve()")
3093+ trans.status = aptd_enums.STATUS_QUERY
3094+ trans.progress = 101
3095+ self.cancellable = False
3096+
3097+ for name_raw in packages:
3098+ #FIXME: Python-apt doesn't allow unicode as key. See #542965
3099+ name = str(name_raw)
3100+ try:
3101+ # Check if the name is a valid package id
3102+ version = self._get_version_by_id(name)
3103+ except ValueError:
3104+ pass
3105+ else:
3106+ if self._package_is_visible(version.package, filters):
3107+ self._emit_pkg_version(trans, version)
3108+ continue
3109+ # The name seems to be a normal name
3110+ try:
3111+ self._emit_visible_package(trans, filters, self._cache[name])
3112+ except KeyError:
3113+ raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
3114+ "Package name %s could not be "
3115+ "resolved.", name)
3116+
3117+ def get_depends(self, trans, filters, package_ids, recursive):
3118+ """Emit all dependencies of the given package ids.
3119+
3120+ Doesn't support recursive dependency resolution.
3121+ """
3122+ def emit_blocked_dependency(base_dependency, pkg=None,
3123+ filters=""):
3124+ """Send a blocked package signal for the given
3125+ apt.package.BaseDependency.
3126+ """
3127+ if FILTER_INSTALLED in filters:
3128+ return
3129+ if pkg:
3130+ summary = pkg.candidate.summary
3131+ try:
3132+ filters.remove(FILTER_NOT_INSTALLED)
3133+ except ValueError:
3134+ pass
3135+ if not self._is_package_visible(pkg, filters):
3136+ return
3137+ else:
3138+ summary = u""
3139+ if base_dependency.relation:
3140+ version = "%s%s" % (base_dependency.relation,
3141+ base_dependency.version)
3142+ else:
3143+ version = base_dependency.version
3144+ trans.emit_package("%s;%s;;" % (base_dependency.name, version),
3145+ pk_enums.INFO_BLOCKED, summary)
3146+
3147+ def check_dependency(pkg, base_dep):
3148+ """Check if the given apt.package.Package can satisfy the
3149+ BaseDepenendcy and emit the corresponding package signals.
3150+ """
3151+ if not self._is_package_visible(pkg, filters):
3152+ return
3153+ if base_dep.version:
3154+ satisfied = False
3155+ # Sort the version list to check the installed
3156+ # and candidate before the other ones
3157+ ver_list = list(pkg.versions)
3158+ if pkg.installed:
3159+ ver_list.remove(pkg.installed)
3160+ ver_list.insert(0, pkg.installed)
3161+ if pkg.candidate:
3162+ ver_list.remove(pkg.candidate)
3163+ ver_list.insert(0, pkg.candidate)
3164+ for dep_ver in ver_list:
3165+ if apt_pkg.check_dep(dep_ver.version,
3166+ base_dep.relation,
3167+ base_dep.version):
3168+ self._emit_pkg_version(trans, dep_ver)
3169+ satisfied = True
3170+ break
3171+ if not satisfied:
3172+ emit_blocked_dependency(base_dep, pkg, filters)
3173+ else:
3174+ self._emit_package(trans, pkg)
3175+
3176+ # Setup the transaction
3177+ pklog.info("Get depends (%s,%s,%s)" % (filter, package_ids, recursive))
3178+ self.status = aptd_enums.STATUS_RESOLVING_DEP
3179+ trans.progress = 101
3180+ self.cancellable = True
3181+
3182+ dependency_types = ["PreDepends", "Depends"]
3183+ if apt_pkg.config["APT::Install-Recommends"]:
3184+ dependency_types.append("Recommends")
3185+ for id in package_ids:
3186+ version = self._get_version_by_id(id)
3187+ for dependency in version.get_dependencies(*dependency_types):
3188+ # Walk through all or_dependencies
3189+ for base_dep in dependency.or_dependencies:
3190+ if self._cache.is_virtual_package(base_dep.name):
3191+ # Check each proivider of a virtual package
3192+ for provider in \
3193+ self._cache.get_providing_packages(base_dep.name):
3194+ check_dependency(provider, base_dep)
3195+ elif base_dep.name in self._cache:
3196+ check_dependency(self._cache[base_dep.name], base_dep)
3197+ else:
3198+ # The dependency does not exist
3199+ emit_blocked_dependency(trans, base_dep, filters=filters)
3200+
3201+ def get_requires(self, trans, filters, package_ids, recursive):
3202+ """Emit all packages which depend on the given ids.
3203+
3204+ Recursive searching is not supported.
3205+ """
3206+ pklog.info("Get requires (%s,%s,%s)" % (filter, package_ids, recursive))
3207+ self.status = aptd_enums.STATUS_RESOLVING_DEP
3208+ self.progress = 101
3209+ self.cancellable = True
3210+ for id in package_ids:
3211+ version = self._get_version_by_id(id)
3212+ for pkg in self._iterate_packages():
3213+ if not self._is_package_visible(pkg, filters):
3214+ continue
3215+ if pkg.is_installed:
3216+ pkg_ver = pkg.installed
3217+ elif pkg.candidate:
3218+ pkg_ver = pkg.candidate
3219+ for dependency in pkg_ver.dependencies:
3220+ satisfied = False
3221+ for base_dep in dependency.or_dependencies:
3222+ if version.package.name == base_dep.name or \
3223+ base_dep.name in version.provides:
3224+ satisfied = True
3225+ break
3226+ if satisfied:
3227+ self._emit_package(trans, pkg)
3228+ break
3229+
3230+ def download_packages(self, trans, store_in_cache, package_ids):
3231+ """Implement the DownloadPackages functionality.
3232+
3233+ The store_in_cache parameter gets ignored.
3234+ """
3235+ def get_download_details(ids):
3236+ """Calculate the start and end point of a package download
3237+ progress.
3238+ """
3239+ total = 0
3240+ downloaded = 0
3241+ versions = []
3242+ # Check if all ids are vaild and calculate the total download size
3243+ for id in ids:
3244+ pkg_ver = self._get_version_by_id(id)
3245+ if not pkg_ver.downloadable:
3246+ raise TransactionFailed(aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED,
3247+ "package %s isn't downloadable" % id)
3248+ total += pkg_ver.size
3249+ versions.append((id, pkg_ver))
3250+ for id, ver in versions:
3251+ start = downloaded * 100 / total
3252+ end = start + ver.size * 100 / total
3253+ yield id, ver, start, end
3254+ downloaded += ver.size
3255+ pklog.info("Downloading packages: %s" % package_ids)
3256+ trans.status = aptd_enums.STATUS_DOWNLOADING
3257+ trans.cancellable = True
3258+ trans.progress = 10
3259+ # Check the destination directory
3260+ if store_in_cache:
3261+ dest = apt_pkg.config.find_dir("Dir::Cache::archives")
3262+ else:
3263+ dest = tempfile.mkdtemp(prefix="aptdaemon-download")
3264+ if not os.path.isdir(dest) or not os.access(dest, os.W_OK):
3265+ raise TransactionFailed(aptd_enums.ERROR_INTERNAL_ERROR,
3266+ "The directory '%s' is not writable" % dest)
3267+ # Start the download
3268+ for id, ver, start, end in get_download_details(package_ids):
3269+ progress = DaemonAcquireProgress(trans, start, end)
3270+ self._emit_pkg_version(trans, ver, pk_enums.INFO_DOWNLOADING)
3271+ try:
3272+ ver.fetch_binary(dest, progress)
3273+ except Exception as error:
3274+ raise TransactionFailed(aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED,
3275+ str(error))
3276+ else:
3277+ trans.emit_files(id,
3278+ os.path.join(dest,
3279+ os.path.basename(ver.filename)))
3280+ self._emit_pkg_version(trans, ver, pk_enums.INFO_FINISHED)
3281+
3282+ def get_files(self, trans, package_ids):
3283+ """Emit the Files signal which includes the files included in a package
3284+ Apt only supports this for installed packages
3285+ """
3286+ for id in package_ids:
3287+ pkg = self._get_package_by_id(id)
3288+ files = ";".join(self._get_installed_files(pkg))
3289+ trans.emit_files(id, files)
3290+
3291+ def what_provides(self, trans, filters, type, values):
3292+ """Emit all dependencies of the given package ids.
3293+
3294+ Doesn't support recursive dependency resolution.
3295+ """
3296+ self._init_plugins()
3297+
3298+ supported_type = False
3299+
3300+ # run plugins
3301+ for plugin in self._plugins.get("what_provides", []):
3302+ pklog.debug("calling what_provides plugin %s %s" % (str(plugin), str(filters)))
3303+ for search_item in values:
3304+ try:
3305+ for package in plugin(self._cache, type, search_item):
3306+ self._emit_visible_package(trans, filters, package)
3307+ supported_type = True
3308+ except NotImplementedError:
3309+ pass # keep supported_type as False
3310+
3311+ if not supported_type and type != pk_enums.PROVIDES_ANY:
3312+ # none of the plugins felt responsible for this type
3313+ raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
3314+ "Query type '%s' is not supported" % type)
3315+
3316+
3317+ # Helpers
3318+
3319+ def _get_id_from_version(self, version):
3320+ """Return the package id of an apt.package.Version instance."""
3321+ if version.origins:
3322+ origin = version.origins[0].label
3323+ else:
3324+ origin = ""
3325+ if version.architecture == apt_pkg.config.find("APT::Architecture") or \
3326+ version.architecture == "all":
3327+ name = version.package.name
3328+ else:
3329+ name = version.package.name.split(":")[0]
3330+ id = "%s;%s;%s;%s" % (name, version.version,
3331+ version.architecture, origin)
3332+ return id
3333+
3334+ def _emit_package(self, trans, pkg, info=None, force_candidate=False):
3335+ """
3336+ Send the Package signal for a given apt package
3337+ """
3338+ if (not pkg.is_installed or force_candidate) and pkg.candidate:
3339+ self._emit_pkg_version(trans, pkg.candidate, info)
3340+ elif pkg.is_installed:
3341+ self._emit_pkg_version(trans, pkg.installed, info)
3342+ else:
3343+ pklog.debug("Package %s hasn't got any version." % pkg.name)
3344+
3345+ def _emit_pkg_version(self, trans, version, info=None):
3346+ """Emit the Package signal of the given apt.package.Version."""
3347+ id = self._get_id_from_version(version)
3348+ section = version.section.split("/")[-1]
3349+ if not info:
3350+ if version == version.package.installed:
3351+ if section == "metapackages":
3352+ info = pk_enums.INFO_COLLECTION_INSTALLED
3353+ else:
3354+ info = pk_enums.INFO_INSTALLED
3355+ else:
3356+ if section == "metapackages":
3357+ info = pk_enums.INFO_COLLECTION_AVAILABLE
3358+ else:
3359+ info = pk_enums.INFO_AVAILABLE
3360+ trans.emit_package(info, id, version.summary)
3361+
3362+ def _emit_all_visible_pkg_versions(self, trans, filters, pkg):
3363+ """Emit all available versions of a package."""
3364+ if self._is_package_visible(pkg, filters):
3365+ if pk_enums.FILTER_NEWEST in filters:
3366+ if pkg.candidate:
3367+ self._emit_pkg_version(trans, pkg.candidate)
3368+ elif pkg.installed:
3369+ self._emit_pkg_version(trans, pkg.installed)
3370+ else:
3371+ for version in pkg.versions:
3372+ self._emit_pkg_version(trans, version)
3373+
3374+ def _emit_visible_package(self, trans, filters, pkg, info=None):
3375+ """
3376+ Filter and emit a package
3377+ """
3378+ if self._is_package_visible(pkg, filters):
3379+ self._emit_package(trans, pkg, info)
3380+
3381+ def _emit_visible_packages(self, trans, filters, pkgs, info=None):
3382+ """
3383+ Filter and emit packages
3384+ """
3385+ for pkg in pkgs:
3386+ if self._is_package_visible(pkg, filters):
3387+ self._emit_package(trans, pkg, info)
3388+
3389+ def _emit_visible_packages_by_name(self, trans, filters, pkgs, info=None):
3390+ """
3391+ Find the packages with the given namens. Afterwards filter and emit
3392+ them
3393+ """
3394+ for name_raw in pkgs:
3395+ #FIXME: Python-apt doesn't allow unicode as key. See #542965
3396+ name = str(name_raw)
3397+ if self._cache.has_key(name) and \
3398+ self._is_package_visible(self._cache[name], filters):
3399+ self._emit_package(trans, self._cache[name], info)
3400+
3401+ def _is_package_visible(self, pkg, filters):
3402+ """
3403+ Return True if the package should be shown in the user interface
3404+ """
3405+ if filters == [pk_enums.FILTER_NONE]:
3406+ return True
3407+ for filter in filters:
3408+ if (filter == pk_enums.FILTER_INSTALLED and not pkg.is_installed) or \
3409+ (filter == pk_enums.FILTER_NOT_INSTALLED and pkg.is_installed) or \
3410+ (filter == pk_enums.FILTER_SUPPORTED and not \
3411+ self._is_package_supported(pkg)) or \
3412+ (filter == pk_enums.FILTER_NOT_SUPPORTED and \
3413+ self._is_package_supported(pkg)) or \
3414+ (filter == pk_enums.FILTER_FREE and not self._is_package_free(pkg)) or \
3415+ (filter == pk_enums.FILTER_NOT_FREE and \
3416+ not self._is_package_not_free(pkg)) or \
3417+ (filter == pk_enums.FILTER_GUI and not self._has_package_gui(pkg)) or \
3418+ (filter == pk_enums.FILTER_NOT_GUI and self._has_package_gui(pkg)) or \
3419+ (filter == pk_enums.FILTER_COLLECTIONS and not \
3420+ self._is_package_collection(pkg)) or \
3421+ (filter == pk_enums.FILTER_NOT_COLLECTIONS and \
3422+ self._is_package_collection(pkg)) or\
3423+ (filter == pk_enums.FILTER_DEVELOPMENT and not \
3424+ self._is_package_devel(pkg)) or \
3425+ (filter == pk_enums.FILTER_NOT_DEVELOPMENT and \
3426+ self._is_package_devel(pkg)):
3427+ return False
3428+ return True
3429+
3430+ def _is_package_not_free(self, pkg):
3431+ """
3432+ Return True if we can be sure that the package's license isn't any
3433+ free one
3434+ """
3435+ if not pkg.candidate:
3436+ return False
3437+ origins = pkg.candidate.origins
3438+ return (origins and
3439+ ((origins[0].origin == "Ubuntu" and
3440+ candidate[0].component in ["multiverse", "restricted"]) or
3441+ (origins[0].origin == "Debian" and
3442+ origins[0].component in ["contrib", "non-free"])) and
3443+ origins[0].trusted)
3444+
3445+ def _is_package_collection(self, pkg):
3446+ """
3447+ Return True if the package is a metapackge
3448+ """
3449+ section = pkg.section.split("/")[-1]
3450+ return section == "metapackages"
3451+
3452+ def _is_package_free(self, pkg):
3453+ """
3454+ Return True if we can be sure that the package has got a free license
3455+ """
3456+ if not pkg.candidate:
3457+ return False
3458+ origins = pkg.candidate.origins
3459+ return (origins and
3460+ ((origins[0].origin == "Ubuntu" and
3461+ candidate[0].component in ["main", "universe"]) or
3462+ (origins[0].origin == "Debian" and
3463+ origins[0].component == "main")) and
3464+ origins[0].trusted)
3465+
3466+ def _has_package_gui(self, pkg):
3467+ #FIXME: should go to a modified Package class
3468+ #FIXME: take application data into account. perhaps checking for
3469+ # property in the xapian database
3470+ return pkg.section.split('/')[-1].lower() in ['x11', 'gnome', 'kde']
3471+
3472+ def _is_package_devel(self, pkg):
3473+ #FIXME: should go to a modified Package class
3474+ return pkg.name.endswith("-dev") or pkg.name.endswith("-dbg") or \
3475+ pkg.section.split('/')[-1].lower() in ['devel', 'libdevel']
3476+
3477+ def _is_package_supported(self, pkg):
3478+ if not pkg.candidate:
3479+ return False
3480+ origins = pkg.candidate.origins
3481+ return (origins and
3482+ ((origins[0].origin == "Ubuntu" and
3483+ candidate[0].component in ["main", "restricted"]) or
3484+ (origins[0].origin == "Debian" and
3485+ origins[0].component == "main")) and
3486+ origins[0].trusted)
3487+
3488+ def _get_package_by_id(self, id):
3489+ """Return the apt.package.Package corresponding to the given
3490+ package id.
3491+
3492+ If the package isn't available error out.
3493+ """
3494+ version = self._get_version_by_id(id)
3495+ return version.package
3496+
3497+ def _get_version_by_id(self, id):
3498+ """Return the apt.package.Version corresponding to the given
3499+ package id.
3500+
3501+ If the version isn't available error out.
3502+ """
3503+ name, version_string, arch, data = id.split(";", 4)
3504+ if arch and arch != apt_pkg.config.find("APT::Architecture") and \
3505+ arch != "all":
3506+ name += ":%s" % arch
3507+ try:
3508+ pkg = self._cache[name]
3509+ except KeyError:
3510+ raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
3511+ "There isn't any package named %s",
3512+ name)
3513+ #FIXME:This requires a not yet released fix in python-apt
3514+ try:
3515+ version = pkg.versions[version_string]
3516+ except:
3517+ raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
3518+ "Verion %s doesn't exist",
3519+ version_string)
3520+ if version.architecture != arch:
3521+ raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
3522+ "Version %s of %s isn't available "
3523+ "for architecture %s",
3524+ pkg.name, version.version, arch)
3525+ return version
3526+
3527+ def _get_installed_files(self, pkg):
3528+ """
3529+ Return the list of unicode names of the files which have
3530+ been installed by the package
3531+
3532+ This method should be obsolete by the apt.package.Package.installedFiles
3533+ attribute as soon as the consolidate branch of python-apt gets merged
3534+ """
3535+ path = os.path.join(apt_pkg.config["Dir"],
3536+ "var/lib/dpkg/info/%s.list" % pkg.name)
3537+ try:
3538+ list = open(path)
3539+ files = list.read().decode().split("\n")
3540+ list.close()
3541+ except:
3542+ return []
3543+ return files
3544+
3545+ def _get_package_group(self, pkg):
3546+ """
3547+ Return the packagekit group corresponding to the package's section
3548+ """
3549+ section = pkg.section.split("/")[-1]
3550+ if SECTION_GROUP_MAP.has_key(section):
3551+ return SECTION_GROUP_MAP[section]
3552+ else:
3553+ pklog.debug("Unkown package section %s of %s" % (pkg.section,
3554+ pkg.name))
3555+ return pk_enums.GROUP_UNKNOWN
3556+
3557+ def _init_plugins(self):
3558+ """Initialize PackageKit apt backend plugins.
3559+
3560+ Do nothing if plugins are already initialized.
3561+ """
3562+ if self._plugins is not None:
3563+ return
3564+
3565+ if not pkg_resources:
3566+ return
3567+
3568+ self._plugins = {} # plugin_name -> [plugin_fn1, ...]
3569+
3570+ # just look in standard Python paths for now
3571+ dists, errors = pkg_resources.working_set.find_plugins(pkg_resources.Environment())
3572+ for dist in dists:
3573+ pkg_resources.working_set.add(dist)
3574+ for plugin_name in ["what_provides"]:
3575+ for entry_point in pkg_resources.iter_entry_points(
3576+ "packagekit.apt.plugins", plugin_name):
3577+ try:
3578+ plugin = entry_point.load()
3579+ except Exception as e:
3580+ pklog.warning("Failed to load %s from plugin %s: %s" % (
3581+ plugin_name, str(entry_point.dist), str(e)))
3582+ continue
3583+ pklog.debug("Loaded %s from plugin %s" % (
3584+ plugin_name, str(entry_point.dist)))
3585+ self._plugins.setdefault(plugin_name, []).append(plugin)
3586+
3587+ def _apply_changes(self, trans, fetch_range=(15, 50),
3588+ install_range=(50, 90)):
3589+ """Apply changes and emit RequireRestart accordingly."""
3590+ aptdaemon.worker.AptWorker._apply_changes(self, trans,
3591+ fetch_range,
3592+ install_range)
3593+ if (hasattr(trans, "pktrans") and
3594+ (trans.role == aptd_enums.ROLE_UPGRADE_SYSTEM or
3595+ trans.packages[aptd_enums.PKGS_UPGRADE] or
3596+ trans.depends[aptd_enums.PKGS_UPGRADE])):
3597+ self._emit_require_restart(trans)
3598+
3599+
3600+if META_RELEASE_SUPPORT:
3601+
3602+ class GMetaRelease(GObject.GObject, MetaReleaseCore):
3603+
3604+ __gsignals__ = {"download-done": (GObject.SignalFlags.RUN_FIRST,
3605+ None,
3606+ ())}
3607+
3608+ def __init__(self):
3609+ GObject.GObject.__init__(self)
3610+ MetaReleaseCore.__init__(self, False, False)
3611+
3612+ def download(self):
3613+ MetaReleaseCore.download(self)
3614+ self.emit("download-done")
3615+
3616+
3617+def get_pk_exit_enum(enum):
3618+ try:
3619+ return MAP_EXIT_ENUM[enum]
3620+ except KeyError:
3621+ return pk_enums.EXIT_UNKNOWN
3622+
3623+def get_pk_status_enum(enum):
3624+ try:
3625+ return MAP_STATUS_ENUM[enum]
3626+ except KeyError:
3627+ return pk_enums.STATUS_UNKNOWN
3628+
3629+def get_pk_package_enum(enum):
3630+ try:
3631+ return MAP_PACKAGE_ENUM[enum]
3632+ except KeyError:
3633+ return pk_enums.INFO_UNKNOWN
3634+
3635+def get_pk_error_enum(enum):
3636+ try:
3637+ return MAP_ERROR_ENUM[enum]
3638+ except KeyError:
3639+ return pk_enums.ERROR_UNKNOWN
3640+
3641+def get_aptd_package_id(pk_id):
3642+ """Convert a PackageKit Package ID to the apt syntax.
3643+ e.g. xterm;235;i386;installed to xterm:i386=235
3644+ """
3645+ name, version, arch, data = pk_id.split(";")
3646+ id = name
3647+ if arch != apt_pkg.config.find("APT::Architecture") and arch != "all":
3648+ id += ":%s" % arch
3649+ if version:
3650+ id += "=%s" % version
3651+ return id
3652+
3653+def get_pk_package_id(pk_id, data=""):
3654+ """Convert an AptDaemon package ID to the PackageKit syntax.
3655+ e.g. xterm:i368=235; to xterm;235;i386;installed
3656+ """
3657+ #FIXME add arch support
3658+ name, version, release = \
3659+ aptdaemon.worker.AptWorker._split_package_id(pk_id)
3660+ try:
3661+ name, arch = name.split(":", 1)
3662+ except ValueError:
3663+ arch = ""
3664+ if version is None:
3665+ version = ""
3666+ if release is None:
3667+ release = ""
3668+ return "%s;%s;%s;%s" % (name, version, arch, data or release)
3669+
3670+def defer_idle(func, *args):
3671+ func(*args)
3672+ return False
3673+
3674+if __name__ == '__main__':
3675+ main()
3676+
3677+# vim: ts=4 et sts=4
3678
3679=== added directory '.pc/fix-lp-971748.patch'
3680=== added directory '.pc/fix-lp-971748.patch/aptdaemon'
3681=== added file '.pc/fix-lp-971748.patch/aptdaemon/networking.py'
3682--- .pc/fix-lp-971748.patch/aptdaemon/networking.py 1970-01-01 00:00:00 +0000
3683+++ .pc/fix-lp-971748.patch/aptdaemon/networking.py 2012-08-11 01:29:19 +0000
3684@@ -0,0 +1,262 @@
3685+# networking - Monitor the network status
3686+#
3687+# Copyright (c) 2010 Mohamed Amine IL Idrissi
3688+# Copyright (c) 2011 Canonical
3689+# Copyright (c) 2011 Sebastian Heinlein
3690+#
3691+# Author: Alex Chiang <achiang@canonical.com>
3692+# Michael Vogt <michael.vogt@ubuntu.com>
3693+# Mohamed Amine IL Idrissi <ilidrissiamine@gmail.com>
3694+# Sebastian Heinlein <devel@glatzor.de>
3695+
3696+# This program is free software; you can redistribute it and/or
3697+# modify it under the terms of the GNU General Public License as
3698+# published by the Free Software Foundation; either version 2 of the
3699+# License, or (at your option) any later version.
3700+#
3701+# This program is distributed in the hope that it will be useful,
3702+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3703+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3704+# GNU General Public License for more details.
3705+#
3706+# You should have received a copy of the GNU General Public License
3707+# along with this program; if not, write to the Free Software
3708+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
3709+# USA
3710+
3711+import defer
3712+from defer import Deferred, inline_callbacks, return_value
3713+from gi.repository import GObject
3714+from gi.repository import Gio
3715+import dbus
3716+from dbus.mainloop.glib import DBusGMainLoop
3717+DBusGMainLoop(set_as_default=True)
3718+import logging
3719+import os
3720+import packagekit.enums as pk_enums
3721+
3722+log = logging.getLogger("AptDaemon.NetMonitor")
3723+
3724+
3725+class NetworkMonitorBase(GObject.GObject):
3726+
3727+ """Check the network state."""
3728+
3729+ __gsignals__ = {"network-state-changed": (GObject.SignalFlags.RUN_FIRST,
3730+ None,
3731+ (GObject.TYPE_STRING,))}
3732+
3733+ def __init__(self):
3734+ log.debug("Initializing network monitor")
3735+ GObject.GObject.__init__(self)
3736+ self._state = pk_enums.NETWORK_ONLINE
3737+
3738+ def _set_state(self, enum):
3739+ if self._state != enum:
3740+ log.debug("Network state changed: %s", enum)
3741+ self._state = enum
3742+ self.emit("network-state-changed", enum)
3743+
3744+ def _get_state(self):
3745+ return self._state
3746+
3747+ state = property(_get_state, _set_state)
3748+
3749+ @inline_callbacks
3750+ def get_network_state(self):
3751+ """Update the network state."""
3752+ return_value(self._state)
3753+
3754+
3755+class ProcNetworkMonitor(NetworkMonitorBase):
3756+
3757+ """Use the route information of the proc filesystem to detect
3758+ the network state.
3759+ """
3760+
3761+ def __init__(self):
3762+ log.debug("Initializing proc based network monitor")
3763+ NetworkMonitorBase.__init__(self)
3764+ self._state = pk_enums.NETWORK_OFFLINE
3765+ self._file = Gio.File.new_for_path("/proc/net/route")
3766+ self._monitor = Gio.File.monitor(self._file,
3767+ Gio.FileMonitorFlags.NONE,
3768+ None)
3769+ self._monitor.connect("changed",
3770+ self._on_route_file_changed)
3771+
3772+ def _on_route_file_changed(self, *args):
3773+ self.state = self._parse_route_file()
3774+
3775+ def _parse_route_file(self):
3776+ """Parse the route file - taken from PackageKit"""
3777+ with open("/proc/net/route") as route_file:
3778+ for line in route_file.readlines():
3779+ rows = line.split("\t")
3780+ # The header line?
3781+ if rows[0] == "Iface":
3782+ continue
3783+ # A loopback device?
3784+ elif rows[0] == "lo":
3785+ continue
3786+ # Correct number of rows?
3787+ elif len(rows) != 11:
3788+ continue
3789+ # The route is a default gateway
3790+ elif rows[1] == "00000000":
3791+ break
3792+ # A gateway is set
3793+ elif rows[2] != "00000000":
3794+ break
3795+ else:
3796+ return pk_enums.NETWORK_OFFLINE
3797+ return pk_enums.NETWORK_ONLINE
3798+
3799+ @inline_callbacks
3800+ def get_network_state(self):
3801+ """Update the network state."""
3802+ self.state = self._parse_route_file()
3803+
3804+
3805+class NetworkManagerMonitor(NetworkMonitorBase):
3806+
3807+ """Use NetworkManager to monitor network state."""
3808+
3809+ NM_DBUS_IFACE = "org.freedesktop.NetworkManager"
3810+ NM_ACTIVE_CONN_DBUS_IFACE = NM_DBUS_IFACE + ".Connection.Active"
3811+ NM_DEVICE_DBUS_IFACE = NM_DBUS_IFACE + ".Device"
3812+
3813+ # The device type is unknown
3814+ NM_DEVICE_TYPE_UNKNOWN = 0
3815+ # The device is wired Ethernet device
3816+ NM_DEVICE_TYPE_ETHERNET = 1
3817+ # The device is an 802.11 WiFi device
3818+ NM_DEVICE_TYPE_WIFI = 2
3819+ # The device is a GSM-based cellular WAN device
3820+ NM_DEVICE_TYPE_GSM = 3
3821+ # The device is a CDMA/IS-95-based cellular WAN device
3822+ NM_DEVICE_TYPE_CDMA = 4
3823+
3824+ def __init__(self):
3825+ log.debug("Initializing NetworkManager monitor")
3826+ NetworkMonitorBase.__init__(self)
3827+ self._state = pk_enums.NETWORK_UNKNOWN
3828+ self.bus = dbus.SystemBus()
3829+ self.proxy = self.bus.get_object("org.freedesktop.NetworkManager",
3830+ "/org/freedesktop/NetworkManager")
3831+ self.proxy.connect_to_signal("PropertiesChanged",
3832+ self._on_nm_properties_changed,
3833+ dbus_interface=self.NM_DBUS_IFACE)
3834+ self.bus.add_signal_receiver(self._on_nm_active_conn_props_changed,
3835+ signal_name="PropertiesChanged",
3836+ dbus_interface=self.NM_ACTIVE_CONN_DBUS_IFACE)
3837+
3838+ @staticmethod
3839+ def get_dbus_property(proxy, interface, property):
3840+ """Small helper to get the property value of a dbus object."""
3841+ props = dbus.Interface(proxy, "org.freedesktop.DBus.Properties")
3842+ deferred = Deferred()
3843+ props.Get(interface, property,
3844+ reply_handler=deferred.callback,
3845+ error_handler=deferred.errback)
3846+ return deferred
3847+
3848+ @inline_callbacks
3849+ def _on_nm_properties_changed(self, props):
3850+ """Callback if NetworkManager properties changed."""
3851+ if "ActiveConnections" in props:
3852+ if not props["ActiveConnections"]:
3853+ log.debug("There aren't any active connections")
3854+ self.state = pk_enums.NETWORK_OFFLINE
3855+ else:
3856+ self.state = yield self.get_network_state()
3857+
3858+ @inline_callbacks
3859+ def _on_nm_active_conn_props_changed(self, props):
3860+ """Callback if properties of the active connection changed."""
3861+ if not "Default" in props:
3862+ raise StopIteration
3863+ self.state = yield self.get_network_state()
3864+
3865+ @inline_callbacks
3866+ def get_network_state(self):
3867+ """Query NetworkManager about the network state."""
3868+ state = pk_enums.NETWORK_UNKNOWN
3869+ try:
3870+ active_conns = yield self.get_dbus_property(self.proxy,
3871+ self.NM_DBUS_IFACE,
3872+ "ActiveConnections")
3873+ except dbus.DBusException:
3874+ log.warning("Failed to determinate network state")
3875+ return_value(state)
3876+
3877+ for conn in active_conns:
3878+ conn_obj = self.bus.get_object(self.NM_DBUS_IFACE, conn)
3879+ try:
3880+ is_default = yield self.get_dbus_property(conn_obj,
3881+ self.NM_ACTIVE_CONN_DBUS_IFACE,
3882+ "Default")
3883+ if not is_default:
3884+ continue
3885+ devs = yield self.get_dbus_property(conn_obj,
3886+ self.NM_ACTIVE_CONN_DBUS_IFACE,
3887+ "Devices")
3888+ except dbus.DBusException:
3889+ log.warning("Failed to determinate network state")
3890+ break
3891+ priority_device_type = -1
3892+ for dev in devs:
3893+ try:
3894+ dev_obj = self.bus.get_object(self.NM_DBUS_IFACE, dev)
3895+ dev_type = yield self.get_dbus_property(dev_obj,
3896+ self.NM_DEVICE_DBUS_IFACE,
3897+ "DeviceType")
3898+ except dbus.DBusException:
3899+ log.warning("Failed to determinate network state")
3900+ return_value(pk_enums.NETWORK_UNKNOWN)
3901+ # prioterizse device types, since a bridged GSM/CDMA connection
3902+ # should be returned as a GSM/CDMA one
3903+ # The NM_DEVICE_TYPE_* enums are luckly ordered in this sense.
3904+ if dev_type <= priority_device_type:
3905+ continue
3906+ priority_device_type = dev_type
3907+
3908+ if dev_type in (self.NM_DEVICE_TYPE_GSM,
3909+ self.NM_DEVICE_TYPE_CDMA):
3910+ state = pk_enums.NETWORK_MOBILE
3911+ elif dev_type == self.NM_DEVICE_TYPE_ETHERNET:
3912+ state = pk_enums.NETWORK_WIRED
3913+ elif dev_type == self.NM_DEVICE_TYPE_WIFI:
3914+ state = pk_enums.NETWORK_WIFI
3915+ elif dev_type == self.NM_DEVICE_TYPE_UNKNOWN:
3916+ state = pk_enums.NETWORK_OFFLINE
3917+ else:
3918+ state = pk_enums.NETWORK_ONLINE
3919+ return_value(state)
3920+
3921+
3922+def get_network_monitor(fallback=False):
3923+ """Return a network monitor."""
3924+ if fallback:
3925+ return ProcNetworkMonitor()
3926+ try:
3927+ return NetworkManagerMonitor()
3928+ except dbus.DBusException:
3929+ pass
3930+ if os.path.exists("/proc/net/route"):
3931+ return ProcNetworkMonitor()
3932+ return NetworkMonitorBase()
3933+
3934+
3935+if __name__ == "__main__":
3936+ @inline_callbacks
3937+ def _call_monitor():
3938+ state = yield monitor.get_network_state()
3939+ print("Initial network state: %s" % state)
3940+ log_handler = logging.StreamHandler()
3941+ log.addHandler(log_handler)
3942+ log.setLevel(logging.DEBUG)
3943+ monitor = get_network_monitor(True)
3944+ _call_monitor()
3945+ loop = GObject.MainLoop()
3946+ loop.run()
3947
3948=== added file '.pc/fix-lp-971748.patch/aptdaemon/pkcompat.py'
3949--- .pc/fix-lp-971748.patch/aptdaemon/pkcompat.py 1970-01-01 00:00:00 +0000
3950+++ .pc/fix-lp-971748.patch/aptdaemon/pkcompat.py 2012-08-11 01:29:19 +0000
3951@@ -0,0 +1,2940 @@
3952+#!/usr/bin/env python
3953+# -*- coding: utf-8 -*-
3954+"""
3955+Provides a limited compatibility layer to PackageKit
3956+
3957+Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
3958+Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
3959+Copyright (C) 2008-2011 Sebastian Heinlein <glatzor@ubuntu.com>
3960+
3961+Licensed under the GNU General Public License Version 2
3962+
3963+This program is free software; you can redistribute it and/or modify
3964+it under the terms of the GNU General Public License as published by
3965+the Free Software Foundation; either version 2 of the License, or
3966+(at your option) any later version.
3967+"""
3968+
3969+__author__ = "Sebastian Heinlein <devel@glatzor.de>"
3970+
3971+import datetime
3972+import glob
3973+import gzip
3974+import locale
3975+import logging
3976+import os
3977+import re
3978+import subprocess
3979+import tempfile
3980+import time
3981+import traceback
3982+import uuid
3983+
3984+import apt
3985+import apt_pkg
3986+from defer import inline_callbacks, return_value
3987+from defer.utils import dbus_deferred_method
3988+import dbus
3989+from gi.repository import GObject
3990+import lsb_release
3991+import packagekit.enums as pk_enums
3992+
3993+# for optional plugin support
3994+try:
3995+ import pkg_resources
3996+except ImportError:
3997+ pkg_resources = None
3998+
3999+from aptdaemon import policykit1
4000+import aptdaemon.core
4001+from aptdaemon.core import APTDAEMON_TRANSACTION_DBUS_INTERFACE
4002+import aptdaemon.enums as aptd_enums
4003+from aptdaemon.errors import TransactionFailed, TransactionCancelled
4004+from aptdaemon.progress import DaemonAcquireProgress
4005+import aptdaemon.worker
4006+import aptdaemon.networking
4007+
4008+GObject.threads_init()
4009+
4010+pklog = logging.getLogger("AptDaemon.PackageKit")
4011+
4012+# Check if update-manager-core is installed to get aware of the
4013+# latest distro releases
4014+try:
4015+ from UpdateManager.Core.MetaRelease import MetaReleaseCore
4016+except ImportError:
4017+ META_RELEASE_SUPPORT = False
4018+else:
4019+ META_RELEASE_SUPPORT = True
4020+
4021+# Xapian database is optionally used to speed up package description search
4022+XAPIAN_DB_PATH = os.environ.get("AXI_DB_PATH", "/var/lib/apt-xapian-index")
4023+XAPIAN_DB = XAPIAN_DB_PATH + "/index"
4024+XAPIAN_DB_VALUES = XAPIAN_DB_PATH + "/values"
4025+XAPIAN_SUPPORT = False
4026+try:
4027+ import xapian
4028+except ImportError:
4029+ pass
4030+else:
4031+ if os.access(XAPIAN_DB, os.R_OK):
4032+ pklog.debug("Use XAPIAN for the search")
4033+ XAPIAN_SUPPORT = True
4034+
4035+# Regular expressions to detect bug numbers in changelogs according to the
4036+# Debian Policy Chapter 4.4. For details see the footnote 16:
4037+# http://www.debian.org/doc/debian-policy/footnotes.html#f16
4038+MATCH_BUG_CLOSES_DEBIAN=r"closes:\s*(?:bug)?\#?\s?\d+(?:,\s*(?:bug)?\#?\s?\d+)*"
4039+MATCH_BUG_NUMBERS=r"\#?\s?(\d+)"
4040+# URL pointing to a bug in the Debian bug tracker
4041+HREF_BUG_DEBIAN="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s"
4042+
4043+MATCH_BUG_CLOSES_UBUNTU = r"lp:\s+\#\d+(?:,\s*\#\d+)*"
4044+HREF_BUG_UBUNTU = "https://bugs.launchpad.net/bugs/%s"
4045+
4046+# Regular expression to find cve references
4047+MATCH_CVE="CVE-\d{4}-\d{4}"
4048+HREF_CVE="http://web.nvd.nist.gov/view/vuln/detail?vulnId=%s"
4049+
4050+# Map Debian sections to the PackageKit group name space
4051+SECTION_GROUP_MAP = {
4052+ "admin" : pk_enums.GROUP_ADMIN_TOOLS,
4053+ "base" : pk_enums.GROUP_SYSTEM,
4054+ "comm" : pk_enums.GROUP_COMMUNICATION,
4055+ "devel" : pk_enums.GROUP_PROGRAMMING,
4056+ "doc" : pk_enums.GROUP_DOCUMENTATION,
4057+ "editors" : pk_enums.GROUP_PUBLISHING,
4058+ "electronics" : pk_enums.GROUP_ELECTRONICS,
4059+ "embedded" : pk_enums.GROUP_SYSTEM,
4060+ "games" : pk_enums.GROUP_GAMES,
4061+ "gnome" : pk_enums.GROUP_DESKTOP_GNOME,
4062+ "graphics" : pk_enums.GROUP_GRAPHICS,
4063+ "hamradio" : pk_enums.GROUP_COMMUNICATION,
4064+ "interpreters" : pk_enums.GROUP_PROGRAMMING,
4065+ "kde" : pk_enums.GROUP_DESKTOP_KDE,
4066+ "libdevel" : pk_enums.GROUP_PROGRAMMING,
4067+ "libs" : pk_enums.GROUP_SYSTEM,
4068+ "mail" : pk_enums.GROUP_INTERNET,
4069+ "math" : pk_enums.GROUP_SCIENCE,
4070+ "misc" : pk_enums.GROUP_OTHER,
4071+ "net" : pk_enums.GROUP_NETWORK,
4072+ "news" : pk_enums.GROUP_INTERNET,
4073+ "oldlibs" : pk_enums.GROUP_LEGACY,
4074+ "otherosfs" : pk_enums.GROUP_SYSTEM,
4075+ "perl" : pk_enums.GROUP_PROGRAMMING,
4076+ "python" : pk_enums.GROUP_PROGRAMMING,
4077+ "science" : pk_enums.GROUP_SCIENCE,
4078+ "shells" : pk_enums.GROUP_SYSTEM,
4079+ "sound" : pk_enums.GROUP_MULTIMEDIA,
4080+ "tex" : pk_enums.GROUP_PUBLISHING,
4081+ "text" : pk_enums.GROUP_PUBLISHING,
4082+ "utils" : pk_enums.GROUP_ACCESSORIES,
4083+ "web" : pk_enums.GROUP_INTERNET,
4084+ "x11" : pk_enums.GROUP_DESKTOP_OTHER,
4085+ "unknown" : pk_enums.GROUP_UNKNOWN,
4086+ "alien" : pk_enums.GROUP_UNKNOWN,
4087+ "translations" : pk_enums.GROUP_LOCALIZATION,
4088+ "metapackages" : pk_enums.GROUP_COLLECTIONS }
4089+
4090+PACKAGEKIT_DBUS_INTERFACE = "org.freedesktop.PackageKit"
4091+PACKAGEKIT_DBUS_SERVICE = "org.freedesktop.PackageKit"
4092+PACKAGEKIT_DBUS_PATH = "/org/freedesktop/PackageKit"
4093+
4094+PACKAGEKIT_TRANS_DBUS_INTERFACE = "org.freedesktop.PackageKit.Transaction"
4095+PACKAGEKIT_TRANS_DBUS_SERVICE = "org.freedesktop.PackageKit.Transaction"
4096+
4097+MAP_EXIT_ENUM = {
4098+ aptd_enums.EXIT_SUCCESS: pk_enums.EXIT_SUCCESS,
4099+ aptd_enums.EXIT_CANCELLED: pk_enums.EXIT_CANCELLED,
4100+ aptd_enums.EXIT_FAILED: pk_enums.EXIT_FAILED,
4101+ aptd_enums.EXIT_FAILED: pk_enums.EXIT_FAILED,
4102+ aptd_enums.EXIT_PREVIOUS_FAILED:
4103+ pk_enums.EXIT_FAILED
4104+ }
4105+
4106+MAP_STATUS_ENUM = {
4107+ aptd_enums.STATUS_WAITING: pk_enums.STATUS_WAIT,
4108+ aptd_enums.STATUS_RUNNING: pk_enums.STATUS_RUNNING,
4109+ aptd_enums.STATUS_CANCELLING: pk_enums.STATUS_CANCEL,
4110+ aptd_enums.STATUS_CLEANING_UP: pk_enums.STATUS_CLEANUP,
4111+ aptd_enums.STATUS_COMMITTING: pk_enums.STATUS_COMMIT,
4112+ aptd_enums.STATUS_DOWNLOADING: pk_enums.STATUS_DOWNLOAD,
4113+ aptd_enums.STATUS_DOWNLOADING_REPO: pk_enums.STATUS_DOWNLOAD_REPOSITORY,
4114+ aptd_enums.STATUS_FINISHED: pk_enums.STATUS_FINISHED,
4115+ aptd_enums.STATUS_LOADING_CACHE: pk_enums.STATUS_LOADING_CACHE,
4116+ aptd_enums.STATUS_RESOLVING_DEP: pk_enums.STATUS_DEP_RESOLVE,
4117+ aptd_enums.STATUS_RUNNING: pk_enums.STATUS_RUNNING,
4118+ aptd_enums.STATUS_WAITING_LOCK:
4119+ pk_enums.STATUS_WAITING_FOR_LOCK,
4120+ aptd_enums.STATUS_WAITING_MEDIUM: pk_enums.STATUS_UNKNOWN,
4121+ aptd_enums.STATUS_WAITING_CONFIG_FILE_PROMPT:
4122+ pk_enums.STATUS_UNKNOWN
4123+}
4124+
4125+MAP_ERROR_ENUM = {
4126+ aptd_enums.ERROR_CACHE_BROKEN: pk_enums.ERROR_NO_CACHE,
4127+ aptd_enums.ERROR_DEP_RESOLUTION_FAILED:
4128+ pk_enums.ERROR_DEP_RESOLUTION_FAILED,
4129+ aptd_enums.ERROR_INCOMPLETE_INSTALL: pk_enums.ERROR_NO_CACHE,
4130+ aptd_enums.ERROR_INVALID_PACKAGE_FILE:
4131+ pk_enums.ERROR_PACKAGE_CORRUPT,
4132+ aptd_enums.ERROR_KEY_NOT_INSTALLED: pk_enums.ERROR_GPG_FAILURE,
4133+ aptd_enums.ERROR_KEY_NOT_REMOVED: pk_enums.ERROR_GPG_FAILURE,
4134+ aptd_enums.ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE:
4135+ pk_enums.ERROR_PACKAGE_FAILED_TO_REMOVE,
4136+ aptd_enums.ERROR_NO_CACHE: pk_enums.ERROR_NO_CACHE,
4137+ aptd_enums.ERROR_NO_LOCK: pk_enums.ERROR_CANNOT_GET_LOCK,
4138+ aptd_enums.ERROR_NO_PACKAGE: pk_enums.ERROR_PACKAGE_NOT_FOUND,
4139+ aptd_enums.ERROR_PACKAGE_ALREADY_INSTALLED:
4140+ pk_enums.ERROR_PACKAGE_ALREADY_INSTALLED,
4141+ aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED:
4142+ pk_enums.ERROR_PACKAGE_DOWNLOAD_FAILED,
4143+ aptd_enums.ERROR_PACKAGE_MANAGER_FAILED:
4144+ pk_enums.ERROR_TRANSACTION_ERROR,
4145+ aptd_enums.ERROR_PACKAGE_NOT_INSTALLED:
4146+ pk_enums.ERROR_PACKAGE_NOT_INSTALLED,
4147+ aptd_enums.ERROR_PACKAGE_UNAUTHENTICATED:
4148+ pk_enums.ERROR_BAD_GPG_SIGNATURE,
4149+ aptd_enums.ERROR_PACKAGE_UPTODATE:
4150+ pk_enums.ERROR_NO_PACKAGES_TO_UPDATE,
4151+ aptd_enums.ERROR_REPO_DOWNLOAD_FAILED:
4152+ pk_enums.ERROR_REPO_NOT_AVAILABLE,
4153+ aptd_enums.ERROR_UNREADABLE_PACKAGE_FILE:
4154+ pk_enums.ERROR_INVALID_PACKAGE_FILE,
4155+ aptd_enums.ERROR_SYSTEM_ALREADY_UPTODATE:
4156+ pk_enums.ERROR_NO_PACKAGES_TO_UPDATE,
4157+ }
4158+
4159+MAP_PACKAGE_ENUM = {
4160+ aptd_enums.PKG_CONFIGURING:
4161+ pk_enums.INFO_INSTALLING,
4162+ aptd_enums.PKG_DISAPPEARING:
4163+ pk_enums.INFO_UNKNOWN,
4164+ aptd_enums.PKG_INSTALLED:
4165+ pk_enums.INFO_FINISHED,
4166+ aptd_enums.PKG_INSTALLING:
4167+ pk_enums.INFO_INSTALLING,
4168+ aptd_enums.PKG_PREPARING_INSTALL:
4169+ pk_enums.INFO_PREPARING,
4170+ aptd_enums.PKG_PREPARING_PURGE:
4171+ pk_enums.INFO_PREPARING,
4172+ aptd_enums.PKG_PREPARING_REMOVE:
4173+ pk_enums.INFO_PREPARING,
4174+ aptd_enums.PKG_PURGED:
4175+ pk_enums.INFO_FINISHED,
4176+ aptd_enums.PKG_PURGING:
4177+ pk_enums.INFO_REMOVING,
4178+ aptd_enums.PKG_REMOVED:
4179+ pk_enums.INFO_FINISHED,
4180+ aptd_enums.PKG_REMOVING:
4181+ pk_enums.INFO_REMOVING,
4182+ aptd_enums.PKG_RUNNING_TRIGGER:
4183+ pk_enums.INFO_CLEANUP,
4184+ aptd_enums.PKG_UNKNOWN:
4185+ pk_enums.INFO_UNKNOWN,
4186+ aptd_enums.PKG_UNPACKING:
4187+ pk_enums.INFO_DECOMPRESSING,
4188+ aptd_enums.PKG_UPGRADING:
4189+ pk_enums.INFO_UPDATING,
4190+ }
4191+
4192+
4193+class PackageKit(aptdaemon.core.DBusObject):
4194+
4195+ """Provides a limited set of the PackageKit system D-Bus API."""
4196+
4197+ SUPPORTED_ROLES = [pk_enums.ROLE_REFRESH_CACHE,
4198+ pk_enums.ROLE_UPDATE_SYSTEM,
4199+ pk_enums.ROLE_SIMULATE_UPDATE_PACKAGES,
4200+ pk_enums.ROLE_UPDATE_PACKAGES,
4201+ pk_enums.ROLE_SIMULATE_REMOVE_PACKAGES,
4202+ pk_enums.ROLE_INSTALL_PACKAGES,
4203+ pk_enums.ROLE_SIMULATE_INSTALL_PACKAGES,
4204+ pk_enums.ROLE_INSTALL_PACKAGES,
4205+ pk_enums.ROLE_GET_DISTRO_UPGRADES,
4206+ pk_enums.ROLE_GET_UPDATES,
4207+ pk_enums.ROLE_GET_UPDATE_DETAIL,
4208+ pk_enums.ROLE_GET_PACKAGES,
4209+ pk_enums.ROLE_GET_DETAILS,
4210+ pk_enums.ROLE_GET_DEPENDS,
4211+ pk_enums.ROLE_GET_REQUIRES,
4212+ pk_enums.ROLE_SEARCH_NAME,
4213+ pk_enums.ROLE_SEARCH_DETAILS,
4214+ pk_enums.ROLE_SEARCH_GROUP,
4215+ pk_enums.ROLE_SEARCH_FILE,
4216+ pk_enums.ROLE_WHAT_PROVIDES,
4217+ pk_enums.ROLE_DOWNLOAD_PACKAGES]
4218+
4219+ SUPPORTED_FILTERS = [pk_enums.FILTER_INSTALLED,
4220+ pk_enums.FILTER_NOT_INSTALLED,
4221+ pk_enums.FILTER_FREE,
4222+ pk_enums.FILTER_NOT_FREE,
4223+ pk_enums.FILTER_GUI,
4224+ pk_enums.FILTER_NOT_GUI,
4225+ pk_enums.FILTER_COLLECTIONS,
4226+ pk_enums.FILTER_NOT_COLLECTIONS,
4227+ pk_enums.FILTER_SUPPORTED,
4228+ pk_enums.FILTER_NOT_SUPPORTED,
4229+ pk_enums.FILTER_NEWEST]
4230+
4231+ def __init__(self, queue, connect=True, bus=None):
4232+ """Initialize a new PackageKit compatibility layer.
4233+
4234+ Keyword arguments:
4235+ connect -- if the daemon should connect to the D-Bus (default is True)
4236+ bus -- the D-Bus to connect to (defaults to the system bus)
4237+ """
4238+ pklog.info("Initializing PackageKit compat layer")
4239+ bus_name = None
4240+ bus_path = None
4241+ if connect == True:
4242+ if bus is None:
4243+ bus = dbus.SystemBus()
4244+ self.bus = bus
4245+ bus_path = PACKAGEKIT_DBUS_PATH
4246+ bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, self.bus)
4247+ aptdaemon.core.DBusObject.__init__(self, bus_name, bus_path)
4248+ self._updates_changed_timeout_id = None
4249+ self._updates_changed = False
4250+ self.queue = queue
4251+ self.queue.worker.connect("transaction-done", self._on_transaction_done)
4252+ self.queue.connect("queue-changed", self._on_queue_changed)
4253+ self._distro_id = None
4254+ self.netmon = aptdaemon.networking.get_network_monitor()
4255+ self.netmon.connect("network-state-changed",
4256+ self._on_network_state_changed)
4257+ self.netmon.get_network_state()
4258+
4259+ # SIGNALS
4260+
4261+ # pylint: disable-msg=C0103,C0322
4262+ @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
4263+ signature="")
4264+ def RestartSchedule(self):
4265+ """A system restart has been sceduled."""
4266+ pass
4267+
4268+ # pylint: disable-msg=C0103,C0322
4269+ @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
4270+ signature="")
4271+ def Changed(self):
4272+ """This signal is emitted when a property on the interface changes."""
4273+ pass
4274+
4275+ # pylint: disable-msg=C0103,C0322
4276+ @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
4277+ signature="as")
4278+ def TransactionListChanged(self, transactions):
4279+ """The transaction list has changed, because either a transaction
4280+ has finished or a new transaction created.
4281+
4282+ :param transactions: A list of transaction ID's.
4283+ :type transactions: as
4284+ """
4285+ pklog.debug("Emitting TransactionListChanged signal: %s", transactions)
4286+
4287+ # pylint: disable-msg=C0103,C0322
4288+ @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
4289+ signature="")
4290+ def UpdatesChanged(self):
4291+ """This signal is emitted when the number of updates has changed."""
4292+ pklog.debug("Emitting UpdatesChanged signal")
4293+
4294+ # pylint: disable-msg=C0103,C0322
4295+ @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
4296+ signature="")
4297+ def RepoListChanged(self):
4298+ """This signal is emitted when the repository list has changed."""
4299+ pass
4300+
4301+ # pylint: disable-msg=C0103,C0322
4302+ @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
4303+ signature="")
4304+ def Changed(self):
4305+ """This signal is emitted when a property on the interface changes."""
4306+ pklog.debug("Emitting PackageKit Changed()")
4307+
4308+ # METHODS
4309+
4310+ # pylint: disable-msg=C0103,C0322
4311+ @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
4312+ in_signature="s", out_signature="s")
4313+ def CanAuthorize(self, action_id):
4314+ """Allows a client to find out if it would be allowed to authorize
4315+ an action.
4316+
4317+ :param action_id: The action ID, e.g.
4318+ org.freedesktop.packagekit.system-network-proxy-configure
4319+ :returns: The result, either yes, no or interactive.
4320+ """
4321+ #FIXME: We need to map packagekit and aptdaemon polices
4322+ return "interactive"
4323+
4324+ # pylint: disable-msg=C0103,C0322
4325+ @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
4326+ in_signature="s", out_signature="")
4327+ def StateHasChanged(self, reason):
4328+ """This method suggests to PackageKit that the package backend state
4329+ may have changed. This allows plugins to the native package manager
4330+ to suggest that PackageKit drops it's caches.
4331+
4332+ :param reason:
4333+ The reason of the state change. Valid reasons are resume or
4334+ posttrans. Resume is given a lower priority than posttrans.
4335+ """
4336+ pklog.debug("StateHasChanged() was called: %s", reason)
4337+ self._updates_changed = True
4338+ if reason == "cache-update":
4339+ self._check_updates_changed(timeout=30)
4340+ elif reason == "resume":
4341+ self._check_updates_changed(timeout=180)
4342+
4343+ # pylint: disable-msg=C0103,C0322
4344+ @dbus_deferred_method(PACKAGEKIT_DBUS_INTERFACE,
4345+ in_signature="", out_signature="s",
4346+ sender_keyword="sender")
4347+ def GetTid(self, sender):
4348+ """Gets a new transaction ID from the daemon.
4349+
4350+ :returns: The tid, e.g. 45_dafeca_checkpoint32
4351+ """
4352+ return self._get_tid(sender)
4353+
4354+ @inline_callbacks
4355+ def _get_tid(self, sender):
4356+ pid, uid, cmdline = \
4357+ yield policykit1.get_proc_info_from_dbus_name(sender, self.bus)
4358+ pktrans = PackageKitTransaction(pid, uid, cmdline, self.queue, sender)
4359+ return_value(pktrans.tid)
4360+
4361+ # pylint: disable-msg=C0103,C0322
4362+ @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
4363+ in_signature="", out_signature="as")
4364+ def GetTransactionList(self):
4365+ """Gets the transaction list of any transactions that are in
4366+ progress.
4367+
4368+ :returns: A list of transaction ID's
4369+ """
4370+ pklog.debug("GetTransactionList() was called")
4371+ return self._get_transaction_list()
4372+
4373+ # HELPERS
4374+
4375+ def _get_properties(self, iface):
4376+ """Helper to get the properties of a D-Bus interface."""
4377+ if iface == PACKAGEKIT_DBUS_INTERFACE:
4378+ return {# Claim that we are a stable version
4379+ "VersionMajor": dbus.UInt32(6),
4380+ "VersionMinor": dbus.UInt32(18),
4381+ "VersionMicro": dbus.UInt32(0),
4382+ "BackendName": dbus.String("aptdaemon"),
4383+ "BackendDescription": dbus.String("Compatibility layer"),
4384+ "BackendAuthor": dbus.String(__author__),
4385+ "Filters": dbus.String(";".join(self.SUPPORTED_FILTERS)),
4386+ "Groups": dbus.String(";".join(SECTION_GROUP_MAP.values())),
4387+ "Roles": dbus.String(";".join(self.SUPPORTED_ROLES)),
4388+ "Locked": dbus.Boolean(False),
4389+ "NetworkState": dbus.String(self.netmon.state),
4390+ "DistroId": dbus.String(self._get_distro_id()),
4391+ }
4392+ else:
4393+ return {}
4394+
4395+ def _get_distro_id(self):
4396+ """Return information about the distibution."""
4397+ if self._distro_id is None:
4398+ info = lsb_release.get_distro_information()
4399+ arch = subprocess.Popen(["dpkg", "--print-architecture"],
4400+ stdout=subprocess.PIPE).communicate()[0]
4401+ try:
4402+ self._distro_id = "%s;%s;%s" % (info["ID"], info["CODENAME"], arch)
4403+ except KeyError:
4404+ self._distro_id = "unknown;unknown;%s" % arch
4405+ return self._distro_id
4406+
4407+ def _on_network_state_changed(self, mon, state):
4408+ self.Changed()
4409+ self.PropertiesChanged(PACKAGEKIT_DBUS_INTERFACE,
4410+ {"Network": state}, [])
4411+
4412+ def _on_queue_changed(self, queue):
4413+ self.TransactionListChanged(self._get_transaction_list())
4414+ self._check_updates_changed()
4415+
4416+ def _get_transaction_list(self):
4417+ pk_transactions = []
4418+ for trans in self.queue.items:
4419+ # We currently only emit PackageKit transaction
4420+ #FIXME: Should we use MergedTransaction for all transactions and
4421+ # ROLE_UNKOWN for aptdaemon only transactions?
4422+ try:
4423+ pk_transactions.append(trans.pktrans.tid)
4424+ except AttributeError:
4425+ pass
4426+ try:
4427+ pk_transactions.append(self.queue.worker.trans.pktrans.tid)
4428+ except AttributeError:
4429+ pass
4430+ return pk_transactions
4431+
4432+ def _on_transaction_done(self, worker, trans):
4433+ # If a cache modifing transaction is completed schedule an
4434+ # UpdatesChanged signal
4435+ if trans.role in (aptd_enums.ROLE_INSTALL_FILE,
4436+ aptd_enums.ROLE_INSTALL_PACKAGES,
4437+ aptd_enums.ROLE_REMOVE_PACKAGES,
4438+ aptd_enums.ROLE_UPGRADE_PACKAGES,
4439+ aptd_enums.ROLE_COMMIT_PACKAGES,
4440+ aptd_enums.ROLE_UPGRADE_SYSTEM,
4441+ aptd_enums.ROLE_FIX_BROKEN_DEPENDS):
4442+ self._updates_changed = True
4443+ self._check_updates_changed()
4444+ elif trans.role == aptd_enums.ROLE_UPDATE_CACHE:
4445+ self._updates_changed = True
4446+ self._check_updates_changed(timeout=30)
4447+
4448+ def _check_updates_changed(self, timeout=60):
4449+ """After the queue was processed schedule a delayed UpdatesChanged
4450+ signal if required.
4451+ """
4452+ if not self.queue.items and self._updates_changed:
4453+ if self._updates_changed_timeout_id:
4454+ # If we already have a scheduled UpdatesChanged signal
4455+ # delay it even further
4456+ pklog.debug("UpdatesChanged signal re-scheduled")
4457+ GObject.source_remove(self._updates_changed_timeout_id)
4458+ else:
4459+ pklog.debug("UpdatesChanged signal scheduled")
4460+ self._updates_changed_timeout_id = \
4461+ GObject.timeout_add_seconds(timeout,
4462+ self._delayed_updates_changed)
4463+
4464+ def _delayed_updates_changed(self):
4465+ """Emit the UpdatesChanged signal and clear the timeout."""
4466+ self.UpdatesChanged()
4467+ self._updates_changed_timeout_id = None
4468+ self._updates_changed = False
4469+ return False
4470+
4471+
4472+class MergedTransaction(aptdaemon.core.Transaction):
4473+
4474+ """Overlay of an Aptdaemon transaction which also provides the
4475+ PackageKit object and its interfaces.
4476+ """
4477+
4478+ def __init__(self, pktrans, role, queue, connect=True,
4479+ bus=None, packages=None, kwargs=None):
4480+ aptdaemon.core.Transaction.__init__(self, pktrans.tid[1:], role, queue,
4481+ pktrans.pid, pktrans.uid,
4482+ pktrans.cmdline, pktrans.sender,
4483+ connect, bus, packages, kwargs)
4484+ self.pktrans = pktrans
4485+ self.run_time = 0
4486+
4487+ def _set_status(self, enum):
4488+ aptdaemon.core.Transaction._set_status(self, enum)
4489+ self.pktrans.status = get_pk_status_enum(enum)
4490+
4491+ status = property(aptdaemon.core.Transaction._get_status, _set_status)
4492+
4493+ def _set_progress(self, percent):
4494+ aptdaemon.core.Transaction._set_progress(self, percent)
4495+ self.pktrans.percentage = self._progress
4496+
4497+ progress = property(aptdaemon.core.Transaction._get_progress, _set_progress)
4498+
4499+ def _set_progress_details(self, details):
4500+ aptdaemon.core.Transaction._set_progress_details(self, details)
4501+ self.pktrans.speed = int(details[4])
4502+ self.pktrans.remaining_time = int(details[5])
4503+ self.pktrans.elapsed_time = int(time.time() - self.pktrans.start_time)
4504+
4505+ progress_details = property(aptdaemon.core.Transaction._get_progress_details,
4506+ _set_progress_details)
4507+
4508+ def _set_progress_package(self, progress):
4509+ aptdaemon.core.Transaction._set_progress_package(self, progress)
4510+ pkg_name, enum = progress
4511+ self.emit_package(get_pk_package_enum(enum),
4512+ get_pk_package_id(pkg_name),
4513+ "")
4514+
4515+ progress_package = property(aptdaemon.core.Transaction._get_progress_package,
4516+ _set_progress_package)
4517+
4518+
4519+ def _set_exit(self, enum):
4520+ aptdaemon.core.Transaction._set_exit(self, enum)
4521+ self.pktrans.exit = get_pk_exit_enum(enum)
4522+
4523+ exit = property(aptdaemon.core.Transaction._get_exit, _set_exit)
4524+
4525+ def _set_error(self, excep):
4526+ aptdaemon.core.Transaction._set_error(self, excep)
4527+ self.pktrans.ErrorCode(get_pk_error_enum(excep.code),
4528+ self._error_property[1])
4529+
4530+ error = property(aptdaemon.core.Transaction._get_error, _set_error)
4531+
4532+ def _remove_from_connection_no_raise(self):
4533+ aptdaemon.core.Transaction._remove_from_connection_no_raise(self)
4534+ self.pktrans.Destroy()
4535+ try:
4536+ self.pktrans.remove_from_connection()
4537+ except LookupError as error:
4538+ pklog.debug("remove_from_connection() raised LookupError: %s",
4539+ error)
4540+ finally:
4541+ self.pktrans.trans = None
4542+ self.pktrans = None
4543+ return False
4544+
4545+ def emit_details(self, package_id, license, group, detail, url, size):
4546+ self.pktrans.Details(package_id, license, group, detail, url, size)
4547+
4548+ def emit_files(self, id, file_list):
4549+ self.pktrans.Files(id, file_list)
4550+
4551+ def emit_package(self, info, id, summary):
4552+ self.pktrans.Package(info, id, summary)
4553+ self.pktrans.last_package = id
4554+
4555+ def emit_update_detail(self, package_id, updates, obsoletes, vendor_url,
4556+ bugzilla_url, cve_url, restart, update_text,
4557+ changelog, state, issued, updated):
4558+ self.pktrans.UpdateDetail(package_id, updates, obsoletes, vendor_url,
4559+ bugzilla_url, cve_url, restart, update_text,
4560+ changelog, state, issued, updated)
4561+
4562+
4563+class PackageKitTransaction(aptdaemon.core.DBusObject):
4564+
4565+ """Provides a PackageKit transaction object."""
4566+
4567+ def __init__(self, pid, uid, cmdline, queue, sender,
4568+ connect=True, bus=None):
4569+ pklog.info("Initializing PackageKit transaction")
4570+ bus_name = None
4571+ bus_path = None
4572+ self.tid = "/%s" % uuid.uuid4().get_hex()
4573+ if connect == True:
4574+ if bus is None:
4575+ bus = dbus.SystemBus()
4576+ self.bus = bus
4577+ bus_path = self.tid
4578+ bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, bus)
4579+ aptdaemon.core.DBusObject.__init__(self, bus_name, bus_path)
4580+ self.queue = queue
4581+ self.hints = {}
4582+ self.start_time = time.time()
4583+ self._elapsed_time = 0
4584+ self._remaining_time = 0
4585+ self._speed = 0
4586+ self._caller_active = True
4587+ self._allow_cancel = False
4588+ self._percentage = 0
4589+ self._subpercentage = 0
4590+ self._status = pk_enums.STATUS_SETUP
4591+ self._last_package = ""
4592+ self.uid = uid
4593+ self.pid = pid
4594+ self.cmdline = cmdline
4595+ self.role = pk_enums.ROLE_UNKNOWN
4596+ self.sender = sender
4597+ self.trans = None
4598+
4599+ @property
4600+ def allow_cancel(self):
4601+ return self._allow_cancel
4602+
4603+ @allow_cancel.setter
4604+ def allow_cancel(self, value):
4605+ self._allow_cancel = dbus.Boolean(value)
4606+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
4607+ {"AllowCancel": self._allow_cancel}, [])
4608+ self.Changed()
4609+
4610+ @property
4611+ def last_package(self):
4612+ return self._last_package
4613+
4614+ @last_package.setter
4615+ def last_package(self, value):
4616+ self._last_package = dbus.String(value)
4617+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
4618+ {"LastPackage": self._last_package}, [])
4619+ self.Changed()
4620+
4621+ @property
4622+ def caller_active(self):
4623+ return self._caller_active
4624+
4625+ @caller_active.setter
4626+ def caller_active(self, value):
4627+ self._caller_active = dbus.Boolean(value)
4628+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
4629+ {"CallerActive": self._caller_active}, [])
4630+ self.Changed()
4631+
4632+ @property
4633+ def percentage(self):
4634+ return self._percentage
4635+
4636+ @percentage.setter
4637+ def percentage(self, progress):
4638+ self._percentage = dbus.UInt32(progress)
4639+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
4640+ {"Percentage": self._percentage}, [])
4641+ self.Changed()
4642+
4643+ @property
4644+ def subpercentage(self):
4645+ return self._subpercentage
4646+
4647+ @subpercentage.setter
4648+ def subpercentage(self, progress):
4649+ self._subpercentage = dbus.UInt32(progress)
4650+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
4651+ {"SubPercentage": self._subpercentage}, [])
4652+ self.Changed()
4653+
4654+ @property
4655+ def status(self):
4656+ return self._status
4657+
4658+ @status.setter
4659+ def status(self, enum):
4660+ self._status = dbus.String(enum)
4661+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
4662+ {"Status": self._status}, [])
4663+ self.Changed()
4664+
4665+ @property
4666+ def elapsed_time(self):
4667+ return self._elapsed_time
4668+
4669+ @elapsed_time.setter
4670+ def elapsed_time(self, ela):
4671+ self._elpased_time = dbus.UInt32(ela)
4672+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
4673+ {"ElapsedTime": self._elapsed_time}, [])
4674+ self.Changed()
4675+
4676+ @property
4677+ def remaining_time(self):
4678+ return self._remaining_time
4679+
4680+ @remaining_time.setter
4681+ def remaining_time(self, value):
4682+ self._elpased_time = dbus.UInt32(value)
4683+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
4684+ {"RemainingTime": self._remaining_time}, [])
4685+ self.Changed()
4686+
4687+ @property
4688+ def speed(self):
4689+ return self._speed
4690+
4691+ @speed.setter
4692+ def speed(self, speed):
4693+ self._speed = dbus.UInt32(speed)
4694+ self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
4695+ {"AllowCancel": self._speed}, [])
4696+ self.Changed()
4697+
4698+ @property
4699+ def exit(self):
4700+ return self._exit
4701+
4702+ @exit.setter
4703+ def exit(self, enum):
4704+ self._exit = exit
4705+ self.run_time = int((time.time() - self.start_time) * 1000)
4706+ # The time could go backwards ...
4707+ if self.run_time < 0:
4708+ self.run_time = 0
4709+ if enum == pk_enums.EXIT_CANCELLED:
4710+ self.ErrorCode(pk_enums.ERROR_TRANSACTION_CANCELLED, "")
4711+ self.status = pk_enums.STATUS_FINISHED
4712+ self.Finished(enum, self.run_time)
4713+
4714+
4715+ # SIGNALS
4716+
4717+ # pylint: disable-msg=C0103,C0322
4718+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
4719+ signature="ssbsusus")
4720+ def Transaction(self, old_tid, timespec, succeeded, role, duration, data,
4721+ uid, cmdline):
4722+ """This signal is sent when more details are required about a
4723+ specific transaction.
4724+
4725+ :param old_tid: The transaction ID of the old transaction.
4726+ :param timespec: The timespec of the old transaction in ISO8601 format.
4727+ :param succeeded: If the transaction succeeded.
4728+ :param role: The role enumerated type.
4729+ :param duration: The duration of the transaction in milliseconds.
4730+ :param data: Any data associated
4731+ :param uid: The user ID of the user that scheduled the action.
4732+ :param cmdline: The command line of the tool that scheduled the action,
4733+ e.g. /usr/bin/gpk-application.
4734+ """
4735+ pass
4736+
4737+ # pylint: disable-msg=C0103,C0322
4738+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
4739+ signature="ss")
4740+ def ErrorCode(self, code, details):
4741+ """This signal is used to report errors back to the session program.
4742+ Errors should only be send on fatal abort.
4743+
4744+ :param code: Enumerated type, e.g. no-network.
4745+ :param details: Long description or error, e.g. "failed to connect"
4746+
4747+ :type code: s
4748+ :type details: s
4749+ """
4750+ pass
4751+
4752+ # pylint: disable-msg=C0103,C0322
4753+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
4754+ signature="")
4755+ def Changed(self):
4756+ """This signal is emitted when a property on the interface changes."""
4757+ pklog.debug("Emitting PackageKitTransaction Changed()")
4758+
4759+ # pylint: disable-msg=C0103,C0322
4760+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
4761+ signature="")
4762+ def Destroy(self):
4763+ """This signal is sent when the transaction has been destroyed
4764+ and is no longer available for use."""
4765+ pklog.debug("Emmitting Destroy()")
4766+
4767+ # pylint: disable-msg=C0103,C0322
4768+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
4769+ signature="su")
4770+ def Finished(self, exit, runtime):
4771+ """This signal is used to signal that the transaction has finished.
4772+ :param exit: The PkExitEnum describing the exit status of the
4773+ transaction.
4774+ :param runtime: The amount of time in milliseconds that the
4775+ transaction ran for.
4776+
4777+ :type exit: s
4778+ :type runtime: u
4779+ """
4780+ pklog.debug("Emitting Finished: %s, %s", exit, runtime)
4781+ pass
4782+
4783+ # pylint: disable-msg=C0103,C0322
4784+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
4785+ signature="ssssst")
4786+ def Details(self, package_id, license, group, detail, url, size):
4787+ """This signal allows the backend to convey more details about the
4788+ package.
4789+
4790+ :param package_id: The package ID
4791+
4792+ :param license:
4793+ The license string, e.g. GPLv2+ or BSD and (MPLv1.1 or GPLv2+).
4794+ Moredetails about the correct way to format licensing strings can
4795+ be found on the Fedora packaging wiki.
4796+ :param group:
4797+ The enumerated package group description
4798+ :param detail:
4799+ The multi-line package description. If formatting is required,
4800+ then markdown syntax should be used, e.g. This is **critically**
4801+ important
4802+ :param url:
4803+ The upstream project homepage
4804+ :param size:
4805+ The size of the package in bytes. This should be the size of the
4806+ entire package file, not the size of the files installed on the
4807+ system. If the package is not installed, and already downloaded
4808+ and present in the package manager cache, then this value should
4809+ be set to zero.
4810+ """
4811+ pklog.debug("Emmitting Details signal for %s", package_id)
4812+
4813+ # pylint: disable-msg=C0103,C0322
4814+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
4815+ signature="ss")
4816+ def Files(self, package_id, file_list):
4817+ """This signal is used to push file lists from the backend to the
4818+ session.
4819+
4820+ :param package_id:
4821+ The Package ID that called the method.
4822+ :param file_list:
4823+ The file list, with each file seporated with ;.
4824+ """
4825+ pklog.debug("Emitting Files signal: %s, %s", package_id, file_list)
4826+
4827+ # pylint: disable-msg=C0103,C0322
4828+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
4829+ signature="ssssssssssss")
4830+ def UpdateDetail(self, package_id, updates, obsoletes, vendor_url,
4831+ bugzilla_url, cve_url, restart, update_text, changelog,
4832+ state, issued, updated):
4833+ """This signal is sent when more details are required about a
4834+ specific update.
4835+
4836+ :param package_id: The package ID
4837+ :param updates:
4838+ A list of package_id's that are to be updated, seporated by
4839+ &. This odd delimited was chosen as \t is already being used
4840+ in the spawned backends, and & is a banned character in a
4841+ package_id.
4842+ :param obsoletes:
4843+ A list of package_id's that are to be obsoleted, separated by &
4844+ :param vendor_url:
4845+ A URL with more details on the update, e.g. a page with more
4846+ information on the update. The format of this command should
4847+ be http://www.foo.org/page.html?4567;Update to SELinux
4848+ :param bugzilla_url:
4849+ A bugzilla URL with more details on the update. If no URL is
4850+ available then this field should be left empty.
4851+ :param cve_url:
4852+ A CVE URL with more details on the security advisory.
4853+ :param restart:
4854+ A valid restart type, e.g. system.
4855+ :param update_text:
4856+ The update text describing the update. If formatting is required,
4857+ then markdown syntax should be used, e.g. This is **critically**
4858+ important.
4859+ :param changelog:
4860+ The ChangeLog text describing the changes since the last version.
4861+ :param state:
4862+ The state of the update, e.g. stable or testing.
4863+ :param issued:
4864+ The ISO8601 encoded date that the update was issued.
4865+ :param updated:
4866+ The ISO8601 encoded date that the update was updated.
4867+ """
4868+ pklog.debug("Emmitting UpdateDetail signal for %s", package_id)
4869+
4870+ # pylint: disable-msg=C0103,C0322
4871+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
4872+ signature="sss")
4873+ def Package(self, info, package_id, summary):
4874+ """This signal allows the backend to communicate packages to the
4875+ session.
4876+
4877+ If updating, as packages are updated then emit them to the screen.
4878+ This allows a summary to be presented after the transaction.
4879+ When returning results from a search always return installed
4880+ before available for the same package name.
4881+
4882+ :param info: A valid info string enumerated type
4883+ :param package_id: This identifier is of the form
4884+ name;version;arch;data in a single string and is meant to
4885+ represent a single package unique across all local and remote
4886+ data stores. For a remote, not-installed package the data
4887+ field should be set as the repository identifier or repository
4888+ name. The data field for an installed package must be prefixed
4889+ with installed as this is used to identify which packages are
4890+ installable or installed in the client tools. As a special
4891+ extension, if the package manager is able to track which
4892+ repository a package was originally installed from, then the data
4893+ field can be set to installed:REPO-NAME which allows the frontend
4894+ client to advise the user of the package origin. The data field
4895+ for a non-installed local package must be local as this signifies
4896+ a repository name is not available and that package resides
4897+ locally on the client system rather than in any specific
4898+ repository.
4899+ :param summary: The one line package summary, e.g. Clipart for
4900+ OpenOffice
4901+ """
4902+ pklog.debug("Emmitting Package signal: info=%s id=%s summary='%s'",
4903+ info, package_id, summary[:10])
4904+
4905+ # pylint: disable-msg=C0103,C0322
4906+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
4907+ signature="sss")
4908+ def DistroUpgrade(self, type, name, summary):
4909+ """This signal allows the backend to communicate distribution upgrades
4910+ to the session.
4911+ :param type: A valid upgrade string enumerated type, e.g. stable
4912+ or unstable
4913+ :param name: The short name of the distribution, e.g. Fedora Core
4914+ 10 RC1
4915+ :param summary: The multi-line description of the release
4916+ """
4917+ pass
4918+
4919+ # pylint: disable-msg=C0103,C0322
4920+ @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
4921+ signature="ss")
4922+ def RequireRestart(self, restart_type, package_id):
4923+ """This signal is sent when the session client should notify the user
4924+ that a restart is required to get all changes into effect.
4925+
4926+ :param package_id:
4927+ The Package ID of the package tiggering the restart
4928+ :param file_list:
4929+ One of system, application or session
4930+ """
4931+ pklog.debug("Emitting RequireRestart signal: %s, %s",
4932+ restart_type, package_id)
4933+
4934+ # METHODS
4935+
4936+ # pylint: disable-msg=C0103,C0322
4937+ @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
4938+ in_signature="as", out_signature="")
4939+ def SetHints(self, hints):
4940+ """This method allows the calling session to set transaction hints
4941+ for the package manager which can change as the transaction runs.
4942+
4943+ This method can be sent before the transaction has been run or
4944+ whilst it is running. There is no limit to the number of times
4945+ this method can be sent, although some backends may only use the
4946+ values that were set before the transaction was started.
4947+
4948+ Each parameter value is optional.
4949+
4950+ :param hints: The values as an array of strings, for example
4951+ ['locale=en_GB.utf8','interactive=false','cache-age=3600']
4952+ """
4953+ for hint in hints:
4954+ key, value = hint.split("=", 1)
4955+ if key not in ["locale", "idle", "background", "interactive",
4956+ "cache-age", "frontend-socket"]:
4957+ raise Exception("Invalid option %s" % key)
4958+ self.hints[key] = value
4959+
4960+ # pylint: disable-msg=C0103,C0322
4961+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
4962+ in_signature="", out_signature="",
4963+ sender_keyword="sender")
4964+ def Cancel(self, sender):
4965+ """This method cancels a transaction that is already running."""
4966+ if self.trans:
4967+ return self.trans._cancel(sender)
4968+
4969+ # pylint: disable-msg=C0103,C0322
4970+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
4971+ in_signature="asbb", out_signature="",
4972+ sender_keyword="sender")
4973+ def RemovePackages(self, package_ids, allow_deps, autoremove, sender):
4974+ """This method removes packages from the local system.
4975+
4976+ This method typically emits Progress, Status and Error and Package.
4977+
4978+ Package enumerated types should be downloading, updating, installing or removing.
4979+
4980+ :param package_ids: An array of package IDs.
4981+ :param allow_deps:
4982+ Either true or false. If true allow other packages to be removed
4983+ with the package, but false should cause the script to abort if
4984+ other packages are dependant on the package.
4985+ :param autoremove:
4986+ Either true or false. This option is only really interesting on
4987+ embedded devices with a limited amount of flash storage. It
4988+ suggests to the packagekit backend that dependencies installed at
4989+ the same time as the package should also be removed if they are not
4990+ required by anything else. For instance, if you install OpenOffice,
4991+ it might download libneon as a dependency. When auto_remove is set
4992+ to true, and you remove OpenOffice then libneon will also get
4993+ removed automatically.
4994+ """
4995+ pklog.debug("RemovePackages() was called")
4996+ self.role = pk_enums.ROLE_REMOVE_PACKAGES
4997+ return self._remove_packages(package_ids, allow_deps, autoremove,
4998+ sender)
4999+
5000+ @inline_callbacks
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches