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

Proposed by Steve Langasek
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 Approve
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.
Revision history for this message
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
100. By Steve Langasek

refresh the patch to minimize delta

101. By Steve Langasek

releasing version 0.43+bzr805-0ubuntu4

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory '.pc'
=== added file '.pc/.quilt_patches'
--- .pc/.quilt_patches 1970-01-01 00:00:00 +0000
+++ .pc/.quilt_patches 2012-08-11 01:29:19 +0000
@@ -0,0 +1,1 @@
1debian/patches
02
=== added file '.pc/.quilt_series'
--- .pc/.quilt_series 1970-01-01 00:00:00 +0000
+++ .pc/.quilt_series 2012-08-11 01:29:19 +0000
@@ -0,0 +1,1 @@
1series
02
=== added file '.pc/.version'
--- .pc/.version 1970-01-01 00:00:00 +0000
+++ .pc/.version 2012-08-11 01:29:19 +0000
@@ -0,0 +1,1 @@
12
02
=== added file '.pc/applied-patches'
--- .pc/applied-patches 1970-01-01 00:00:00 +0000
+++ .pc/applied-patches 2012-08-11 01:29:19 +0000
@@ -0,0 +1,5 @@
1fix-lp-932581.patch
2fix-lp-971748.patch
3fix-lp-981124.patch
4fix-lp-900982.patch
5fix_gettext_return_value_type.patch
06
=== added directory '.pc/fix-lp-900982.patch'
=== added directory '.pc/fix-lp-900982.patch/aptdaemon'
=== added file '.pc/fix-lp-900982.patch/aptdaemon/enums.py'
--- .pc/fix-lp-900982.patch/aptdaemon/enums.py 1970-01-01 00:00:00 +0000
+++ .pc/fix-lp-900982.patch/aptdaemon/enums.py 2012-08-11 01:29:19 +0000
@@ -0,0 +1,698 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3"""enums - Enumerates for apt daemon dbus messages"""
4# Copyright (C) 2008-2009 Sebastian Heinlein <devel@glatzor.de>
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program; if not, write to the Free Software Foundation, Inc.,
18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20__author__ = "Sebastian Heinlein <devel@glatzor.de>"
21
22import gettext
23def _(msg):
24 return gettext.dgettext("aptdaemon", msg)
25
26__all__ = ("PKGS_INSTALL", "PKGS_REINSTALL", "PKGS_REMOVE", "PKGS_PURGE",
27 "PKGS_UPGRADE", "PKGS_DOWNGRADE", "PKGS_KEEP",
28 "EXIT_SUCCESS", "EXIT_CANCELLED", "EXIT_FAILED", "EXIT_UNFINISHED",
29 "ERROR_PACKAGE_DOWNLOAD_FAILED", "ERROR_REPO_DOWNLOAD_FAILED",
30 "ERROR_DEP_RESOLUTION_FAILED",
31 "ERROR_KEY_NOT_INSTALLED", "ERROR_KEY_NOT_REMOVED", "ERROR_NO_LOCK",
32 "ERROR_NO_CACHE", "ERROR_NO_PACKAGE", "ERROR_PACKAGE_UPTODATE",
33 "ERROR_PACKAGE_NOT_INSTALLED", "ERROR_PACKAGE_ALREADY_INSTALLED",
34 "ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE", "ERROR_DAEMON_DIED",
35 "ERROR_PACKAGE_MANAGER_FAILED", "ERROR_CACHE_BROKEN",
36 "ERROR_PACKAGE_UNAUTHENTICATED", "ERROR_INCOMPLETE_INSTALL",
37 "ERROR_UNREADABLE_PACKAGE_FILE", "ERROR_INVALID_PACKAGE_FILE",
38 "ERROR_SYSTEM_ALREADY_UPTODATE", "ERROR_NOT_SUPPORTED",
39 "ERROR_LICENSE_KEY_INSTALL_FAILED",
40 "ERROR_LICENSE_KEY_DOWNLOAD_FAILED",
41 "ERROR_UNKNOWN",
42 "STATUS_SETTING_UP", "STATUS_WAITING", "STATUS_WAITING_MEDIUM",
43 "STATUS_WAITING_CONFIG_FILE_PROMPT", "STATUS_WAITING_LOCK",
44 "STATUS_RUNNING", "STATUS_LOADING_CACHE", "STATUS_DOWNLOADING",
45 "STATUS_COMMITTING", "STATUS_CLEANING_UP", "STATUS_RESOLVING_DEP",
46 "STATUS_FINISHED", "STATUS_CANCELLING", "STATUS_QUERY",
47 "STATUS_DOWNLOADING_REPO",
48 "ROLE_UNSET", "ROLE_INSTALL_PACKAGES", "ROLE_INSTALL_FILE",
49 "ROLE_UPGRADE_PACKAGES", "ROLE_UPGRADE_SYSTEM", "ROLE_UPDATE_CACHE",
50 "ROLE_REMOVE_PACKAGES", "ROLE_COMMIT_PACKAGES",
51 "ROLE_ADD_VENDOR_KEY_FILE", "ROLE_ADD_VENDOR_KEY_FROM_KEYSERVER",
52 "ROLE_REMOVE_VENDOR_KEY", "ROLE_FIX_INCOMPLETE_INSTALL",
53 "ROLE_FIX_BROKEN_DEPENDS", "ROLE_ADD_REPOSITORY",
54 "ROLE_ENABLE_DISTRO_COMP", "ROLE_CLEAN", "ROLE_RECONFIGURE",
55 "ROLE_PK_QUERY", "ROLE_ADD_LICENSE_KEY",
56 "DOWNLOAD_DONE", "DOWNLOAD_AUTH_ERROR", "DOWNLOAD_ERROR",
57 "DOWNLOAD_FETCHING", "DOWNLOAD_IDLE", "DOWNLOAD_NETWORK_ERROR",
58 "PKG_INSTALLING", "PKG_CONFIGURING", "PKG_REMOVING",
59 "PKG_PURGING", "PKG_UPGRADING", "PKG_RUNNING_TRIGGER",
60 "PKG_DISAPPEARING", "PKG_PREPARING_REMOVE", "PKG_PREPARING_INSTALL",
61 "PKG_PREPARING_PURGE", "PKG_PREPARING_PURGE", "PKG_INSTALLED",
62 "PKG_REMOVED", "PKG_PURGED", "PKG_UNPACKING", "PKG_UNKNOWN",
63 "get_status_icon_name_from_enum", "get_role_icon_name_from_enum",
64 "get_status_animation_name_from_enum",
65 "get_package_status_from_enum",
66 "get_role_localised_past_from_enum", "get_exit_string_from_enum",
67 "get_role_localised_present_from_enum", "get_role_error_from_enum",
68 "get_error_description_from_enum", "get_error_string_from_enum",
69 "get_status_string_from_enum", "get_download_status_from_enum")
70
71# PACKAGE GROUP INDEXES
72#: Index of the list of to be installed packages in the :attr:`dependencies`
73#: and :attr:`packages` property of :class:`~aptdaemon.client.AptTransaction`.
74PKGS_INSTALL = 0
75#: Index of the list of to be re-installed packages in the :attr:`dependencies`
76#: and :attr:`packages` property of :class:`~aptdaemon.client.AptTransaction`.
77PKGS_REINSTALL = 1
78#: Index of the list of to be removed packages in the :attr:`dependencies`
79#: and :attr:`packages` property of :class:`~aptdaemon.client.AptTransaction`.
80PKGS_REMOVE = 2
81#: Index of the list of to be purged packages in the :attr:`dependencies`
82#: and :attr:`packages` property of :class:`~aptdaemon.client.AptTransaction`.
83PKGS_PURGE = 3
84#: Index of the list of to be upgraded packages in the :attr:`dependencies`
85#: and :attr:`packages` property of :class:`~aptdaemon.client.AptTransaction`.
86PKGS_UPGRADE = 4
87#: Index of the list of to be downgraded packages in the :attr:`dependencies`
88#: and :attr:`packages` property of :class:`~aptdaemon.client.AptTransaction`.
89PKGS_DOWNGRADE = 5
90#: Index of the list of to be keept packages in the :attr:`dependencies`
91#: property of :class:`~aptdaemon.client.AptTransaction`.
92PKGS_KEEP = 6
93
94# FINISH STATES
95#: The transaction was successful.
96EXIT_SUCCESS = "exit-success"
97#: The transaction has been cancelled by the user.
98EXIT_CANCELLED = "exit-cancelled"
99#: The transaction has failed.
100EXIT_FAILED = "exit-failed"
101#: The transaction failed since a previous one in a chain failed.
102EXIT_PREVIOUS_FAILED = "exit-previous-failed"
103#: The transaction is still being queued or processed.
104EXIT_UNFINISHED = "exit-unfinished"
105
106# ERROR CODES
107#: Failed to download package files which should be installed.
108ERROR_PACKAGE_DOWNLOAD_FAILED = "error-package-download-failed"
109#: Failed to download package information (index files) from the repositories
110ERROR_REPO_DOWNLOAD_FAILED = "error-repo-download-failed"
111#: Failed to satisfy the dependencies or conflicts of packages.
112ERROR_DEP_RESOLUTION_FAILED = "error-dep-resolution-failed"
113#: The requested vendor key is not installed.
114ERROR_KEY_NOT_INSTALLED = "error-key-not-installed"
115#: The requested vendor could not be removed.
116ERROR_KEY_NOT_REMOVED = "error-key-not-removed"
117#: The package management system could not be locked. Eventually another
118#: package manager is running.
119ERROR_NO_LOCK = "error-no-lock"
120#: The package cache could not be opened. This indicates a serious problem
121#: on the system.
122ERROR_NO_CACHE = "error-no-cache"
123#: The requested package is not available.
124ERROR_NO_PACKAGE = "error-no-package"
125#: The package could not be upgraded since it is already up-to-date.
126ERROR_PACKAGE_UPTODATE = "error-package-uptodate"
127#: The package which was requested to install is already installed.
128ERROR_PACKAGE_ALREADY_INSTALLED = "error-package-already-installed"
129#: The package could not be removed since it is not installed.
130ERROR_PACKAGE_NOT_INSTALLED = "error-package-not-installed"
131#: It is not allowed to remove an essential system package.
132ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE = "error-not-remove-essential"
133#: The aptdaemon crashed or could not be connected to on the D-Bus.
134ERROR_DAEMON_DIED = "error-daemon-died"
135#: On of the maintainer scripts during the dpkg call failed.
136ERROR_PACKAGE_MANAGER_FAILED = "error-package-manager-failed"
137#: There are packages with broken dependencies installed on the system.
138#: This has to fixed before performing another transaction.
139ERROR_CACHE_BROKEN = "error-cache-broken"
140#: It is not allowed to install an unauthenticated packages. Packages are
141#: authenticated by installing the vendor key.
142ERROR_PACKAGE_UNAUTHENTICATED = "error-package-unauthenticated"
143#: A previous installation has been aborted and is now incomplete.
144#: Should be fixed by `dpkg --configure -a` or the :func:`FixIncomplete()`
145#: transaction.
146ERROR_INCOMPLETE_INSTALL = "error-incomplete-install"
147#: Failed to open and read the package file
148ERROR_UNREADABLE_PACKAGE_FILE = "error-unreadable-package-file"
149#: The package file violates the Debian/Ubuntu policy
150ERROR_INVALID_PACKAGE_FILE = "error-invalid-package-file"
151#: The requested feature is not supported yet (mainly used by PackageKit
152ERROR_NOT_SUPPORTED = "error-not-supported"
153#: The license key download failed
154ERROR_LICENSE_KEY_DOWNLOAD_FAILED = "error-license-key-download-failed"
155#: The license key is invalid
156ERROR_LICENSE_KEY_INSTALL_FAILED = "error-license-key-install-failed"
157#: The system is already up-to-date and don't needs any upgrades
158ERROR_SYSTEM_ALREADY_UPTODATE = "error-system-already-uptodate"
159#: An unknown error occured. In most cases these are programming ones.
160ERROR_UNKNOWN = "error-unknown"
161
162# TRANSACTION STATES
163#: The transaction was created, but hasn't been queued.
164STATUS_SETTING_UP = "status-setting-up"
165#: The transaction performs a query
166STATUS_QUERY = "status-query"
167#: The transaction is waiting in the queue.
168STATUS_WAITING = "status-waiting"
169#: The transaction is paused and waits until a required medium is inserted.
170#: See :func:`ProvideMedium()`.
171STATUS_WAITING_MEDIUM = "status-waiting-medium"
172#: The transaction is paused and waits for the user to resolve a configuration
173#: file conflict. See :func:`ResolveConfigFileConflict()`.
174STATUS_WAITING_CONFIG_FILE_PROMPT = "status-waiting-config-file-prompt"
175#: Wait until the package management system can be locked. Most likely
176#: another package manager is running currently.
177STATUS_WAITING_LOCK = "status-waiting-lock"
178#: The processing of the transaction has started.
179STATUS_RUNNING = "status-running"
180#: The package cache is opened.
181STATUS_LOADING_CACHE = "status-loading-cache"
182#: The information about available packages is downloaded
183STATUS_DOWNLOADING_REPO = "status-downloading-repo"
184#: The required package files to install are getting downloaded.
185STATUS_DOWNLOADING = "status-downloading"
186#: The actual installation/removal takes place.
187STATUS_COMMITTING = "status-committing"
188#: The package management system is cleaned up.
189STATUS_CLEANING_UP = "status-cleaning-up"
190#: The dependecies and conflicts are now getting resolved.
191STATUS_RESOLVING_DEP = "status-resolving-dep"
192#: The transaction has been completed.
193STATUS_FINISHED = "status-finished"
194#: The transaction has been cancelled.
195STATUS_CANCELLING = "status-cancelling"
196#: The transaction waits for authentication
197STATUS_AUTHENTICATING = "status-authenticating"
198
199# PACKAGE STATES
200#: The package gets unpacked
201PKG_UNPACKING = "pkg-unpacking"
202#: The installation of the package gets prepared
203PKG_PREPARING_INSTALL = "pkg-preparing-install"
204#: The package is installed
205PKG_INSTALLED = "pkg-installed"
206#: The package gets installed
207PKG_INSTALLING = "pkg-installing"
208#: The configuration of the package gets prepared
209PKG_PREPARING_CONFIGURE = "pkg-preparing-configure"
210#: The package gets configured
211PKG_CONFIGURING = "pkg-configuring"
212#: The removal of the package gets prepared
213PKG_PREPARING_REMOVE = "pkg-preparing-removal"
214#: The package gets removed
215PKG_REMOVING = "pkg-removing"
216#: The package is removed
217PKG_REMOVED = "pkg-removed"
218#: The purging of the package gets prepared
219PKG_PREPARING_PURGE = "pkg-preparing-purge"
220#: The package gets purged
221PKG_PURGING = "pkg-purging"
222#: The package was completely removed
223PKG_PURGED = "pkg-purged"
224#: The post installation trigger of the package is processed
225PKG_RUNNING_TRIGGER = "pkg-running-trigger"
226#: The package disappered - very rare
227PKG_DISAPPEARING = "pkg-disappearing"
228#: The package gets upgraded
229PKG_UPGRADING = "pkg-upgrading"
230#: Failed to get a current status of the package
231PKG_UNKNOWN = "pkg-unknown"
232
233# TRANSACTION ROLES
234#: The role of the transaction has not been specified yet.
235ROLE_UNSET = "role-unset"
236#: The transaction performs a query compatible to the PackageKit interface
237ROLE_PK_QUERY = "role-pk-query"
238#: The transaction will install one or more packages.
239ROLE_INSTALL_PACKAGES = "role-install-packages"
240#: The transaction will install a local package file.
241ROLE_INSTALL_FILE = "role-install-file"
242#: The transaction will upgrade one or more packages.
243ROLE_UPGRADE_PACKAGES = "role-upgrade-packages"
244#: The transaction will perform a system upgrade.
245ROLE_UPGRADE_SYSTEM = "role-upgrade-system"
246#: The transaction will update the package cache.
247ROLE_UPDATE_CACHE = "role-update-cache"
248#: The transaction will remove one or more packages.
249ROLE_REMOVE_PACKAGES = "role-remove-packages"
250#: The transaction will perform a combined install, remove, upgrade or
251#: downgrade action.
252ROLE_COMMIT_PACKAGES = "role-commit-packages"
253#: The transaction will add a local vendor key file to authenticate packages.
254ROLE_ADD_VENDOR_KEY_FILE = "role-add-vendor-key-file"
255#: The transaction will download vendor key to authenticate packages from
256#: a keyserver.
257ROLE_ADD_VENDOR_KEY_FROM_KEYSERVER = "role-add-vendor-key-from-keyserver"
258#: The transaction will remove a vendor key which was used to authenticate
259#: packages.
260ROLE_REMOVE_VENDOR_KEY = "role-remove-vendor-key"
261#: The transaction will try to finish a previous aborted installation.
262ROLE_FIX_INCOMPLETE_INSTALL = "role-fix-incomplete-install"
263#: The transaction will to resolve broken dependencies of already installed
264#: packages.
265ROLE_FIX_BROKEN_DEPENDS = "role-fix-broken-depends"
266#: The transaction will enable a repository to download software from.
267ROLE_ADD_REPOSITORY = "role-add-repository"
268#: The transaction will enable a component in the distro repositories,
269#: e.g main or universe
270ROLE_ENABLE_DISTRO_COMP = "role-enable-distro-comp"
271#: The transaction will reconfigure the given already installed packages
272ROLE_RECONFIGURE = "role-reconfigure"
273#: The transaction will remove all downloaded package files.
274ROLE_CLEAN = "role-clean"
275#: The transaction will add a license key to the system
276ROLE_ADD_LICENSE_KEY = "role-add-license-key"
277
278# DOWNLOAD STATES
279#: The download has been completed.
280DOWNLOAD_DONE = "download-done"
281#: The file could not be downloaded since the authentication for the repository
282#: failed.
283DOWNLOAD_AUTH_ERROR = "download-auth-error"
284#: There file could not be downloaded, e.g. because it is not available (404).
285DOWNLOAD_ERROR = "download-error"
286#: The file is currently being downloaded.
287DOWNLOAD_FETCHING = "download-fetching"
288#: The download is currently idling.
289DOWNLOAD_IDLE = "download-idle"
290#: The download failed since there seem to be a networking problem.
291DOWNLOAD_NETWORK_ERROR = "download-network-error"
292
293_ICONS_STATUS = {
294 STATUS_CANCELLING: 'aptdaemon-cleanup',
295 STATUS_CLEANING_UP: 'aptdaemon-cleanup',
296 STATUS_RESOLVING_DEP: 'aptdaemon-resolve',
297 STATUS_COMMITTING: 'aptdaemon-working',
298 STATUS_DOWNLOADING: 'aptdaemon-download',
299 STATUS_DOWNLOADING_REPO: 'aptdaemon-download',
300 STATUS_FINISHED: 'aptdaemon-cleanup',
301 STATUS_LOADING_CACHE: 'aptdaemon-update-cache',
302 STATUS_RUNNING: 'aptdaemon-working',
303 STATUS_SETTING_UP: 'aptdaemon-working',
304 STATUS_WAITING: 'aptdaemon-wait',
305 STATUS_WAITING_LOCK: 'aptdaemon-wait',
306 STATUS_WAITING_MEDIUM: 'aptdaemon-wait',
307 STATUS_WAITING_CONFIG_FILE_PROMPT: 'aptdaemon-wait',
308 }
309
310def get_status_icon_name_from_enum(enum):
311 """Get the icon name for a transaction status.
312
313 :param enum: The transaction status enum, e.g. :data:`STATUS_WAITING`.
314 :returns: The icon name string.
315 """
316 try:
317 return _ICONS_STATUS[enum]
318 except KeyError:
319 return "aptdaemon-working"
320
321_ICONS_ROLE = {
322 ROLE_INSTALL_FILE: 'aptdaemon-add',
323 ROLE_INSTALL_PACKAGES: 'aptdaemon-add',
324 ROLE_UPDATE_CACHE: 'aptdaemon-update-cache',
325 ROLE_REMOVE_PACKAGES: 'aptdaemon-delete',
326 ROLE_UPGRADE_PACKAGES: 'aptdaemon-upgrade',
327 ROLE_UPGRADE_SYSTEM: 'system-software-update',
328 }
329
330def get_role_icon_name_from_enum(enum):
331 """Get an icon to represent the role of a transaction.
332
333 :param enum: The transaction role enum, e.g. :data:`ROLE_UPDATE_CACHE`.
334 :returns: The icon name string.
335 """
336 try:
337 return _ICONS_ROLE[enum]
338 except KeyError:
339 return "aptdaemon-working"
340
341_ANIMATIONS_STATUS = {
342 STATUS_CANCELLING: 'aptdaemon-action-cleaning-up',
343 STATUS_CLEANING_UP: 'aptdaemon-action-cleaning-up',
344 STATUS_RESOLVING_DEP: 'aptdaemon-action-resolving',
345 STATUS_DOWNLOADING: 'aptdaemon-action-downloading',
346 STATUS_DOWNLOADING_REPO: 'aptdaemon-action-downloading',
347 STATUS_LOADING_CACHE: 'aptdaemon-action-updating-cache',
348 STATUS_WAITING: 'aptdaemon-action-waiting',
349 STATUS_WAITING_LOCK: 'aptdaemon-action-waiting',
350 STATUS_WAITING_MEDIUM: 'aptdaemon-action-waiting',
351 STATUS_WAITING_CONFIG_FILE_PROMPT: 'aptdaemon-action-waiting',
352 }
353
354def get_status_animation_name_from_enum(enum):
355 """Get an animation to represent a transaction status.
356
357 :param enum: The transaction status enum, e.g. :data:`STATUS_WAITING`.
358 :returns: The animation name string.
359 """
360 try:
361 return _ANIMATIONS_STATUS[enum]
362 except KeyError:
363 return None
364
365_PAST_ROLE = {
366 ROLE_INSTALL_FILE : _("Installed file"),
367 ROLE_INSTALL_PACKAGES : _("Installed packages"),
368 ROLE_ADD_VENDOR_KEY_FILE: _("Added key from file"),
369 ROLE_UPDATE_CACHE : _("Updated cache"),
370 ROLE_PK_QUERY : _("Search done"),
371 ROLE_REMOVE_VENDOR_KEY : _("Removed trusted key"),
372 ROLE_REMOVE_PACKAGES : _("Removed packages"),
373 ROLE_UPGRADE_PACKAGES : _("Updated packages"),
374 ROLE_UPGRADE_SYSTEM : _("Upgraded system"),
375 ROLE_COMMIT_PACKAGES : _("Applied changes"),
376 ROLE_FIX_INCOMPLETE_INSTALL : _("Repaired incomplete installation"),
377 ROLE_FIX_BROKEN_DEPENDS: _("Repaired broken dependencies"),
378 ROLE_ADD_REPOSITORY: _("Added software source"),
379 ROLE_ENABLE_DISTRO_COMP: _("Enabled component of the distribution"),
380 ROLE_CLEAN: _("Removed downloaded package files"),
381 ROLE_RECONFIGURE: _("Reconfigured installed packages"),
382 ROLE_UNSET: ""
383 }
384
385def get_role_localised_past_from_enum(enum):
386 """Get the description of a completed transaction action.
387
388 :param enum: The transaction role enum, e.g. :data:`ROLE_UPDATE_CACHE`.
389 :returns: The description string.
390 """
391 try:
392 return _PAST_ROLE[enum]
393 except KeyError:
394 return None
395
396_STRING_EXIT = {
397 EXIT_SUCCESS : _("Successful"),
398 EXIT_CANCELLED : _("Canceled"),
399 EXIT_FAILED : _("Failed")
400 }
401
402def get_exit_string_from_enum(enum):
403 """Get the description of a transaction exit status.
404
405 :param enum: The transaction exit status enum, e.g. :data:`EXIT_FAILED`.
406 :returns: The description string.
407 """
408 try:
409 return _STRING_EXIT[enum]
410 except:
411 return None
412
413_PRESENT_ROLE = {
414 ROLE_INSTALL_FILE : _("Installing file"),
415 ROLE_INSTALL_PACKAGES : _("Installing packages"),
416 ROLE_ADD_VENDOR_KEY_FILE : _("Adding key from file"),
417 ROLE_UPDATE_CACHE : _("Updating cache"),
418 ROLE_REMOVE_VENDOR_KEY : _("Removing trusted key"),
419 ROLE_REMOVE_PACKAGES : _("Removing packages"),
420 ROLE_UPGRADE_PACKAGES : _("Updating packages"),
421 ROLE_UPGRADE_SYSTEM : _("Upgrading system"),
422 ROLE_COMMIT_PACKAGES : _("Applying changes"),
423 ROLE_FIX_INCOMPLETE_INSTALL : _("Repairing incomplete installation"),
424 ROLE_FIX_BROKEN_DEPENDS: _("Repairing installed software"),
425 ROLE_ADD_REPOSITORY: _("Adding software source"),
426 ROLE_ENABLE_DISTRO_COMP: _("Enabling component of the distribution"),
427 ROLE_CLEAN: _("Removing downloaded package files"),
428 ROLE_RECONFIGURE: _("Reconfiguring installed packages"),
429 ROLE_PK_QUERY : _("Searching"),
430 ROLE_UNSET : ""
431 }
432
433def get_role_localised_present_from_enum(enum):
434 """Get the description of a present transaction action.
435
436 :param enum: The transaction role enum, e.g. :data:`ROLE_UPDATE_CACHE`.
437 :returns: The description string.
438 """
439 try:
440 return _PRESENT_ROLE[enum]
441 except KeyError:
442 return None
443
444_ERROR_ROLE = {
445 ROLE_INSTALL_FILE: _("Installation of the package file failed"),
446 ROLE_INSTALL_PACKAGES: _("Installation of software failed"),
447 ROLE_ADD_VENDOR_KEY_FILE: _("Adding the key to the list of trused "
448 "software vendors failed"),
449 ROLE_UPDATE_CACHE: _("Refreshing the software list failed"),
450 ROLE_REMOVE_VENDOR_KEY: _("Removing the vendor from the list of trusted "
451 "ones failed"),
452 ROLE_REMOVE_PACKAGES: _("Removing software failed"),
453 ROLE_UPGRADE_PACKAGES: _("Updating software failed"),
454 ROLE_UPGRADE_SYSTEM: _("Upgrading the system failed"),
455 ROLE_COMMIT_PACKAGES: _("Applying software changes failed"),
456 ROLE_FIX_INCOMPLETE_INSTALL: _("Repairing incomplete installation failed"),
457 ROLE_FIX_BROKEN_DEPENDS: _("Repairing broken dependencies failed"),
458 ROLE_ADD_REPOSITORY: _("Adding software source failed"),
459 ROLE_ENABLE_DISTRO_COMP: _("Enabling component of the distribution failed"),
460 ROLE_CLEAN: _("Removing downloaded package files failed"),
461 ROLE_RECONFIGURE: _("Removing downloaded package files failed"),
462 ROLE_PK_QUERY: _("Search failed"),
463 ROLE_ADD_LICENSE_KEY: _("Adding license key"),
464 ROLE_UNSET: ""
465 }
466
467def get_role_error_from_enum(enum):
468 """Get the description of a failed transaction action.
469
470 :param enum: The transaction role enum, e.g. :data:`ROLE_UPDATE_CACHE`.
471 :returns: The description string.
472 """
473 try:
474 return _ERROR_ROLE[enum]
475 except KeyError:
476 return None
477
478_DESCS_ERROR = {
479 ERROR_PACKAGE_DOWNLOAD_FAILED : _("Check your Internet connection."),
480 ERROR_REPO_DOWNLOAD_FAILED : _("Check your Internet connection."),
481 ERROR_CACHE_BROKEN : _("Check if you are using third party "
482 "repositories. If so disable them, since "
483 "they are a common source of problems.\n"
484 "Furthermore run the following command in a "
485 "Terminal: apt-get install -f"),
486 ERROR_KEY_NOT_INSTALLED : _("The selected file may not be a GPG key file "
487 "or it might be corrupt."),
488 ERROR_KEY_NOT_REMOVED : _("The selected key couldn't be removed. "
489 "Check that you provided a valid fingerprint."),
490 ERROR_NO_LOCK : _("Check if you are currently running another "
491 "software management tool, e.g. Synaptic or aptitude. "
492 "Only one tool is allowed to make changes at a time."),
493 ERROR_NO_CACHE : _("This is a serious problem. Try again later. If this "
494 "problem appears again, please report an error to the "
495 "developers."),
496 ERROR_NO_PACKAGE : _("Check the spelling of the package name, and "
497 "that the appropriate repository is enabled."),
498 ERROR_PACKAGE_UPTODATE : _("There isn't any need for an update."),
499 ERROR_PACKAGE_ALREADY_INSTALLED : _("There isn't any need for an "
500 "installation"),
501 ERROR_PACKAGE_NOT_INSTALLED : _("There isn't any need for a removal."),
502 ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE : _("You requested to remove a package "
503 "which is an essential part of your "
504 "system."),
505 ERROR_DAEMON_DIED : _("The connection to the daemon was lost. Most likely "
506 "the background daemon crashed."),
507 ERROR_PACKAGE_MANAGER_FAILED: _("The installation or removal of a software "
508 "package failed."),
509 ERROR_NOT_SUPPORTED: _("The requested feature is not supported."),
510 ERROR_UNKNOWN : _("There seems to be a programming error in aptdaemon, "
511 "the software that allows you to install/remove "
512 "software and to perform other package management "
513 "related tasks."),
514 ERROR_DEP_RESOLUTION_FAILED: _("This error could be caused by required "
515 "additional software packages which are "
516 "missing or not installable. Furthermore "
517 "there could be a conflict between software "
518 "packages which are not allowed to be "
519 "installed at the same time."),
520 ERROR_PACKAGE_UNAUTHENTICATED: _("The action would require the "
521 "installation of packages from not "
522 "authenticated sources."),
523 ERROR_INCOMPLETE_INSTALL: _("The installation could have failed because "
524 "of an error in the corresponding software "
525 "package or it was cancelled in an unfriendly "
526 "way. "
527 "You have to repair this before you can "
528 "install or remove any further software."),
529 ERROR_UNREADABLE_PACKAGE_FILE: _("Please copy the file to your local "
530 "computer and check the file "
531 "permissions."),
532 ERROR_INVALID_PACKAGE_FILE: _("The installation of a package which "
533 "violates the quality standards isn't "
534 "allowed. This could cause serious problems "
535 "on your computer. Please contact the person "
536 "or organisation who provided this package "
537 "file and include the details beneath."),
538 ERROR_LICENSE_KEY_INSTALL_FAILED: _("The downloaded license key which is "
539 "required to run this piece of "
540 "software is not valid or could not "
541 "be installed correctly.\n"
542 "See the details for more "
543 "information."),
544 ERROR_SYSTEM_ALREADY_UPTODATE: _("All available upgrades have already "
545 "been installed."),
546 ERROR_LICENSE_KEY_DOWNLOAD_FAILED: _("The license key which allows you to "
547 "use this piece of software could not be "
548 "downloaded. Please check your "
549 "network connection."),
550 }
551
552def get_error_description_from_enum(enum):
553 """Get a long description of an error.
554
555 :param enum: The transaction error enum, e.g. :data:`ERROR_NO_LOCK`.
556 :returns: The description string.
557 """
558 try:
559 return _DESCS_ERROR[enum]
560 except KeyError:
561 return None
562
563_STRINGS_ERROR = {
564 ERROR_PACKAGE_DOWNLOAD_FAILED : _("Failed to download package files"),
565 ERROR_REPO_DOWNLOAD_FAILED : _("Failed to download repository information"),
566 ERROR_DEP_RESOLUTION_FAILED : _("Package dependencies cannot be resolved"),
567 ERROR_CACHE_BROKEN : _("The package system is broken"),
568 ERROR_KEY_NOT_INSTALLED : _("Key was not installed"),
569 ERROR_KEY_NOT_REMOVED: _("Key was not removed"),
570 ERROR_NO_LOCK : _("Failed to lock the package manager"),
571 ERROR_NO_CACHE : _("Failed to load the package list"),
572 ERROR_NO_PACKAGE : _("Package does not exist"),
573 ERROR_PACKAGE_UPTODATE : _("Package is already up to date"),
574 ERROR_PACKAGE_ALREADY_INSTALLED : _("Package is already installed"),
575 ERROR_PACKAGE_NOT_INSTALLED : _("Package isn't installed"),
576 ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE : _("Failed to remove essential "
577 "system package"),
578 ERROR_DAEMON_DIED : _("Task cannot be monitored or controlled"),
579 ERROR_PACKAGE_MANAGER_FAILED: _("Package operation failed"),
580 ERROR_PACKAGE_UNAUTHENTICATED: _("Requires installation of untrusted "
581 "packages"),
582 ERROR_INCOMPLETE_INSTALL: _("Previous installation hasn't been completed"),
583 ERROR_INVALID_PACKAGE_FILE: _("The package is of bad quality"),
584 ERROR_UNREADABLE_PACKAGE_FILE: _("Package file could not be opened"),
585 ERROR_NOT_SUPPORTED: _("Not supported feature"),
586 ERROR_LICENSE_KEY_DOWNLOAD_FAILED: _("Failed to download the license key"),
587 ERROR_LICENSE_KEY_INSTALL_FAILED: _("Failed to install the license key"),
588 ERROR_SYSTEM_ALREADY_UPTODATE: _("The system is already up to date"),
589 ERROR_UNKNOWN : _("An unhandlable error occured")
590 }
591
592def get_error_string_from_enum(enum):
593 """Get a short description of an error.
594
595 :param enum: The transaction error enum, e.g. :data:`ERROR_NO_LOCK`.
596 :returns: The description string.
597 """
598 try:
599 return _STRINGS_ERROR[enum]
600 except KeyError:
601 return None
602
603_STRINGS_STATUS = {
604 STATUS_SETTING_UP : _("Waiting for service to start"),
605 STATUS_QUERY : _("Searching"),
606 STATUS_WAITING : _("Waiting"),
607 STATUS_WAITING_MEDIUM : _("Waiting for required medium"),
608 STATUS_WAITING_LOCK : _("Waiting for other software managers to quit"),
609 STATUS_WAITING_CONFIG_FILE_PROMPT : _("Waiting for configuration file "
610 "prompt"),
611 STATUS_RUNNING : _("Running task"),
612 STATUS_DOWNLOADING : _("Downloading"),
613 STATUS_DOWNLOADING_REPO : _("Querying software sources"),
614 STATUS_CLEANING_UP : _("Cleaning up"),
615 STATUS_RESOLVING_DEP : _("Resolving dependencies"),
616 STATUS_COMMITTING : _("Applying changes"),
617 STATUS_FINISHED : _("Finished"),
618 STATUS_CANCELLING : _("Cancelling"),
619 STATUS_LOADING_CACHE : _("Loading software list"),
620 STATUS_AUTHENTICATING : _("Waiting for authentication"),
621 }
622
623def get_status_string_from_enum(enum):
624 """Get the description of a transaction status.
625
626 :param enum: The transaction status enum, e.g. :data:`STATUS_WAITING`.
627 :returns: The description string.
628 """
629 try:
630 return _STRINGS_STATUS[enum]
631 except KeyError:
632 return None
633
634STRINGS_PKG_STATUS = {
635 #TRANSLATORS: %s is the name of a package
636 PKG_INSTALLING: _("Installing %s"),
637 #TRANSLATORS: %s is the name of a package
638 PKG_CONFIGURING: _( "Configuring %s"),
639 #TRANSLATORS: %s is the name of a package
640 PKG_REMOVING: _( "Removing %s"),
641 #TRANSLATORS: %s is the name of a package
642 PKG_PURGING: _( "Completely removing %s"),
643 #TRANSLATORS: %s is the name of a package
644 PKG_PURGING: _( "Noting disappearance of %s"),
645 #TRANSLATORS: %s is the name of a package
646 PKG_RUNNING_TRIGGER: _("Running post-installation trigger %s"),
647 #TRANSLATORS: %s is the name of a package
648 PKG_UPGRADING: _("Upgrading %s"),
649 #TRANSLATORS: %s is the name of a package
650 PKG_UNPACKING: _("Unpacking %s"),
651 #TRANSLATORS: %s is the name of a package
652 PKG_PREPARING_INSTALL: _("Preparing installation of %s"),
653 #TRANSLATORS: %s is the name of a package
654 PKG_PREPARING_CONFIGURE: _("Preparing configuration of %s"),
655 #TRANSLATORS: %s is the name of a package
656 PKG_PREPARING_REMOVE: _("Preparing removal of %s"),
657 #TRANSLATORS: %s is the name of a package
658 PKG_PREPARING_PURGE: _("Preparing complete removal of %s"),
659 #TRANSLATORS: %s is the name of a package
660 PKG_INSTALLED: _("Installed %s"),
661 #TRANSLATORS: %s is the name of a package
662 PKG_PURGED: _("Completely removed %s"),
663 #TRANSLATORS: %s is the name of a package
664 PKG_REMOVED: _("Removed %s"),
665 }
666
667def get_package_status_from_enum(enum):
668 """Get the description of a package status.
669
670 :param enum: The download status enum, e.g. :data:`PKG_INSTALLING`.
671 :returns: The description string.
672 """
673 try:
674 return STRINGS_PKG_STATUS[enum]
675 except KeyError:
676 return _("Processing %s"),
677
678STRINGS_DOWNLOAD = {
679 DOWNLOAD_DONE: _("Done"),
680 DOWNLOAD_AUTH_ERROR: _("Authentication failed"),
681 DOWNLOAD_ERROR: _("Failed"),
682 DOWNLOAD_FETCHING: _("Fetching"),
683 DOWNLOAD_IDLE: _("Idle"),
684 DOWNLOAD_NETWORK_ERROR: _("Network isn't available"),
685 }
686
687def get_download_status_from_enum(enum):
688 """Get the description of a download status.
689
690 :param enum: The download status enum, e.g. :data:`DOWNLOAD_DONE`.
691 :returns: The description string.
692 """
693 try:
694 return STRINGS_DOWNLOAD[enum]
695 except KeyError:
696 return None
697
698# vim:ts=4:sw=4:et
0699
=== added directory '.pc/fix-lp-932581.patch'
=== added directory '.pc/fix-lp-932581.patch/aptdaemon'
=== added file '.pc/fix-lp-932581.patch/aptdaemon/pkcompat.py'
--- .pc/fix-lp-932581.patch/aptdaemon/pkcompat.py 1970-01-01 00:00:00 +0000
+++ .pc/fix-lp-932581.patch/aptdaemon/pkcompat.py 2012-08-11 01:29:19 +0000
@@ -0,0 +1,2937 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3"""
4Provides a limited compatibility layer to PackageKit
5
6Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
7Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
8Copyright (C) 2008-2011 Sebastian Heinlein <glatzor@ubuntu.com>
9
10Licensed under the GNU General Public License Version 2
11
12This program is free software; you can redistribute it and/or modify
13it under the terms of the GNU General Public License as published by
14the Free Software Foundation; either version 2 of the License, or
15(at your option) any later version.
16"""
17
18__author__ = "Sebastian Heinlein <devel@glatzor.de>"
19
20import datetime
21import glob
22import gzip
23import locale
24import logging
25import os
26import re
27import subprocess
28import tempfile
29import time
30import traceback
31import uuid
32
33import apt
34import apt_pkg
35from defer import inline_callbacks, return_value
36from defer.utils import dbus_deferred_method
37import dbus
38from gi.repository import GObject
39import lsb_release
40import packagekit.enums as pk_enums
41
42# for optional plugin support
43try:
44 import pkg_resources
45except ImportError:
46 pkg_resources = None
47
48from aptdaemon import policykit1
49import aptdaemon.core
50from aptdaemon.core import APTDAEMON_TRANSACTION_DBUS_INTERFACE
51import aptdaemon.enums as aptd_enums
52from aptdaemon.errors import TransactionFailed, TransactionCancelled
53from aptdaemon.progress import DaemonAcquireProgress
54import aptdaemon.worker
55import aptdaemon.networking
56
57GObject.threads_init()
58
59pklog = logging.getLogger("AptDaemon.PackageKit")
60
61# Check if update-manager-core is installed to get aware of the
62# latest distro releases
63try:
64 from UpdateManager.Core.MetaRelease import MetaReleaseCore
65except ImportError:
66 META_RELEASE_SUPPORT = False
67else:
68 META_RELEASE_SUPPORT = True
69
70# Xapian database is optionally used to speed up package description search
71XAPIAN_DB_PATH = os.environ.get("AXI_DB_PATH", "/var/lib/apt-xapian-index")
72XAPIAN_DB = XAPIAN_DB_PATH + "/index"
73XAPIAN_DB_VALUES = XAPIAN_DB_PATH + "/values"
74XAPIAN_SUPPORT = False
75try:
76 import xapian
77except ImportError:
78 pass
79else:
80 if os.access(XAPIAN_DB, os.R_OK):
81 pklog.debug("Use XAPIAN for the search")
82 XAPIAN_SUPPORT = True
83
84# Regular expressions to detect bug numbers in changelogs according to the
85# Debian Policy Chapter 4.4. For details see the footnote 16:
86# http://www.debian.org/doc/debian-policy/footnotes.html#f16
87MATCH_BUG_CLOSES_DEBIAN=r"closes:\s*(?:bug)?\#?\s?\d+(?:,\s*(?:bug)?\#?\s?\d+)*"
88MATCH_BUG_NUMBERS=r"\#?\s?(\d+)"
89# URL pointing to a bug in the Debian bug tracker
90HREF_BUG_DEBIAN="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s"
91
92MATCH_BUG_CLOSES_UBUNTU = r"lp:\s+\#\d+(?:,\s*\#\d+)*"
93HREF_BUG_UBUNTU = "https://bugs.launchpad.net/bugs/%s"
94
95# Regular expression to find cve references
96MATCH_CVE="CVE-\d{4}-\d{4}"
97HREF_CVE="http://web.nvd.nist.gov/view/vuln/detail?vulnId=%s"
98
99# Map Debian sections to the PackageKit group name space
100SECTION_GROUP_MAP = {
101 "admin" : pk_enums.GROUP_ADMIN_TOOLS,
102 "base" : pk_enums.GROUP_SYSTEM,
103 "comm" : pk_enums.GROUP_COMMUNICATION,
104 "devel" : pk_enums.GROUP_PROGRAMMING,
105 "doc" : pk_enums.GROUP_DOCUMENTATION,
106 "editors" : pk_enums.GROUP_PUBLISHING,
107 "electronics" : pk_enums.GROUP_ELECTRONICS,
108 "embedded" : pk_enums.GROUP_SYSTEM,
109 "games" : pk_enums.GROUP_GAMES,
110 "gnome" : pk_enums.GROUP_DESKTOP_GNOME,
111 "graphics" : pk_enums.GROUP_GRAPHICS,
112 "hamradio" : pk_enums.GROUP_COMMUNICATION,
113 "interpreters" : pk_enums.GROUP_PROGRAMMING,
114 "kde" : pk_enums.GROUP_DESKTOP_KDE,
115 "libdevel" : pk_enums.GROUP_PROGRAMMING,
116 "libs" : pk_enums.GROUP_SYSTEM,
117 "mail" : pk_enums.GROUP_INTERNET,
118 "math" : pk_enums.GROUP_SCIENCE,
119 "misc" : pk_enums.GROUP_OTHER,
120 "net" : pk_enums.GROUP_NETWORK,
121 "news" : pk_enums.GROUP_INTERNET,
122 "oldlibs" : pk_enums.GROUP_LEGACY,
123 "otherosfs" : pk_enums.GROUP_SYSTEM,
124 "perl" : pk_enums.GROUP_PROGRAMMING,
125 "python" : pk_enums.GROUP_PROGRAMMING,
126 "science" : pk_enums.GROUP_SCIENCE,
127 "shells" : pk_enums.GROUP_SYSTEM,
128 "sound" : pk_enums.GROUP_MULTIMEDIA,
129 "tex" : pk_enums.GROUP_PUBLISHING,
130 "text" : pk_enums.GROUP_PUBLISHING,
131 "utils" : pk_enums.GROUP_ACCESSORIES,
132 "web" : pk_enums.GROUP_INTERNET,
133 "x11" : pk_enums.GROUP_DESKTOP_OTHER,
134 "unknown" : pk_enums.GROUP_UNKNOWN,
135 "alien" : pk_enums.GROUP_UNKNOWN,
136 "translations" : pk_enums.GROUP_LOCALIZATION,
137 "metapackages" : pk_enums.GROUP_COLLECTIONS }
138
139PACKAGEKIT_DBUS_INTERFACE = "org.freedesktop.PackageKit"
140PACKAGEKIT_DBUS_SERVICE = "org.freedesktop.PackageKit"
141PACKAGEKIT_DBUS_PATH = "/org/freedesktop/PackageKit"
142
143PACKAGEKIT_TRANS_DBUS_INTERFACE = "org.freedesktop.PackageKit.Transaction"
144PACKAGEKIT_TRANS_DBUS_SERVICE = "org.freedesktop.PackageKit.Transaction"
145
146MAP_EXIT_ENUM = {
147 aptd_enums.EXIT_SUCCESS: pk_enums.EXIT_SUCCESS,
148 aptd_enums.EXIT_CANCELLED: pk_enums.EXIT_CANCELLED,
149 aptd_enums.EXIT_FAILED: pk_enums.EXIT_FAILED,
150 aptd_enums.EXIT_FAILED: pk_enums.EXIT_FAILED,
151 aptd_enums.EXIT_PREVIOUS_FAILED:
152 pk_enums.EXIT_FAILED
153 }
154
155MAP_STATUS_ENUM = {
156 aptd_enums.STATUS_WAITING: pk_enums.STATUS_WAIT,
157 aptd_enums.STATUS_RUNNING: pk_enums.STATUS_RUNNING,
158 aptd_enums.STATUS_CANCELLING: pk_enums.STATUS_CANCEL,
159 aptd_enums.STATUS_CLEANING_UP: pk_enums.STATUS_CLEANUP,
160 aptd_enums.STATUS_COMMITTING: pk_enums.STATUS_COMMIT,
161 aptd_enums.STATUS_DOWNLOADING: pk_enums.STATUS_DOWNLOAD,
162 aptd_enums.STATUS_DOWNLOADING_REPO: pk_enums.STATUS_DOWNLOAD_REPOSITORY,
163 aptd_enums.STATUS_FINISHED: pk_enums.STATUS_FINISHED,
164 aptd_enums.STATUS_LOADING_CACHE: pk_enums.STATUS_LOADING_CACHE,
165 aptd_enums.STATUS_RESOLVING_DEP: pk_enums.STATUS_DEP_RESOLVE,
166 aptd_enums.STATUS_RUNNING: pk_enums.STATUS_RUNNING,
167 aptd_enums.STATUS_WAITING_LOCK:
168 pk_enums.STATUS_WAITING_FOR_LOCK,
169 aptd_enums.STATUS_WAITING_MEDIUM: pk_enums.STATUS_UNKNOWN,
170 aptd_enums.STATUS_WAITING_CONFIG_FILE_PROMPT:
171 pk_enums.STATUS_UNKNOWN
172}
173
174MAP_ERROR_ENUM = {
175 aptd_enums.ERROR_CACHE_BROKEN: pk_enums.ERROR_NO_CACHE,
176 aptd_enums.ERROR_DEP_RESOLUTION_FAILED:
177 pk_enums.ERROR_DEP_RESOLUTION_FAILED,
178 aptd_enums.ERROR_INCOMPLETE_INSTALL: pk_enums.ERROR_NO_CACHE,
179 aptd_enums.ERROR_INVALID_PACKAGE_FILE:
180 pk_enums.ERROR_PACKAGE_CORRUPT,
181 aptd_enums.ERROR_KEY_NOT_INSTALLED: pk_enums.ERROR_GPG_FAILURE,
182 aptd_enums.ERROR_KEY_NOT_REMOVED: pk_enums.ERROR_GPG_FAILURE,
183 aptd_enums.ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE:
184 pk_enums.ERROR_PACKAGE_FAILED_TO_REMOVE,
185 aptd_enums.ERROR_NO_CACHE: pk_enums.ERROR_NO_CACHE,
186 aptd_enums.ERROR_NO_LOCK: pk_enums.ERROR_CANNOT_GET_LOCK,
187 aptd_enums.ERROR_NO_PACKAGE: pk_enums.ERROR_PACKAGE_NOT_FOUND,
188 aptd_enums.ERROR_PACKAGE_ALREADY_INSTALLED:
189 pk_enums.ERROR_PACKAGE_ALREADY_INSTALLED,
190 aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED:
191 pk_enums.ERROR_PACKAGE_DOWNLOAD_FAILED,
192 aptd_enums.ERROR_PACKAGE_MANAGER_FAILED:
193 pk_enums.ERROR_TRANSACTION_ERROR,
194 aptd_enums.ERROR_PACKAGE_NOT_INSTALLED:
195 pk_enums.ERROR_PACKAGE_NOT_INSTALLED,
196 aptd_enums.ERROR_PACKAGE_UNAUTHENTICATED:
197 pk_enums.ERROR_BAD_GPG_SIGNATURE,
198 aptd_enums.ERROR_PACKAGE_UPTODATE:
199 pk_enums.ERROR_NO_PACKAGES_TO_UPDATE,
200 aptd_enums.ERROR_REPO_DOWNLOAD_FAILED:
201 pk_enums.ERROR_REPO_NOT_AVAILABLE,
202 aptd_enums.ERROR_UNREADABLE_PACKAGE_FILE:
203 pk_enums.ERROR_INVALID_PACKAGE_FILE,
204 aptd_enums.ERROR_SYSTEM_ALREADY_UPTODATE:
205 pk_enums.ERROR_NO_PACKAGES_TO_UPDATE,
206 }
207
208MAP_PACKAGE_ENUM = {
209 aptd_enums.PKG_CONFIGURING:
210 pk_enums.INFO_INSTALLING,
211 aptd_enums.PKG_DISAPPEARING:
212 pk_enums.INFO_UNKNOWN,
213 aptd_enums.PKG_INSTALLED:
214 pk_enums.INFO_FINISHED,
215 aptd_enums.PKG_INSTALLING:
216 pk_enums.INFO_INSTALLING,
217 aptd_enums.PKG_PREPARING_INSTALL:
218 pk_enums.INFO_PREPARING,
219 aptd_enums.PKG_PREPARING_PURGE:
220 pk_enums.INFO_PREPARING,
221 aptd_enums.PKG_PREPARING_REMOVE:
222 pk_enums.INFO_PREPARING,
223 aptd_enums.PKG_PURGED:
224 pk_enums.INFO_FINISHED,
225 aptd_enums.PKG_PURGING:
226 pk_enums.INFO_REMOVING,
227 aptd_enums.PKG_REMOVED:
228 pk_enums.INFO_FINISHED,
229 aptd_enums.PKG_REMOVING:
230 pk_enums.INFO_REMOVING,
231 aptd_enums.PKG_RUNNING_TRIGGER:
232 pk_enums.INFO_CLEANUP,
233 aptd_enums.PKG_UNKNOWN:
234 pk_enums.INFO_UNKNOWN,
235 aptd_enums.PKG_UNPACKING:
236 pk_enums.INFO_DECOMPRESSING,
237 aptd_enums.PKG_UPGRADING:
238 pk_enums.INFO_UPDATING,
239 }
240
241
242class PackageKit(aptdaemon.core.DBusObject):
243
244 """Provides a limited set of the PackageKit system D-Bus API."""
245
246 SUPPORTED_ROLES = [pk_enums.ROLE_REFRESH_CACHE,
247 pk_enums.ROLE_UPDATE_SYSTEM,
248 pk_enums.ROLE_SIMULATE_UPDATE_PACKAGES,
249 pk_enums.ROLE_UPDATE_PACKAGES,
250 pk_enums.ROLE_SIMULATE_REMOVE_PACKAGES,
251 pk_enums.ROLE_INSTALL_PACKAGES,
252 pk_enums.ROLE_SIMULATE_INSTALL_PACKAGES,
253 pk_enums.ROLE_INSTALL_PACKAGES,
254 pk_enums.ROLE_GET_DISTRO_UPGRADES,
255 pk_enums.ROLE_GET_UPDATES,
256 pk_enums.ROLE_GET_UPDATE_DETAIL,
257 pk_enums.ROLE_GET_PACKAGES,
258 pk_enums.ROLE_GET_DETAILS,
259 pk_enums.ROLE_GET_DEPENDS,
260 pk_enums.ROLE_GET_REQUIRES,
261 pk_enums.ROLE_SEARCH_NAME,
262 pk_enums.ROLE_SEARCH_DETAILS,
263 pk_enums.ROLE_SEARCH_GROUP,
264 pk_enums.ROLE_SEARCH_FILE,
265 pk_enums.ROLE_WHAT_PROVIDES,
266 pk_enums.ROLE_DOWNLOAD_PACKAGES]
267
268 SUPPORTED_FILTERS = [pk_enums.FILTER_INSTALLED,
269 pk_enums.FILTER_NOT_INSTALLED,
270 pk_enums.FILTER_FREE,
271 pk_enums.FILTER_NOT_FREE,
272 pk_enums.FILTER_GUI,
273 pk_enums.FILTER_NOT_GUI,
274 pk_enums.FILTER_COLLECTIONS,
275 pk_enums.FILTER_NOT_COLLECTIONS,
276 pk_enums.FILTER_SUPPORTED,
277 pk_enums.FILTER_NOT_SUPPORTED,
278 pk_enums.FILTER_NEWEST]
279
280 def __init__(self, queue, connect=True, bus=None):
281 """Initialize a new PackageKit compatibility layer.
282
283 Keyword arguments:
284 connect -- if the daemon should connect to the D-Bus (default is True)
285 bus -- the D-Bus to connect to (defaults to the system bus)
286 """
287 pklog.info("Initializing PackageKit compat layer")
288 bus_name = None
289 bus_path = None
290 if connect == True:
291 if bus is None:
292 bus = dbus.SystemBus()
293 self.bus = bus
294 bus_path = PACKAGEKIT_DBUS_PATH
295 bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, self.bus)
296 aptdaemon.core.DBusObject.__init__(self, bus_name, bus_path)
297 self._updates_changed_timeout_id = None
298 self._updates_changed = False
299 self.queue = queue
300 self.queue.worker.connect("transaction-done", self._on_transaction_done)
301 self.queue.connect("queue-changed", self._on_queue_changed)
302 self._distro_id = None
303 self.netmon = aptdaemon.networking.get_network_monitor()
304 self.netmon.connect("network-state-changed",
305 self._on_network_state_changed)
306 self.netmon.get_network_state()
307
308 # SIGNALS
309
310 # pylint: disable-msg=C0103,C0322
311 @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
312 signature="")
313 def RestartSchedule(self):
314 """A system restart has been sceduled."""
315 pass
316
317 # pylint: disable-msg=C0103,C0322
318 @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
319 signature="")
320 def Changed(self):
321 """This signal is emitted when a property on the interface changes."""
322 pass
323
324 # pylint: disable-msg=C0103,C0322
325 @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
326 signature="as")
327 def TransactionListChanged(self, transactions):
328 """The transaction list has changed, because either a transaction
329 has finished or a new transaction created.
330
331 :param transactions: A list of transaction ID's.
332 :type transactions: as
333 """
334 pklog.debug("Emitting TransactionListChanged signal: %s", transactions)
335
336 # pylint: disable-msg=C0103,C0322
337 @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
338 signature="")
339 def UpdatesChanged(self):
340 """This signal is emitted when the number of updates has changed."""
341 pklog.debug("Emitting UpdatesChanged signal")
342
343 # pylint: disable-msg=C0103,C0322
344 @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
345 signature="")
346 def RepoListChanged(self):
347 """This signal is emitted when the repository list has changed."""
348 pass
349
350 # pylint: disable-msg=C0103,C0322
351 @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
352 signature="")
353 def Changed(self):
354 """This signal is emitted when a property on the interface changes."""
355 pklog.debug("Emitting PackageKit Changed()")
356
357 # METHODS
358
359 # pylint: disable-msg=C0103,C0322
360 @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
361 in_signature="s", out_signature="s")
362 def CanAuthorize(self, action_id):
363 """Allows a client to find out if it would be allowed to authorize
364 an action.
365
366 :param action_id: The action ID, e.g.
367 org.freedesktop.packagekit.system-network-proxy-configure
368 :returns: The result, either yes, no or interactive.
369 """
370 #FIXME: We need to map packagekit and aptdaemon polices
371 return "interactive"
372
373 # pylint: disable-msg=C0103,C0322
374 @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
375 in_signature="s", out_signature="")
376 def StateHasChanged(self, reason):
377 """This method suggests to PackageKit that the package backend state
378 may have changed. This allows plugins to the native package manager
379 to suggest that PackageKit drops it's caches.
380
381 :param reason:
382 The reason of the state change. Valid reasons are resume or
383 posttrans. Resume is given a lower priority than posttrans.
384 """
385 pklog.debug("StateHasChanged() was called: %s", reason)
386 self._updates_changed = True
387 if reason == "cache-update":
388 self._check_updates_changed(timeout=30)
389 elif reason == "resume":
390 self._check_updates_changed(timeout=180)
391
392 # pylint: disable-msg=C0103,C0322
393 @dbus_deferred_method(PACKAGEKIT_DBUS_INTERFACE,
394 in_signature="", out_signature="s",
395 sender_keyword="sender")
396 def GetTid(self, sender):
397 """Gets a new transaction ID from the daemon.
398
399 :returns: The tid, e.g. 45_dafeca_checkpoint32
400 """
401 return self._get_tid(sender)
402
403 @inline_callbacks
404 def _get_tid(self, sender):
405 pid, uid, cmdline = \
406 yield policykit1.get_proc_info_from_dbus_name(sender, self.bus)
407 pktrans = PackageKitTransaction(pid, uid, cmdline, self.queue, sender)
408 return_value(pktrans.tid)
409
410 # pylint: disable-msg=C0103,C0322
411 @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
412 in_signature="", out_signature="as")
413 def GetTransactionList(self):
414 """Gets the transaction list of any transactions that are in
415 progress.
416
417 :returns: A list of transaction ID's
418 """
419 pklog.debug("GetTransactionList() was called")
420 return self._get_transaction_list()
421
422 # HELPERS
423
424 def _get_properties(self, iface):
425 """Helper to get the properties of a D-Bus interface."""
426 if iface == PACKAGEKIT_DBUS_INTERFACE:
427 return {# Claim that we are a stable version
428 "VersionMajor": dbus.UInt32(6),
429 "VersionMinor": dbus.UInt32(18),
430 "VersionMicro": dbus.UInt32(0),
431 "BackendName": dbus.String("aptdaemon"),
432 "BackendDescription": dbus.String("Compatibility layer"),
433 "BackendAuthor": dbus.String(__author__),
434 "Filters": dbus.String(";".join(self.SUPPORTED_FILTERS)),
435 "Groups": dbus.String(";".join(SECTION_GROUP_MAP.values())),
436 "Roles": dbus.String(";".join(self.SUPPORTED_ROLES)),
437 "Locked": dbus.Boolean(False),
438 "NetworkState": dbus.String(self.netmon.state),
439 "DistroId": dbus.String(self._get_distro_id()),
440 }
441 else:
442 return {}
443
444 def _get_distro_id(self):
445 """Return information about the distibution."""
446 if self._distro_id is None:
447 info = lsb_release.get_distro_information()
448 arch = subprocess.Popen(["dpkg", "--print-architecture"],
449 stdout=subprocess.PIPE).communicate()[0]
450 try:
451 self._distro_id = "%s;%s;%s" % (info["ID"], info["CODENAME"], arch)
452 except KeyError:
453 self._distro_id = "unknown;unknown;%s" % arch
454 return self._distro_id
455
456 def _on_network_state_changed(self, mon, state):
457 self.Changed()
458 self.PropertiesChanged(PACKAGEKIT_DBUS_INTERFACE,
459 {"Network": state}, [])
460
461 def _on_queue_changed(self, queue):
462 self.TransactionListChanged(self._get_transaction_list())
463 self._check_updates_changed()
464
465 def _get_transaction_list(self):
466 pk_transactions = []
467 for trans in self.queue.items:
468 # We currently only emit PackageKit transaction
469 #FIXME: Should we use MergedTransaction for all transactions and
470 # ROLE_UNKOWN for aptdaemon only transactions?
471 try:
472 pk_transactions.append(trans.pktrans.tid)
473 except AttributeError:
474 pass
475 try:
476 pk_transactions.append(self.queue.worker.trans.pktrans.tid)
477 except AttributeError:
478 pass
479 return pk_transactions
480
481 def _on_transaction_done(self, worker, trans):
482 # If a cache modifing transaction is completed schedule an
483 # UpdatesChanged signal
484 if trans.role in (aptd_enums.ROLE_INSTALL_FILE,
485 aptd_enums.ROLE_INSTALL_PACKAGES,
486 aptd_enums.ROLE_REMOVE_PACKAGES,
487 aptd_enums.ROLE_UPGRADE_PACKAGES,
488 aptd_enums.ROLE_COMMIT_PACKAGES,
489 aptd_enums.ROLE_UPGRADE_SYSTEM,
490 aptd_enums.ROLE_FIX_BROKEN_DEPENDS):
491 self._updates_changed = True
492 self._check_updates_changed()
493 elif trans.role == aptd_enums.ROLE_UPDATE_CACHE:
494 self._updates_changed = True
495 self._check_updates_changed(timeout=30)
496
497 def _check_updates_changed(self, timeout=60):
498 """After the queue was processed schedule a delayed UpdatesChanged
499 signal if required.
500 """
501 if not self.queue.items and self._updates_changed:
502 if self._updates_changed_timeout_id:
503 # If we already have a scheduled UpdatesChanged signal
504 # delay it even further
505 pklog.debug("UpdatesChanged signal re-scheduled")
506 GObject.source_remove(self._updates_changed_timeout_id)
507 else:
508 pklog.debug("UpdatesChanged signal scheduled")
509 self._updates_changed_timeout_id = \
510 GObject.timeout_add_seconds(timeout,
511 self._delayed_updates_changed)
512
513 def _delayed_updates_changed(self):
514 """Emit the UpdatesChanged signal and clear the timeout."""
515 self.UpdatesChanged()
516 self._updates_changed_timeout_id = None
517 self._updates_changed = False
518 return False
519
520
521class MergedTransaction(aptdaemon.core.Transaction):
522
523 """Overlay of an Aptdaemon transaction which also provides the
524 PackageKit object and its interfaces.
525 """
526
527 def __init__(self, pktrans, role, queue, connect=True,
528 bus=None, packages=None, kwargs=None):
529 aptdaemon.core.Transaction.__init__(self, pktrans.tid[1:], role, queue,
530 pktrans.pid, pktrans.uid,
531 pktrans.cmdline, pktrans.sender,
532 connect, bus, packages, kwargs)
533 self.pktrans = pktrans
534 self.run_time = 0
535
536 def _set_status(self, enum):
537 aptdaemon.core.Transaction._set_status(self, enum)
538 self.pktrans.status = get_pk_status_enum(enum)
539
540 status = property(aptdaemon.core.Transaction._get_status, _set_status)
541
542 def _set_progress(self, percent):
543 aptdaemon.core.Transaction._set_progress(self, percent)
544 self.pktrans.percentage = self._progress
545
546 progress = property(aptdaemon.core.Transaction._get_progress, _set_progress)
547
548 def _set_progress_details(self, details):
549 aptdaemon.core.Transaction._set_progress_details(self, details)
550 self.pktrans.speed = int(details[4])
551 self.pktrans.remaining_time = int(details[5])
552 self.pktrans.elapsed_time = int(time.time() - self.pktrans.start_time)
553
554 progress_details = property(aptdaemon.core.Transaction._get_progress_details,
555 _set_progress_details)
556
557 def _set_progress_package(self, progress):
558 aptdaemon.core.Transaction._set_progress_package(self, progress)
559 pkg_name, enum = progress
560 self.emit_package(get_pk_package_enum(enum),
561 get_pk_package_id(pkg_name),
562 "")
563
564 progress_package = property(aptdaemon.core.Transaction._get_progress_package,
565 _set_progress_package)
566
567
568 def _set_exit(self, enum):
569 aptdaemon.core.Transaction._set_exit(self, enum)
570 self.pktrans.exit = get_pk_exit_enum(enum)
571
572 exit = property(aptdaemon.core.Transaction._get_exit, _set_exit)
573
574 def _set_error(self, excep):
575 aptdaemon.core.Transaction._set_error(self, excep)
576 self.pktrans.ErrorCode(get_pk_error_enum(excep.code),
577 self._error_property[1])
578
579 error = property(aptdaemon.core.Transaction._get_error, _set_error)
580
581 def _remove_from_connection_no_raise(self):
582 aptdaemon.core.Transaction._remove_from_connection_no_raise(self)
583 self.pktrans.Destroy()
584 try:
585 self.pktrans.remove_from_connection()
586 except LookupError as error:
587 pklog.debug("remove_from_connection() raised LookupError: %s",
588 error)
589 finally:
590 self.pktrans.trans = None
591 self.pktrans = None
592 return False
593
594 def emit_details(self, package_id, license, group, detail, url, size):
595 self.pktrans.Details(package_id, license, group, detail, url, size)
596
597 def emit_files(self, id, file_list):
598 self.pktrans.Files(id, file_list)
599
600 def emit_package(self, info, id, summary):
601 self.pktrans.Package(info, id, summary)
602 self.pktrans.last_package = id
603
604 def emit_update_detail(self, package_id, updates, obsoletes, vendor_url,
605 bugzilla_url, cve_url, restart, update_text,
606 changelog, state, issued, updated):
607 self.pktrans.UpdateDetail(package_id, updates, obsoletes, vendor_url,
608 bugzilla_url, cve_url, restart, update_text,
609 changelog, state, issued, updated)
610
611
612class PackageKitTransaction(aptdaemon.core.DBusObject):
613
614 """Provides a PackageKit transaction object."""
615
616 def __init__(self, pid, uid, cmdline, queue, sender,
617 connect=True, bus=None):
618 pklog.info("Initializing PackageKit transaction")
619 bus_name = None
620 bus_path = None
621 self.tid = "/%s" % uuid.uuid4().get_hex()
622 if connect == True:
623 if bus is None:
624 bus = dbus.SystemBus()
625 self.bus = bus
626 bus_path = self.tid
627 bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, bus)
628 aptdaemon.core.DBusObject.__init__(self, bus_name, bus_path)
629 self.queue = queue
630 self.hints = {}
631 self.start_time = time.time()
632 self._elapsed_time = 0
633 self._remaining_time = 0
634 self._speed = 0
635 self._caller_active = True
636 self._allow_cancel = False
637 self._percentage = 0
638 self._subpercentage = 0
639 self._status = pk_enums.STATUS_SETUP
640 self._last_package = ""
641 self.uid = uid
642 self.pid = pid
643 self.cmdline = cmdline
644 self.role = pk_enums.ROLE_UNKNOWN
645 self.sender = sender
646 self.trans = None
647
648 @property
649 def allow_cancel(self):
650 return self._allow_cancel
651
652 @allow_cancel.setter
653 def allow_cancel(self, value):
654 self._allow_cancel = dbus.Boolean(value)
655 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
656 {"AllowCancel": self._allow_cancel}, [])
657 self.Changed()
658
659 @property
660 def last_package(self):
661 return self._last_package
662
663 @last_package.setter
664 def last_package(self, value):
665 self._last_package = dbus.String(value)
666 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
667 {"LastPackage": self._last_package}, [])
668 self.Changed()
669
670 @property
671 def caller_active(self):
672 return self._caller_active
673
674 @caller_active.setter
675 def caller_active(self, value):
676 self._caller_active = dbus.Boolean(value)
677 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
678 {"CallerActive": self._caller_active}, [])
679 self.Changed()
680
681 @property
682 def percentage(self):
683 return self._percentage
684
685 @percentage.setter
686 def percentage(self, progress):
687 self._percentage = dbus.UInt32(progress)
688 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
689 {"Percentage": self._percentage}, [])
690 self.Changed()
691
692 @property
693 def subpercentage(self):
694 return self._subpercentage
695
696 @subpercentage.setter
697 def subpercentage(self, progress):
698 self._subpercentage = dbus.UInt32(progress)
699 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
700 {"SubPercentage": self._subpercentage}, [])
701 self.Changed()
702
703 @property
704 def status(self):
705 return self._status
706
707 @status.setter
708 def status(self, enum):
709 self._status = dbus.String(enum)
710 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
711 {"Status": self._status}, [])
712 self.Changed()
713
714 @property
715 def elapsed_time(self):
716 return self._elapsed_time
717
718 @elapsed_time.setter
719 def elapsed_time(self, ela):
720 self._elpased_time = dbus.UInt32(ela)
721 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
722 {"ElapsedTime": self._elapsed_time}, [])
723 self.Changed()
724
725 @property
726 def remaining_time(self):
727 return self._remaining_time
728
729 @remaining_time.setter
730 def remaining_time(self, value):
731 self._elpased_time = dbus.UInt32(value)
732 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
733 {"RemainingTime": self._remaining_time}, [])
734 self.Changed()
735
736 @property
737 def speed(self):
738 return self._speed
739
740 @speed.setter
741 def speed(self, speed):
742 self._speed = dbus.UInt32(speed)
743 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
744 {"AllowCancel": self._speed}, [])
745 self.Changed()
746
747 @property
748 def exit(self):
749 return self._exit
750
751 @exit.setter
752 def exit(self, enum):
753 self._exit = exit
754 self.run_time = int((time.time() - self.start_time) * 1000)
755 # The time could go backwards ...
756 if self.run_time < 0:
757 self.run_time = 0
758 if enum == pk_enums.EXIT_CANCELLED:
759 self.ErrorCode(pk_enums.ERROR_TRANSACTION_CANCELLED, "")
760 self.status = pk_enums.STATUS_FINISHED
761 self.Finished(enum, self.run_time)
762
763
764 # SIGNALS
765
766 # pylint: disable-msg=C0103,C0322
767 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
768 signature="ssbsusus")
769 def Transaction(self, old_tid, timespec, succeeded, role, duration, data,
770 uid, cmdline):
771 """This signal is sent when more details are required about a
772 specific transaction.
773
774 :param old_tid: The transaction ID of the old transaction.
775 :param timespec: The timespec of the old transaction in ISO8601 format.
776 :param succeeded: If the transaction succeeded.
777 :param role: The role enumerated type.
778 :param duration: The duration of the transaction in milliseconds.
779 :param data: Any data associated
780 :param uid: The user ID of the user that scheduled the action.
781 :param cmdline: The command line of the tool that scheduled the action,
782 e.g. /usr/bin/gpk-application.
783 """
784 pass
785
786 # pylint: disable-msg=C0103,C0322
787 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
788 signature="ss")
789 def ErrorCode(self, code, details):
790 """This signal is used to report errors back to the session program.
791 Errors should only be send on fatal abort.
792
793 :param code: Enumerated type, e.g. no-network.
794 :param details: Long description or error, e.g. "failed to connect"
795
796 :type code: s
797 :type details: s
798 """
799 pass
800
801 # pylint: disable-msg=C0103,C0322
802 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
803 signature="")
804 def Changed(self):
805 """This signal is emitted when a property on the interface changes."""
806 pklog.debug("Emitting PackageKitTransaction Changed()")
807
808 # pylint: disable-msg=C0103,C0322
809 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
810 signature="")
811 def Destroy(self):
812 """This signal is sent when the transaction has been destroyed
813 and is no longer available for use."""
814 pklog.debug("Emmitting Destroy()")
815
816 # pylint: disable-msg=C0103,C0322
817 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
818 signature="su")
819 def Finished(self, exit, runtime):
820 """This signal is used to signal that the transaction has finished.
821 :param exit: The PkExitEnum describing the exit status of the
822 transaction.
823 :param runtime: The amount of time in milliseconds that the
824 transaction ran for.
825
826 :type exit: s
827 :type runtime: u
828 """
829 pklog.debug("Emitting Finished: %s, %s", exit, runtime)
830 pass
831
832 # pylint: disable-msg=C0103,C0322
833 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
834 signature="ssssst")
835 def Details(self, package_id, license, group, detail, url, size):
836 """This signal allows the backend to convey more details about the
837 package.
838
839 :param package_id: The package ID
840
841 :param license:
842 The license string, e.g. GPLv2+ or BSD and (MPLv1.1 or GPLv2+).
843 Moredetails about the correct way to format licensing strings can
844 be found on the Fedora packaging wiki.
845 :param group:
846 The enumerated package group description
847 :param detail:
848 The multi-line package description. If formatting is required,
849 then markdown syntax should be used, e.g. This is **critically**
850 important
851 :param url:
852 The upstream project homepage
853 :param size:
854 The size of the package in bytes. This should be the size of the
855 entire package file, not the size of the files installed on the
856 system. If the package is not installed, and already downloaded
857 and present in the package manager cache, then this value should
858 be set to zero.
859 """
860 pklog.debug("Emmitting Details signal for %s", package_id)
861
862 # pylint: disable-msg=C0103,C0322
863 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
864 signature="ss")
865 def Files(self, package_id, file_list):
866 """This signal is used to push file lists from the backend to the
867 session.
868
869 :param package_id:
870 The Package ID that called the method.
871 :param file_list:
872 The file list, with each file seporated with ;.
873 """
874 pklog.debug("Emitting Files signal: %s, %s", package_id, file_list)
875
876 # pylint: disable-msg=C0103,C0322
877 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
878 signature="ssssssssssss")
879 def UpdateDetail(self, package_id, updates, obsoletes, vendor_url,
880 bugzilla_url, cve_url, restart, update_text, changelog,
881 state, issued, updated):
882 """This signal is sent when more details are required about a
883 specific update.
884
885 :param package_id: The package ID
886 :param updates:
887 A list of package_id's that are to be updated, seporated by
888 &. This odd delimited was chosen as \t is already being used
889 in the spawned backends, and & is a banned character in a
890 package_id.
891 :param obsoletes:
892 A list of package_id's that are to be obsoleted, separated by &
893 :param vendor_url:
894 A URL with more details on the update, e.g. a page with more
895 information on the update. The format of this command should
896 be http://www.foo.org/page.html?4567;Update to SELinux
897 :param bugzilla_url:
898 A bugzilla URL with more details on the update. If no URL is
899 available then this field should be left empty.
900 :param cve_url:
901 A CVE URL with more details on the security advisory.
902 :param restart:
903 A valid restart type, e.g. system.
904 :param update_text:
905 The update text describing the update. If formatting is required,
906 then markdown syntax should be used, e.g. This is **critically**
907 important.
908 :param changelog:
909 The ChangeLog text describing the changes since the last version.
910 :param state:
911 The state of the update, e.g. stable or testing.
912 :param issued:
913 The ISO8601 encoded date that the update was issued.
914 :param updated:
915 The ISO8601 encoded date that the update was updated.
916 """
917 pklog.debug("Emmitting UpdateDetail signal for %s", package_id)
918
919 # pylint: disable-msg=C0103,C0322
920 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
921 signature="sss")
922 def Package(self, info, package_id, summary):
923 """This signal allows the backend to communicate packages to the
924 session.
925
926 If updating, as packages are updated then emit them to the screen.
927 This allows a summary to be presented after the transaction.
928 When returning results from a search always return installed
929 before available for the same package name.
930
931 :param info: A valid info string enumerated type
932 :param package_id: This identifier is of the form
933 name;version;arch;data in a single string and is meant to
934 represent a single package unique across all local and remote
935 data stores. For a remote, not-installed package the data
936 field should be set as the repository identifier or repository
937 name. The data field for an installed package must be prefixed
938 with installed as this is used to identify which packages are
939 installable or installed in the client tools. As a special
940 extension, if the package manager is able to track which
941 repository a package was originally installed from, then the data
942 field can be set to installed:REPO-NAME which allows the frontend
943 client to advise the user of the package origin. The data field
944 for a non-installed local package must be local as this signifies
945 a repository name is not available and that package resides
946 locally on the client system rather than in any specific
947 repository.
948 :param summary: The one line package summary, e.g. Clipart for
949 OpenOffice
950 """
951 pklog.debug("Emmitting Package signal: info=%s id=%s summary='%s'",
952 info, package_id, summary[:10])
953
954 # pylint: disable-msg=C0103,C0322
955 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
956 signature="sss")
957 def DistroUpgrade(self, type, name, summary):
958 """This signal allows the backend to communicate distribution upgrades
959 to the session.
960 :param type: A valid upgrade string enumerated type, e.g. stable
961 or unstable
962 :param name: The short name of the distribution, e.g. Fedora Core
963 10 RC1
964 :param summary: The multi-line description of the release
965 """
966 pass
967
968 # pylint: disable-msg=C0103,C0322
969 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
970 signature="ss")
971 def RequireRestart(self, restart_type, package_id):
972 """This signal is sent when the session client should notify the user
973 that a restart is required to get all changes into effect.
974
975 :param package_id:
976 The Package ID of the package tiggering the restart
977 :param file_list:
978 One of system, application or session
979 """
980 pklog.debug("Emitting RequireRestart signal: %s, %s",
981 restart_type, package_id)
982
983 # METHODS
984
985 # pylint: disable-msg=C0103,C0322
986 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
987 in_signature="as", out_signature="")
988 def SetHints(self, hints):
989 """This method allows the calling session to set transaction hints
990 for the package manager which can change as the transaction runs.
991
992 This method can be sent before the transaction has been run or
993 whilst it is running. There is no limit to the number of times
994 this method can be sent, although some backends may only use the
995 values that were set before the transaction was started.
996
997 Each parameter value is optional.
998
999 :param hints: The values as an array of strings, for example
1000 ['locale=en_GB.utf8','interactive=false','cache-age=3600']
1001 """
1002 for hint in hints:
1003 key, value = hint.split("=", 1)
1004 if key not in ["locale", "idle", "background", "interactive",
1005 "cache-age", "frontend-socket"]:
1006 raise Exception("Invalid option %s" % key)
1007 self.hints[key] = value
1008
1009 # pylint: disable-msg=C0103,C0322
1010 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1011 in_signature="", out_signature="",
1012 sender_keyword="sender")
1013 def Cancel(self, sender):
1014 """This method cancels a transaction that is already running."""
1015 if self.trans:
1016 return self.trans._cancel(sender)
1017
1018 # pylint: disable-msg=C0103,C0322
1019 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1020 in_signature="asbb", out_signature="",
1021 sender_keyword="sender")
1022 def RemovePackages(self, package_ids, allow_deps, autoremove, sender):
1023 """This method removes packages from the local system.
1024
1025 This method typically emits Progress, Status and Error and Package.
1026
1027 Package enumerated types should be downloading, updating, installing or removing.
1028
1029 :param package_ids: An array of package IDs.
1030 :param allow_deps:
1031 Either true or false. If true allow other packages to be removed
1032 with the package, but false should cause the script to abort if
1033 other packages are dependant on the package.
1034 :param autoremove:
1035 Either true or false. This option is only really interesting on
1036 embedded devices with a limited amount of flash storage. It
1037 suggests to the packagekit backend that dependencies installed at
1038 the same time as the package should also be removed if they are not
1039 required by anything else. For instance, if you install OpenOffice,
1040 it might download libneon as a dependency. When auto_remove is set
1041 to true, and you remove OpenOffice then libneon will also get
1042 removed automatically.
1043 """
1044 pklog.debug("RemovePackages() was called")
1045 self.role = pk_enums.ROLE_REMOVE_PACKAGES
1046 return self._remove_packages(package_ids, allow_deps, autoremove,
1047 sender)
1048
1049 @inline_callbacks
1050 def _remove_packages(self, package_ids, allow_deps, autoremove, sender):
1051 self.trans = self._get_merged_trans(aptd_enums.ROLE_REMOVE_PACKAGES,
1052 pkg_ids=package_ids,
1053 pkg_type=aptd_enums.PKGS_REMOVE)
1054 yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
1055 "RemoveObsoletedDepends", autoremove,
1056 sender)
1057 try:
1058 yield self.trans._simulate(sender)
1059 except aptdameon.errors.TransactionFailed:
1060 raise StopIteration
1061 for pkgs in self.trans.depends:
1062 if pkgs:
1063 error_code = packagekit.errors.ERROR_DEP_RESOLUTION_FAILED
1064 self.trans.pktrans.ErrorCode(error_code,
1065 "Would change additional packages")
1066 self.trans.pktrans.exit = pk_enums.EXIT_FAILED
1067 yield self.trans._run(sender)
1068
1069 # pylint: disable-msg=C0103,C0322
1070 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1071 in_signature="asb", out_signature="",
1072 sender_keyword="sender")
1073 def SimulateRemovePackages(self, package_ids, autoremove, sender):
1074 """This method simulates a package update emitting packages
1075 required to be installed, removed, updated, reinstalled,
1076 downgraded, obsoleted or untrusted. The latter is used to present
1077 the user untrusted packages that are about to be installed.
1078
1079 This method typically emits Error and Package.
1080
1081 :param package_ids: An array of package IDs.
1082 :param autoremove:
1083 Either true or false. This option is only really interesting on
1084 embedded devices with a limited amount of flash storage. It
1085 suggests to the packagekit backend that dependencies installed at
1086 the same time as the package should also be removed if they are not
1087 required by anything else. For instance, if you install OpenOffice,
1088 it might download libneon as a dependency. When auto_remove is set
1089 to true, and you remove OpenOffice then libneon will also get
1090 removed automatically.
1091 """
1092 pklog.debug("SimulateRemovePackages() was called")
1093 GObject.idle_add(defer_idle, self._simulate_remove_packages,
1094 package_ids, autoremove, sender)
1095
1096 @inline_callbacks
1097 def _simulate_remove_packages(self, package_ids, autoremove, sender):
1098 self.role = pk_enums.ROLE_SIMULATE_REMOVE_PACKAGES
1099 self.status = pk_enums.STATUS_DEP_RESOLVE
1100 self.trans = self._get_merged_trans(aptd_enums.ROLE_REMOVE_PACKAGES,
1101 pkg_ids=package_ids,
1102 pkg_type=aptd_enums.PKGS_REMOVE)
1103 yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
1104 "RemoveObsoletedDepends", autoremove,
1105 sender)
1106 yield self._simulate_and_emit_packages(sender)
1107
1108
1109 # pylint: disable-msg=C0103,C0322
1110 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1111 in_signature="bas", out_signature="",
1112 sender_keyword="sender")
1113 def UpdatePackages(self, only_trusted, package_ids, sender):
1114 """This method updates existing packages on the local system.
1115
1116 The installer should always update extra packages automatically
1117 to fulfil dependencies.
1118
1119 This should allow an application to find out what package owns a
1120 file on the system.
1121
1122 This method typically emits Progress, Status and Error and Package.
1123
1124 :param only_trusted:
1125 If the transaction is only allowed to install trusted packages.
1126 Unsigned packages should not be installed if this parameter is
1127 TRUE. If this method is can only install trusted packages, and
1128 the packages are unsigned, then the backend will send a
1129 ErrorCode(missing-gpg-signature). On recieving this error, the
1130 client may choose to retry with only_trusted FALSE after
1131 gaining further authentication.
1132 : param package_ids: An array of package IDs.
1133 """
1134 pklog.debug("UpdatePackages() was called")
1135 return self._update_packages(only_trusted, package_ids, sender)
1136
1137 @inline_callbacks
1138 def _update_packages(self, only_trusted, package_ids, sender):
1139 self.role = pk_enums.ROLE_UPDATE_PACKAGES
1140 self.trans = self._get_merged_trans(aptd_enums.ROLE_UPGRADE_PACKAGES,
1141 pkg_ids=package_ids,
1142 pkg_type=aptd_enums.PKGS_UPGRADE)
1143 yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
1144 "AllowUnauthenticated", not only_trusted,
1145 sender)
1146 yield self.trans._run(sender)
1147
1148 # pylint: disable-msg=C0103,C0322
1149 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1150 in_signature="as", out_signature="",
1151 sender_keyword="sender")
1152 def SimulateUpdatePackages(self, package_ids, sender):
1153 """This method simulates a package update emitting packages
1154 required to be installed, removed, updated, reinstalled,
1155 downgraded, obsoleted or untrusted. The latter is used to present
1156 the user untrusted packages that are about to be installed.
1157
1158 This method typically emits Error and Package.
1159
1160 :param package_ids: An array of package IDs.
1161 """
1162 pklog.debug("SimulateUpdatePackages() was called")
1163 self.role = pk_enums.ROLE_SIMULATE_UPDATE_PACKAGES
1164 GObject.idle_add(defer_idle, self._simulate_update_packages,
1165 package_ids, sender)
1166
1167 @inline_callbacks
1168 def _simulate_update_packages(self, package_ids, sender):
1169 self.status = pk_enums.STATUS_RUNNING
1170 self.trans = self._get_merged_trans(aptd_enums.ROLE_UPGRADE_PACKAGES,
1171 pkg_ids=package_ids,
1172 pkg_type=aptd_enums.PKGS_UPGRADE)
1173 yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
1174 "AllowUnauthenticated", True, sender)
1175 yield self._simulate_and_emit_packages(sender)
1176
1177 # pylint: disable-msg=C0103,C0322
1178 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1179 in_signature="bas", out_signature="",
1180 sender_keyword="sender")
1181 def InstallPackages(self, only_trusted, package_ids, sender):
1182 """This method installs new packages on the local system.
1183
1184 The installer should always install extra packages automatically
1185 as the use could call GetDepends prior to the install if a
1186 confirmation is required in the UI.
1187
1188 This method typically emits Progress, Status and Error and Package.
1189
1190 Package enumerated types should be downloading, updating,
1191 installing or removing.
1192
1193 :param only_trusted:
1194 If the transaction is only allowed to install trusted packages.
1195 Unsigned packages should not be installed if this parameter is
1196 TRUE. If this method is can only install trusted packages, and
1197 the packages are unsigned, then the backend will send a
1198 ErrorCode(missing-gpg-signature). On recieving this error, the
1199 client may choose to retry with only_trusted FALSE after
1200 gaining further authentication.
1201 : param package_ids: An array of package IDs.
1202 """
1203 pklog.debug("InstallPackages() was called")
1204 self.role = pk_enums.ROLE_INSTALL_PACKAGES
1205 return self._install_packages(only_trusted, package_ids, sender)
1206
1207 @inline_callbacks
1208 def _install_packages(self, only_trusted, package_ids, sender):
1209 self.trans = self._get_merged_trans(aptd_enums.ROLE_INSTALL_PACKAGES,
1210 pkg_ids=package_ids,
1211 pkg_type=aptd_enums.PKGS_INSTALL)
1212 yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
1213 "AllowUnauthenticated", not only_trusted,
1214 sender)
1215 yield self.trans._run(sender)
1216
1217 # pylint: disable-msg=C0103,C0322
1218 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1219 in_signature="as", out_signature="",
1220 sender_keyword="sender")
1221 def SimulateInstallPackages(self, package_ids, sender):
1222 """This method simulates a package instalation emitting packages
1223 required to be installed, removed, updated, reinstalled, downgraded,
1224 obsoleted or untrusted. The latter is used to present the user
1225 untrusted packages that are about to be installed.
1226
1227 This method typically emits Error and Package.
1228
1229 :param package_ids: An array of package IDs.
1230 """
1231 pklog.debug("SimulateInstallPackages() was called")
1232 self.role = pk_enums.ROLE_SIMULATE_INSTALL_PACKAGES
1233 GObject.idle_add(defer_idle, self._simulate_install_packages,
1234 package_ids, sender)
1235
1236 @inline_callbacks
1237 def _simulate_install_packages(self, package_ids, sender):
1238 self.status = pk_enums.STATUS_RUNNING
1239 self.trans = self._get_merged_trans(aptd_enums.ROLE_INSTALL_PACKAGES,
1240 pkg_ids=package_ids,
1241 pkg_type=aptd_enums.PKGS_INSTALL)
1242 yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
1243 "AllowUnauthenticated", True, sender)
1244 yield self._simulate_and_emit_packages(sender)
1245
1246 @inline_callbacks
1247 def _simulate_and_emit_packages(self, sender, update_info=None):
1248 try:
1249 yield self.trans._simulate(sender)
1250 except:
1251 raise StopIteration
1252 for pkg in self.trans.depends[aptd_enums.PKGS_INSTALL]:
1253 self.Package(pk_enums.INFO_INSTALLING,
1254 get_pk_package_id(pkg), "")
1255 for pkg in self.trans.depends[aptd_enums.PKGS_REINSTALL]:
1256 self.Package(pk_enums.INFO_REINSTALLING,
1257 get_pk_package_id(pkg, "installed"), "")
1258 for pkg in self.trans.depends[aptd_enums.PKGS_REMOVE]:
1259 self.Package(pk_enums.INFO_REMOVING,
1260 get_pk_package_id(pkg, "installed"), "")
1261 for pkg in self.trans.depends[aptd_enums.PKGS_PURGE]:
1262 self.Package(pk_enums.INFO_REMOVING,
1263 get_pk_package_id(pkg, "installed"), "")
1264 for pkg in self.trans.depends[aptd_enums.PKGS_UPGRADE]:
1265 self.Package(update_info or pk_enums.INFO_UPDATING,
1266 get_pk_package_id(pkg, None), "")
1267 for pkg in self.trans.depends[aptd_enums.PKGS_DOWNGRADE]:
1268 self.Package(pk_enums.INFO_DOWNGRADING,
1269 get_pk_package_id(pkg), "")
1270 for pkg in self.trans.depends[aptd_enums.PKGS_KEEP]:
1271 self.Package(pk_enums.INFO_BLOCKED,
1272 get_pk_package_id(pkg), "")
1273 self.status = pk_enums.STATUS_FINISHED
1274 self.Finished(pk_enums.EXIT_SUCCESS, 0)
1275
1276 # pylint: disable-msg=C0103,C0322
1277 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1278 in_signature="b", out_signature="",
1279 sender_keyword="sender")
1280 def RefreshCache(self, force, sender):
1281 """This method should fetch updated meta-data for all enabled
1282 repositories.
1283
1284 When fetching each software source, ensure to emit RepoDetail for
1285 the current source to give the user interface some extra details.
1286 Be sure to have the "enabled" field set to true, otherwise you
1287 wouldn't be fetching that source.
1288
1289 This method typically emits Progress, Error and RepoDetail.
1290
1291 :param force: If the caches should be cleaned and reloaded even if
1292 there is valid, up to date data.
1293 """
1294 pklog.debug("RefreshCache() was called")
1295 self.role = pk_enums.ROLE_REFRESH_CACHE
1296 return self._refresh_cache(force, sender)
1297
1298 @inline_callbacks
1299 def _refresh_cache(self, force, sender):
1300 self.trans = self._get_merged_trans(aptd_enums.ROLE_UPDATE_CACHE,
1301 kwargs={"sources_list": None})
1302 yield self.trans._run(sender)
1303
1304 # pylint: disable-msg=C0103,C0322
1305 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1306 in_signature="b", out_signature="",
1307 sender_keyword="sender")
1308 def UpdateSystem(self, only_trusted, sender):
1309 """This method updates all packages on the system to thier newest
1310 versions.
1311
1312 The installer should update all the updateable packages on the
1313 system, including automatically installing any new packages that
1314 are needed for dependancies.
1315
1316 :param only_trusted:
1317 If the transaction is only allowed to install trusted packages.
1318 Unsigned packages should not be installed if this parameter is
1319 TRUE. If this method is can only install trusted packages, and
1320 the packages are unsigned, then the backend will send a
1321 ErrorCode(missing-gpg-signature). On recieving this error, the
1322 client may choose to retry with only_trusted FALSE after
1323 gaining further authentication.
1324 : param package_ids: An array of package IDs.
1325 """
1326 pklog.debug("UpdateSystem() was called")
1327 return self._update_system(only_trusted, sender)
1328
1329 @inline_callbacks
1330 def _update_system(self, only_trusted, sender):
1331 self.role = pk_enums.ROLE_UPDATE_SYSTEM
1332 self.trans = self._get_merged_trans(aptd_enums.ROLE_UPGRADE_SYSTEM,
1333 kwargs={"safe_mode": False})
1334 yield self.trans._set_property(APTDAEMON_TRANSACTION_DBUS_INTERFACE,
1335 "AllowUnauthenticated", not only_trusted,
1336 sender)
1337 yield self.trans._run(sender)
1338
1339 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1340 in_signature="as", out_signature="",
1341 sender_keyword="sender")
1342 def GetUpdateDetail(self, package_ids, sender):
1343 """This method returns details about a specific update.
1344
1345 This method typically emits UpdateDetail and Error
1346
1347 :param package_ids: An array of package IDs.
1348 """
1349 pklog.debug("GetUpdateDetail() was called")
1350 self.role = pk_enums.ROLE_GET_UPDATE_DETAIL
1351 kwargs = {"package_ids": package_ids}
1352 return self._run_query(kwargs, sender)
1353
1354 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1355 in_signature="s", out_signature="",
1356 sender_keyword="sender")
1357 def GetUpdates(self, filter, sender):
1358 """This method should return a list of packages that are installed
1359 and are upgradable. It should only return the newest update for
1360 each installed package.
1361
1362 This method typically emits Progress, Error and Package.
1363
1364 :param filter: A correct filter, e.g. none or installed;~devel
1365 """
1366 pklog.debug("GetUpdates() was called")
1367 self.role = pk_enums.ROLE_GET_UPDATES
1368 kwargs = {"filters": filter.split(";")}
1369 return self._run_query(kwargs, sender)
1370
1371 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1372 in_signature="", out_signature="",
1373 sender_keyword="sender")
1374 def GetDistroUpgrades(self, sender):
1375 """This method should return a list of distribution upgrades that are
1376 available. It should not return updates, only major upgrades.
1377
1378 This method typically emits DistroUpgrade, Error
1379 """
1380 pklog.debug("GetDistroUpgrades() was called")
1381 self.role = pk_enums.ROLE_GET_DISTRO_UPGRADES
1382 self.status = pk_enums.STATUS_RUNNING
1383 GObject.idle_add(defer_idle, self._get_distro_upgrades)
1384
1385 def _get_distro_upgrades(self):
1386 #FIXME: Should go into the worker after the threading branch is merged
1387 # It allows to run a nested loop until the download is finished
1388 self.allow_cancel = False
1389 self.percentage = 101
1390 self.status = pk_enums.STATUS_DOWNLOAD_UPDATEINFO
1391
1392 if META_RELEASE_SUPPORT == False:
1393 self.ErrorCode(pk_enums.ERROR_INTERNAL_ERROR,
1394 "Please make sure that update-manager-core is"
1395 "correctly installed.")
1396 self.exit = pk_enums.EXIT_FAILED
1397 return
1398
1399 #FIXME Evil to start the download during init
1400 meta_release = GMetaRelease()
1401 meta_release.connect("download-done",
1402 self._on_distro_upgrade_download_done)
1403
1404 def _on_distro_upgrade_download_done(self, meta_release):
1405 #FIXME: Add support for description
1406 if meta_release.new_dist != None:
1407 self.DistroUpgrade("stable",
1408 "%s %s" % (meta_release.new_dist.name,
1409 meta_release.new_dist.version),
1410 "The latest stable release")
1411 self.exit = pk_enums.EXIT_SUCCESS
1412
1413 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1414 in_signature="sas", out_signature="",
1415 sender_keyword="sender")
1416 def Resolve(self, filter, packages, sender):
1417 """This method turns a single package name into a package_id suitable
1418 for the other methods.
1419
1420 If the package is a fully formed package_id, then this should be
1421 treated as an exact package match. This is useful to find the summary
1422 or installed status of a package_id returned from other methods.
1423
1424 This method typically emits Error and Package.
1425
1426 Package enumerated types should be available or installed.
1427
1428 :param filter: A correct filter, e.g. none or installed;~devel
1429 :param packages:
1430 An array of package names, e.g. scribus-clipart. The package
1431 names are case sensitive, so for instance: Resolve('Packagekit')
1432 would not match PackageKit. As a special case, if Resolve() is
1433 called with a name prefixed with @ then this should be treated as
1434 a category, for example: @web-development. In this instance, a
1435 meta-package should be emitted, for example:
1436 web-development;;;meta with the correct installed status and
1437 summary for the category.
1438 """
1439 pklog.debug("Resolve() was called")
1440 self.role = pk_enums.ROLE_RESOLVE
1441 kwargs = {"filters": filter.split(";"), "packages": packages}
1442 return self._run_query(kwargs, sender)
1443
1444 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1445 in_signature="s", out_signature="",
1446 sender_keyword="sender")
1447 def GetPackages(self, filter, sender):
1448 """This method returns all the packages without a search term.
1449
1450 This method typically emits Progress, Error and Package.
1451
1452 Package enumerated types should be available or installed.
1453
1454 :param filter: A correct filter, e.g. none or installed;~devel
1455 """
1456 pklog.debug("GetPackages() was called")
1457 self.role = pk_enums.ROLE_GET_PACKAGES
1458 kwargs = {"filters": filter.split(";")}
1459 return self._run_query(kwargs, sender)
1460
1461 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1462 in_signature="as", out_signature="",
1463 sender_keyword="sender")
1464 def GetDetails(self, package_ids, sender):
1465 """This method should return all the details about a specific
1466 package_id.
1467
1468 This method typically emits Progress, Status and Error and Details.
1469
1470 :param package_ids: An array of package IDs.
1471 """
1472 pklog.debug("GetDetails() was called")
1473 self.role = pk_enums.ROLE_GET_DETAILS
1474 kwargs = {"package_ids": package_ids}
1475 return self._run_query(kwargs, sender)
1476
1477 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1478 in_signature="as", out_signature="",
1479 sender_keyword="sender")
1480 def GetFiles(self, package_ids, sender):
1481 """This method should return the file list of the package_id.
1482
1483 This method typically emits Progress, Status and Error and Files.
1484
1485 :param package_ids: An array of package IDs.
1486 """
1487 pklog.debug("GetFiles() was called")
1488 self.role = pk_enums.ROLE_GET_FILES
1489 kwargs = {"package_ids": package_ids}
1490 return self._run_query(kwargs, sender)
1491
1492 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1493 in_signature="sas", out_signature="",
1494 sender_keyword="sender")
1495 def SearchFiles(self, filter, values, sender):
1496 """This method searches for files on the local system and files in
1497 available packages.
1498
1499 This should search for files. This should allow an application to
1500 find out what package owns a file on the system.
1501
1502 This method typically emits Progress, Error and Package.
1503
1504 Package enumerated types should be available or installed.
1505
1506 :param filter: A correct filter, e.g. none or installed;~devel
1507 :param values:
1508 A filename or fully qualified path and filename on the system.
1509 If the search term begins with a / it will be assumed the entire
1510 path has been given and only packages that contain this exact
1511 path and filename will be returned. If the search term does not
1512 start with / then it should be treated as a single filename,
1513 which can be in any directory. The search is case sensitive,
1514 and should not be escaped or surrounded in quotes.
1515 """
1516 pklog.debug("SearchFiles() was called")
1517 self.role = pk_enums.ROLE_SEARCH_FILE
1518 kwargs = {"filters": filter.split(";"),
1519 "values": values}
1520 return self._run_query(kwargs, sender)
1521
1522 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1523 in_signature="sas", out_signature="",
1524 sender_keyword="sender")
1525 def SearchDetails(self, filter, values, sender):
1526 """This method allows deeper searching than SearchName().
1527
1528 Do not refresh the package cache. This should be fast. This is very
1529 similar to search-name. This should search as much data as possible,
1530 including, if possible repo names, package summaries, descriptions,
1531 licenses and URLs.
1532
1533 Try to emit installed before available packages first, as it allows
1534 the client program to perform the GUI filtering and matching whilst
1535 the daemon is running the transaction.
1536
1537 If the backend includes installed and available versions of the same
1538 package when searching then the available version will have to be
1539 filtered in the backend.
1540
1541 This method typically emits Progress, Error and Package.
1542
1543 Package enumerated types should be available or installed.
1544
1545 :param filter: A correct filter, e.g. none or installed;~devel
1546 :param values:
1547 A single word search term with no wildcard chars. The search term
1548 can contain many words separated by spaces. In this case, the
1549 search operator is AND. For example, search of gnome power should
1550 returns gnome-power-manager but not gnomesword or powertop.
1551 The search should not be treated as case sensitive.
1552 """
1553 pklog.debug("SearchDetails() was called")
1554 self.role = pk_enums.ROLE_SEARCH_DETAILS
1555 kwargs = {"filters": filter.split(";"),
1556 "values": values}
1557 return self._run_query(kwargs, sender)
1558
1559 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1560 in_signature="sas", out_signature="",
1561 sender_keyword="sender")
1562 def SearchGroups(self, filter, values, sender):
1563 """This method returns packages from a given group enumerated type.
1564
1565 Do not refresh the package cache. This should be fast.
1566
1567 Try to emit installed before available packages first, as it
1568 allows the client program to perform the GUI filtering and matching
1569 whilst the daemon is running the transaction.
1570
1571 If the backend includes installed and available versions of the same
1572 package when searching then the available version will have to be
1573 filtered in the backend.
1574
1575 This method typically emits Progress, Error and Package.
1576
1577 Package enumerated types should be available or installed.
1578
1579 :param filter: A correct filter, e.g. none or installed;~devel
1580 :param values:
1581 An enumerated group type, or unknown. The search cannot contain
1582 spaces. The following recommendations are made below: If the values
1583 strings are prefixed with category: then the request is treated
1584 as a 'category search', for example: category:web-development.
1585 Note: the old nomenclature for a 'category search' suggested using
1586 a @ prefix for the values options. This is still supported, and
1587 backends should continue to support category searches like
1588 @web-development. If the values strings are prefixed with
1589 repo: then the request is treated as a 'repository search', for
1590 example: repo:fedora-debuginfo. In this instance all packages that
1591 were either installed from, or can be installed from the
1592 fedora-debuginfo source would be returned.
1593 """
1594 pklog.debug("SearchGroups() was called")
1595 self.role = pk_enums.ROLE_SEARCH_GROUP
1596 kwargs = {"filters": filter.split(";"),
1597 "values": values}
1598 return self._run_query(kwargs, sender)
1599
1600 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1601 in_signature="sas", out_signature="",
1602 sender_keyword="sender")
1603 def SearchNames(self, filter, values, sender):
1604 """This method searches the package database by package name.
1605
1606 Try to emit installed before available packages first, as it
1607 allows the client program to perform the GUI filtering and matching
1608 whilst the daemon is running the transaction.
1609
1610 If the backend includes installed and available versions of the same
1611 package when searching then the available version will have to be
1612 filtered in the backend.
1613
1614 The search methods should return all results in all repositories.
1615 This may mean that multiple versions of package are returned. If this
1616 is not what is wanted by the client program, then the newest filter
1617 should be used.
1618
1619 This method typically emits Progress, Error and Package.
1620
1621 Package enumerated types should be available or installed.
1622
1623 :param filter: A correct filter, e.g. none or installed;~devel
1624 :param values:
1625 A single word search term with no wildcard chars. The search term
1626 can contain many words separated by spaces. In this case, the
1627 search operator is AND. For example, search of gnome power should
1628 returns gnome-power-manager but not gnomesword or powertop.
1629 The search should not be treated as case sensitive.
1630 """
1631 pklog.debug("SearchNames() was called")
1632 self.role = pk_enums.ROLE_SEARCH_NAME
1633 kwargs = {"filters": filter.split(";"),
1634 "values": values}
1635 return self._run_query(kwargs, sender)
1636
1637 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1638 in_signature="s", out_signature="",
1639 sender_keyword="sender")
1640 def AcceptEula(self, eula_id, sender):
1641 """This method allows the user to accept a end user licence agreement.
1642
1643 :param eula_id: A valid EULA ID
1644 """
1645 self.role = pk_enums.ROLE_ACCEPT_EULA
1646 GObject.idle_add(self._fail_not_implemented)
1647
1648 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1649 in_signature="bas", out_signature="",
1650 sender_keyword="sender")
1651 def DownloadPackages(self, store_in_cache, package_ids, sender):
1652 """This method downloads packages into a temporary directory.
1653
1654 This method should emit one Files signal for each package that
1655 is downloaded, with the file list set as the name of the complete
1656 downloaded file and directory, so for example:
1657
1658 DownloadPackages('hal;0.1.2;i386;fedora',
1659 'hal-info;2009-09-07;no-arch;updates') should send two signals,
1660 e.g. Files('hal;0.1.2;i386;fedora', '/tmp/hal-0.1.2.i386.rpm')
1661 and Files('hal-info;2009-09-07;no-arch;updates',
1662 '/tmp/hal-info-2009-09-07.noarch.rpm').
1663
1664 :param store_in_cache:
1665 If the downloaded files should be stored in the system package
1666 cache rather than copied into a newly created directory. See the
1667 developer docs for more details on how this is supposed to work.
1668 :param package_ids: An array of package IDs.
1669 """
1670 self.role = pk_enums.ROLE_DOWNLOAD_PACKAGES
1671 kwargs = {"store_in_cache": store_in_cache,
1672 "package_ids": package_ids}
1673 return self._run_query(kwargs, sender)
1674
1675 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1676 in_signature="u", out_signature="",
1677 sender_keyword="sender")
1678 def GetOldTransactions(self, number, sender):
1679 """This method allows a client to view details for old transactions.
1680
1681 :param number:
1682 The number of past transactions, or 0 for all known transactions.
1683 """
1684 self.role = pk_enums.ROLE_GET_OLD_TRANSACTIONS
1685 GObject.idle_add(self._fail_not_implemented)
1686
1687 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1688 in_signature="s", out_signature="",
1689 sender_keyword="sender")
1690 def GetRepoList(self, filter, sender):
1691 """This method returns the list of repositories used in the system.
1692
1693 This method should emit RepoDetail.
1694
1695 :param filter: A correct filter, e.g. none or installed;~devel
1696 """
1697 self.role = pk_enums.ROLE_GET_REPO_LIST
1698 GObject.idle_add(self._fail_not_implemented)
1699
1700 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1701 in_signature="as", out_signature="",
1702 sender_keyword="sender")
1703 def SimulateInstallFiles(self, full_paths, sender):
1704 """This method simulates a package file instalation emitting packages
1705 required to be installed, removed, updated, reinstalled, downgraded,
1706 obsoleted or untrusted. The latter is used to present the user
1707 untrusted packages that are about to be installed.
1708
1709 This method typically emits Error and Package.
1710
1711 :param full_paths:
1712 An array of full path and filenames to packages.
1713 """
1714 self.role = pk_enums.ROLE_SIMULATE_INSTALL_FILES
1715 GObject.idle_add(self._fail_not_implemented)
1716
1717 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1718 in_signature="bas", out_signature="",
1719 sender_keyword="sender")
1720 def InstallFiles(self, only_trusted, full_paths, sender):
1721 """This method installs local package files onto the local system.
1722
1723 The installer should always install extra dependant packages
1724 automatically.
1725
1726 This method typically emits Progress, Status and Error and Package.
1727
1728 Package enumerated types should be downloading, updating, installing
1729 or removing.
1730
1731 :param only_trusted:
1732 If the transaction is only allowed to install trusted files.
1733 Unsigned files should not be installed if this parameter is TRUE.
1734 If this method is can only install trusted files, and the files
1735 are unsigned, then the backend will send a
1736 ErrorCode(missing-gpg-signature). On recieving this error, the
1737 client may choose to retry with only_trusted FALSE after gaining
1738 further authentication.
1739 :param full_paths: An array of full path and filenames to packages.
1740 """
1741 self.role = pk_enums.ROLE_INSTALL_FILES
1742 GObject.idle_add(self._fail_not_implemented)
1743
1744 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1745 in_signature="sss", out_signature="",
1746 sender_keyword="sender")
1747 def InstallSignature(self, sig_type, key_id, package_id, sender):
1748 """This method allows us to install new security keys.
1749
1750 :param sig_type: A key type, e.g. gpg
1751 :param key_id: A key ID, e.g. BB7576AC
1752 :param package_id:
1753 A PackageID for the package that the user is trying to install
1754 """
1755 self.role = pk_enums.ROLE_INSTALL_SIGNATURE
1756 GObject.idle_add(self._fail_not_implemented)
1757
1758 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1759 in_signature="sss", out_signature="",
1760 sender_keyword="sender")
1761 def RepoSetData(self, repo_id, parameter, value, sender):
1762 """This method allows arbitary data to be passed to the repository
1763 handler.
1764
1765 :param repo_id:
1766 A repository identifier, e.g. fedora-development-debuginfo
1767 :param parameter:
1768 The backend specific value, e.g. set-download-url.
1769 :param value:
1770 The backend specific value, e.g. http://foo.bar.org/baz.
1771 """
1772 self.role = pk_enums.ROLE_REPO_SET_DATA
1773 GObject.idle_add(self._fail_not_implemented)
1774
1775 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1776 in_signature="sb", out_signature="",
1777 sender_keyword="sender")
1778 def RepoEnable(self, repo_id, enabled, sender):
1779 """This method enables the repository specified.
1780
1781 :param repo_id:
1782 A repository identifier, e.g. fedora-development-debuginfo
1783 :param enabled: true if enabled, false if disabled.
1784 """
1785 self.role = pk_enums.ROLE_REPO_ENABLE
1786 GObject.idle_add(self._fail_not_implemented)
1787
1788 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1789 in_signature="s", out_signature="",
1790 sender_keyword="sender")
1791 def Rollback(self, transaction_id, sender):
1792 """This method rolls back the package database to a previous transaction.
1793
1794 :param transaction_id: A valid transaction ID.
1795 """
1796 self.role = pk_enums.ROLE_GET_CATEGORIES
1797 GObject.idle_add(self._fail_not_implemented)
1798
1799 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1800 in_signature="ssas", out_signature="",
1801 sender_keyword="sender")
1802 def WhatProvides(self, filter, type, values, sender):
1803 """This method returns packages that provide the supplied attributes.
1804 This method is useful for finding out what package(s) provide a
1805 modalias or GStreamer codec string.
1806
1807 This method typically emits Progress, Status and Error and Package.
1808
1809 Package enumerated types should be available or installed.
1810
1811 :param filter:
1812 A correct filter, e.g. none or installed;~devel
1813 :param type:
1814 A PkProvideType, e.g. PK_PROVIDES_ENUM_CODEC.
1815 :param values:
1816 The data to send to the backend to get the packages. Note: This
1817 is backend specific.
1818 """
1819 self.role = pk_enums.ROLE_WHAT_PROVIDES
1820 kwargs = {"filters": filter.split(";"),
1821 "type": type,
1822 "values": values}
1823 return self._run_query(kwargs, sender)
1824
1825 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1826 in_signature="", out_signature="",
1827 sender_keyword="sender")
1828 def GetCategories(self, sender):
1829 """This method return the collection categories"""
1830 self.role = pk_enums.ROLE_GET_CATEGORIES
1831 GObject.idle_add(self._fail_not_implemented)
1832
1833 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1834 in_signature="sasb", out_signature="",
1835 sender_keyword="sender")
1836 def GetRequires(self, filter, package_ids, recursive, sender):
1837 """This method returns packages that depend on this package. This is
1838 useful to know, as if package_id is being removed, we can warn the
1839 user what else would be removed.
1840
1841 This method typically emits Progress, Status and Error and Package.
1842
1843 Package enumerated types should be available or installed.
1844
1845 :param filter: A correct filter, e.g. none or installed;~devel
1846 :param package_ids: An array of package IDs.
1847 :param recursive:
1848 Either true or false. If yes then the requirements should be
1849 returned for all packages returned. This means if
1850 gnome-power-manager depends on NetworkManager and NetworkManager
1851 depends on HAL, then GetRequires on HAL should return both
1852 gnome-power-manager and NetworkManager.
1853 """
1854 self.role = pk_enums.ROLE_GET_REQUIRES
1855 kwargs = {"filters": filter.split(";"),
1856 "package_ids": package_ids,
1857 "recursive": recursive}
1858 return self._run_query(kwargs, sender)
1859
1860 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1861 in_signature="sasb", out_signature="",
1862 sender_keyword="sender")
1863 def GetDepends(self, filter, package_ids, recursive, sender):
1864 """This method returns packages that this package depends on.
1865
1866 This method typically emits Progress, Status and Error and Package.
1867
1868 Package enumerated types should be available or installed.
1869
1870 :param filter: A correct filter, e.g. none or installed;~devel
1871 :param package_ids: An array of package IDs.
1872 :param recursive:
1873 Either true or false. If yes then the requirements should be
1874 returned for all packages returned. This means if
1875 gnome-power-manager depends on NetworkManager and NetworkManager
1876 depends on HAL, then GetDepends on gnome-power-manager should
1877 return both HAL and NetworkManager.
1878 """
1879 self.role = pk_enums.ROLE_GET_DEPENDS
1880 kwargs = {"filters": filter.split(";"),
1881 "package_ids": package_ids,
1882 "recursive": recursive}
1883 return self._run_query(kwargs, sender)
1884
1885 # HELPERS
1886
1887 def _fail_not_implemented(self):
1888 self.ErrorCode(pk_enums.ERROR_NOT_SUPPORTED, "")
1889 self.exit = pk_enums.EXIT_FAILED
1890 return False
1891
1892 def _get_properties(self, iface):
1893 """Helper to get the properties of a D-Bus interface."""
1894 if iface == PACKAGEKIT_TRANS_DBUS_INTERFACE:
1895 return {"Role": dbus.String(self.role),
1896 "Status": dbus.String(self.status),
1897 "LastPackage": dbus.String(self.last_package),
1898 "Uid": dbus.UInt32(self.uid),
1899 "Percentage": dbus.UInt32(self.percentage),
1900 "Subpercentage": dbus.UInt32(self.subpercentage),
1901 "AllowCancel": dbus.Boolean(self.allow_cancel),
1902 "CallerActive": dbus.Boolean(self.caller_active),
1903 "ElapsedTime": dbus.UInt32(self.elapsed_time),
1904 "RemainingTime": dbus.UInt32(self.remaining_time),
1905 "Speed": dbus.UInt32(self.speed)
1906 }
1907 else:
1908 return {}
1909
1910 @inline_callbacks
1911 def _run_query(self, kwargs, sender):
1912 self.trans = self._get_merged_trans(aptd_enums.ROLE_PK_QUERY,
1913 kwargs=kwargs)
1914 yield self.trans._run(sender)
1915
1916 def _get_merged_trans(self, role, pkg_ids=None, pkg_type=None, kwargs=None):
1917 if pkg_ids:
1918 packages = [[], [], [], [], [], []]
1919 packages[pkg_type] = [get_aptd_package_id(pkg) for pkg in pkg_ids]
1920 else:
1921 packages = None
1922 if self.trans:
1923 raise Exception("%s: Transaction may only run once." % \
1924 pk_enums.ERROR_TRANSACTION_FAILED)
1925 trans = MergedTransaction(self, role, self.queue,
1926 packages=packages, kwargs=kwargs)
1927 try:
1928 trans._set_locale(self.hints["locale"])
1929 except (KeyError, ValueError):
1930 # If the locale isn't vaild or supported a ValueError will be raised
1931 pass
1932 try:
1933 trans._set_debconf(self.hints["frontend-socket"])
1934 except KeyError:
1935 pass
1936 self.queue.limbo[trans.tid] = trans
1937 return trans
1938
1939
1940class PackageKitWorker(aptdaemon.worker.AptWorker):
1941
1942 _plugins = None
1943
1944 """Process PackageKit Query transactions."""
1945
1946 def query(self, trans):
1947 """Run the worker"""
1948 if trans.role != aptd_enums.ROLE_PK_QUERY:
1949 raise TransactionFailed(aptd_enums.ERROR_UNKNOWN,
1950 "The transaction doesn't seem to be "
1951 "a query")
1952 if trans.pktrans.role == pk_enums.ROLE_RESOLVE:
1953 self.resolve(trans, **trans.kwargs)
1954 elif trans.pktrans.role == pk_enums.ROLE_GET_UPDATES:
1955 self.get_updates(trans, **trans.kwargs)
1956 elif trans.pktrans.role == pk_enums.ROLE_GET_UPDATE_DETAIL:
1957 self.get_update_detail(trans, **trans.kwargs)
1958 elif trans.pktrans.role == pk_enums.ROLE_GET_PACKAGES:
1959 self.get_packages(trans, **trans.kwargs)
1960 elif trans.pktrans.role == pk_enums.ROLE_GET_FILES:
1961 self.get_files(trans, **trans.kwargs)
1962 elif trans.pktrans.role == pk_enums.ROLE_SEARCH_NAME:
1963 self.search_names(trans, **trans.kwargs)
1964 elif trans.pktrans.role == pk_enums.ROLE_SEARCH_GROUP:
1965 self.search_groups(trans, **trans.kwargs)
1966 elif trans.pktrans.role == pk_enums.ROLE_SEARCH_DETAILS:
1967 self.search_details(trans, **trans.kwargs)
1968 elif trans.pktrans.role == pk_enums.ROLE_SEARCH_FILE:
1969 self.search_files(trans, **trans.kwargs)
1970 elif trans.pktrans.role == pk_enums.ROLE_GET_DEPENDS:
1971 self.get_depends(trans, **trans.kwargs)
1972 elif trans.pktrans.role == pk_enums.ROLE_GET_REQUIRES:
1973 self.get_requires(trans, **trans.kwargs)
1974 elif trans.pktrans.role == pk_enums.ROLE_GET_DETAILS:
1975 self.get_details(trans, **trans.kwargs)
1976 elif trans.pktrans.role == pk_enums.ROLE_DOWNLOAD_PACKAGES:
1977 self.download_packages(trans, **trans.kwargs)
1978 elif trans.pktrans.role == pk_enums.ROLE_WHAT_PROVIDES:
1979 self.what_provides(trans, **trans.kwargs)
1980 else:
1981 raise TransactionFailed(aptd_enums.ERROR_UNKNOWN,
1982 "Role %s isn't supported",
1983 trans.pktrans.role)
1984
1985 def search_files(self, trans, filters, values):
1986 """Implement org.freedesktop.PackageKit.Transaction.SearchFiles()
1987
1988 Works only for installed file if apt-file isn't installed.
1989 """
1990 trans.progress = 101
1991
1992 result_names = set()
1993 # Optionally make use of apt-file's Contents cache to search for not
1994 # installed files. But still search for installed files additionally
1995 # to make sure that we provide up-to-date results
1996 if os.path.exists("/usr/bin/apt-file") and \
1997 pk_enums.FILTER_INSTALLED not in filters:
1998 #FIXME: Make use of rapt-file on Debian if the network is available
1999 #FIXME: Show a warning to the user if the apt-file cache is several
2000 # weeks old
2001 pklog.debug("Using apt-file")
2002 filenames_regex = []
2003 for filename in values:
2004 if filename.startswith("/"):
2005 pattern = "^%s$" % filename[1:].replace("/", "\/")
2006 else:
2007 pattern = "\/%s$" % filename
2008 filenames_regex.append(pattern)
2009 cmd = ["/usr/bin/apt-file", "--regexp", "--non-interactive",
2010 "--package-only", "find", "|".join(filenames_regex)]
2011 pklog.debug("Calling: %s" % cmd)
2012 apt_file = subprocess.Popen(cmd, stdout=subprocess.PIPE,
2013 stderr=subprocess.PIPE)
2014 stdout, stderr = apt_file.communicate()
2015 if apt_file.returncode == 0:
2016 #FIXME: Actually we should check if the file is part of the
2017 # candidate, e.g. if unstable and experimental are
2018 # enabled and a file would only be part of the
2019 # experimental version
2020 result_names.update(stdout.split())
2021 self._emit_visible_packages_by_name(trans, filters,
2022 result_names)
2023 else:
2024 raise TransactionFailed(ERROR_INTERNAL_ERROR,
2025 "%s %s" % (stdout, stderr))
2026 # Search for installed files
2027 filenames_regex = []
2028 for filename in values:
2029 if filename.startswith("/"):
2030 pattern = "^%s$" % filename.replace("/", "\/")
2031 else:
2032 pattern = ".*\/%s$" % filename
2033 filenames_regex.append(pattern)
2034 files_pattern = re.compile("|".join(filenames_regex))
2035 for pkg in self._iterate_packages():
2036 if pkg.name in result_names:
2037 continue
2038 for installed_file in self._get_installed_files(pkg):
2039 if files_pattern.match(installed_file):
2040 self._emit_visible_package(trans, filters, pkg)
2041 break
2042
2043 def search_groups(self, trans, filters, values):
2044 """Implement org.freedesktop.PackageKit.Transaction.SearchGroups()"""
2045 #FIXME: Handle repo and category search
2046 trans.progress = 101
2047
2048 for pkg in self._iterate_packages():
2049 if self._get_package_group(pkg) in values:
2050 self._emit_visible_package(trans, filters, pkg)
2051
2052 def search_names(self, trans, filters, values):
2053 """Implement org.freedesktop.PackageKit.Transaction.SearchNames()"""
2054 def matches(searches, text):
2055 for search in searches:
2056 if not search in text:
2057 return False
2058 return True
2059 pklog.info("Searching for package name: %s" % values)
2060 trans.progress = 101
2061
2062 for pkg_name in self._cache.keys():
2063 if matches(values, pkg_name):
2064 self._emit_all_visible_pkg_versions(trans, filters,
2065 self._cache[pkg_name])
2066
2067 def search_details(self, trans, filters, values):
2068 """Implement org.freedesktop.PackageKit.Transaction.SearchDetails()"""
2069 trans.progress = 101
2070 results = []
2071
2072 if XAPIAN_SUPPORT == True:
2073 search_flags = (xapian.QueryParser.FLAG_BOOLEAN |
2074 xapian.QueryParser.FLAG_PHRASE |
2075 xapian.QueryParser.FLAG_LOVEHATE |
2076 xapian.QueryParser.FLAG_BOOLEAN_ANY_CASE)
2077 pklog.debug("Performing xapian db based search")
2078 db = xapian.Database(XAPIAN_DB)
2079 parser = xapian.QueryParser()
2080 parser.set_default_op(xapian.Query.OP_AND)
2081 query = parser.parse_query(u" ".join(values), search_flags)
2082 enquire = xapian.Enquire(db)
2083 enquire.set_query(query)
2084 matches = enquire.get_mset(0, 1000)
2085 for pkg_name in (match.document.get_data()
2086 for match in enquire.get_mset(0,1000)):
2087 if pkg_name in self._cache:
2088 self._emit_visible_package(trans, filters,
2089 self._cache[pkg_name])
2090 else:
2091 def matches(searches, text):
2092 for search in searches:
2093 if not search in text:
2094 return False
2095 return True
2096 pklog.debug("Performing apt cache based search")
2097 values = [val.lower() for val in values]
2098 for pkg in self._iterate_packages():
2099 txt = pkg.name
2100 try:
2101 txt += pkg.candidate.raw_description.lower()
2102 txt += pkg.candidate._translated_records.long_desc.lower()
2103 except AttributeError:
2104 pass
2105 if matches(values, txt):
2106 self._emit_visible_package(trans, filters, pkg)
2107
2108 def get_updates(self, trans, filters):
2109 """Only report updates which can be installed safely: Which can depend
2110 on the installation of additional packages but which don't require
2111 the removal of already installed packages or block any other update.
2112 """
2113 def succeeds_security_update(pkg):
2114 """
2115 Return True if an update succeeds a previous security update
2116
2117 An example would be a package with version 1.1 in the security
2118 archive and 1.1.1 in the archive of proposed updates or the
2119 same version in both archives.
2120 """
2121 for version in pkg.versions:
2122 # Only check versions between the installed and the candidate
2123 if (pkg.installed and
2124 apt_pkg.version_compare(version.version,
2125 pkg.installed.version) <= 0 and
2126 apt_pkg.version_compare(version.version,
2127 pkg.candidate.version) > 0):
2128 continue
2129 for origin in version.origins:
2130 if origin.origin in ["Debian", "Ubuntu"] and \
2131 (origin.archive.endswith("-security") or \
2132 origin.label == "Debian-Security") and \
2133 origin.trusted:
2134 return True
2135 return False
2136 #FIXME: Implment the basename filter
2137 pklog.info("Get updates()")
2138 self.cancellable = False
2139 self.progress = 101
2140 # Start with a safe upgrade
2141 self._cache.upgrade(dist_upgrade=True)
2142 for pkg in self._iterate_packages():
2143 if not pkg.is_upgradable:
2144 continue
2145 # This may occur on pinned packages which have been updated to
2146 # later version than the pinned one
2147 if not pkg.candidate.origins:
2148 continue
2149 if not pkg.marked_upgrade:
2150 #FIXME: Would be nice to all show why
2151 self._emit_package(trans, pkg, pk_enums.INFO_BLOCKED,
2152 force_candidate=True)
2153 continue
2154 # The update can be safely installed
2155 info = pk_enums.INFO_NORMAL
2156 # Detect the nature of the upgrade (e.g. security, enhancement)
2157 candidate_origin = pkg.candidate.origins[0]
2158 archive = candidate_origin.archive
2159 origin = candidate_origin.origin
2160 trusted = candidate_origin.trusted
2161 label = candidate_origin.label
2162 if origin in ["Debian", "Ubuntu"] and trusted == True:
2163 if archive.endswith("-security") or label == "Debian-Security":
2164 info = pk_enums.INFO_SECURITY
2165 elif succeeds_security_update(pkg):
2166 pklog.debug("Update of %s succeeds a security update. "
2167 "Raising its priority." % pkg.name)
2168 info = pk_enums.INFO_SECURITY
2169 elif archive.endswith("-backports"):
2170 info = pk_enums.INFO_ENHANCEMENT
2171 elif archive.endswith("-updates"):
2172 info = pk_enums.INFO_BUGFIX
2173 if origin in ["Backports.org archive"] and trusted == True:
2174 info = pk_enums.INFO_ENHANCEMENT
2175 self._emit_package(trans, pkg, info, force_candidate=True)
2176 self._emit_require_restart(trans)
2177
2178 def _emit_require_restart(self, trans):
2179 """Emit RequireRestart if required."""
2180 # Check for a system restart
2181 if self.is_reboot_required():
2182 trans.pktrans.RequireRestart(pk_enums.RESTART_SYSTEM, "")
2183
2184 def get_update_detail(self, trans, package_ids):
2185 """
2186 Implement the {backend}-get-update-details functionality
2187 """
2188 def get_bug_urls(changelog):
2189 """
2190 Create a list of urls pointing to closed bugs in the changelog
2191 """
2192 urls = []
2193 for r in re.findall(MATCH_BUG_CLOSES_DEBIAN, changelog,
2194 re.IGNORECASE | re.MULTILINE):
2195 urls.extend([HREF_BUG_DEBIAN % bug for bug in \
2196 re.findall(MATCH_BUG_NUMBERS, r)])
2197 for r in re.findall(MATCH_BUG_CLOSES_UBUNTU, changelog,
2198 re.IGNORECASE | re.MULTILINE):
2199 urls.extend([HREF_BUG_UBUNTU % bug for bug in \
2200 re.findall(MATCH_BUG_NUMBERS, r)])
2201 return urls
2202
2203 def get_cve_urls(changelog):
2204 """
2205 Create a list of urls pointing to cves referred in the changelog
2206 """
2207 return map(lambda c: HREF_CVE % c,
2208 re.findall(MATCH_CVE, changelog, re.MULTILINE))
2209
2210 pklog.info("Get update details of %s" % package_ids)
2211 trans.progress = 0
2212 trans.cancellable = False
2213 trans.pktrans.status = pk_enums.STATUS_DOWNLOAD_CHANGELOG
2214 total = len(package_ids)
2215 count = 1
2216 old_locale = locale.getlocale(locale.LC_TIME)
2217 locale.setlocale(locale.LC_TIME, "C")
2218 for pkg_id in package_ids:
2219 self._iterate_mainloop()
2220 trans.progress = count * 100 / total
2221 count += 1
2222 pkg = self._get_package_by_id(pkg_id)
2223 # FIXME add some real data
2224 if pkg.installed.origins:
2225 installed_origin = pkg.installed.origins[0].label
2226 else:
2227 installed_origin = ""
2228 updates = "%s;%s;%s;%s" % (pkg.name, pkg.installed.version,
2229 pkg.installed.architecture,
2230 installed_origin)
2231 obsoletes = ""
2232 vendor_url = ""
2233 restart = "none"
2234 update_text = u""
2235 state = ""
2236 issued = ""
2237 updated = ""
2238 #FIXME: make this more configurable. E.g. a dbus update requires
2239 # a reboot on Ubuntu but not on Debian
2240 if pkg.name.startswith("linux-image-") or \
2241 pkg.name in ["libc6", "dbus"]:
2242 restart == pk_enums.RESTART_SYSTEM
2243 changelog_dir = apt_pkg.config.find_dir("Dir::Cache::Changelogs")
2244 if changelog_dir == "/":
2245 changelog_dir = os.path.join(apt_pkg.config.find_dir("Dir::"
2246 "Cache"),
2247 "Changelogs")
2248 filename = os.path.join(changelog_dir,
2249 "%s_%s.gz" % (pkg.name,
2250 pkg.candidate.version))
2251 changelog_raw = ""
2252 if os.path.exists(filename):
2253 pklog.debug("Reading changelog from cache")
2254 changelog_file = gzip.open(filename, "rb")
2255 try:
2256 changelog_raw = changelog_file.read().decode("UTF-8")
2257 except:
2258 pass
2259 finally:
2260 changelog_file.close()
2261 if not changelog_raw:
2262 pklog.debug("Downloading changelog")
2263 changelog_raw = pkg.get_changelog()
2264 # The internal download error string of python-apt ist not
2265 # provided as unicode object
2266 if not isinstance(changelog_raw, unicode):
2267 changelog_raw = changelog_raw.decode("UTF-8")
2268 # Cache the fetched changelog
2269 if not os.path.exists(changelog_dir):
2270 os.makedirs(changelog_dir)
2271 # Remove old cached changelogs
2272 pattern = os.path.join(changelog_dir, "%s_*" % pkg.name)
2273 for old_changelog in glob.glob(pattern):
2274 os.remove(os.path.join(changelog_dir, old_changelog))
2275 changelog_file = gzip.open(filename, mode="wb")
2276 try:
2277 changelog_file.write(changelog_raw.encode("UTF-8"))
2278 finally:
2279 changelog_file.close()
2280 # Convert the changelog to markdown syntax
2281 changelog = u""
2282 for line in changelog_raw.split("\n"):
2283 if line == "":
2284 changelog += " \n"
2285 else:
2286 changelog += u" %s \n" % line
2287 if line.startswith(pkg.candidate.source_name):
2288 match = re.match(r"(?P<source>.+) \((?P<version>.*)\) "
2289 "(?P<dist>.+); urgency=(?P<urgency>.+)",
2290 line)
2291 update_text += u"%s\n%s\n\n" % (match.group("version"),
2292 "=" * \
2293 len(match.group("version")))
2294 elif line.startswith(" "):
2295 update_text += u" %s \n" % line
2296 elif line.startswith(" --"):
2297 #FIXME: Add %z for the time zone - requires Python 2.6
2298 update_text += u" \n"
2299 match = re.match("^ -- (?P<maintainer>.+) (?P<mail><.+>) "
2300 "(?P<date>.+) (?P<offset>[-\+][0-9]+)$",
2301 line)
2302 if not match:
2303 continue
2304 try:
2305 date = datetime.datetime.strptime(match.group("date"),
2306 "%a, %d %b %Y "
2307 "%H:%M:%S")
2308 except ValueError:
2309 continue
2310 issued = date.isoformat()
2311 if not updated:
2312 updated = date.isoformat()
2313 if issued == updated:
2314 updated = ""
2315 bugzilla_url = ";;".join(get_bug_urls(changelog))
2316 cve_url = ";;".join(get_cve_urls(changelog))
2317 trans.emit_update_detail(pkg_id, updates, obsoletes, vendor_url,
2318 bugzilla_url, cve_url, restart,
2319 update_text, changelog,
2320 state, issued, updated)
2321 locale.setlocale(locale.LC_TIME, old_locale)
2322
2323 def get_details(self, trans, package_ids):
2324 """Implement org.freedesktop.PackageKit.Transaction.GetDetails()"""
2325 trans.progress = 101
2326
2327 for pkg_id in package_ids:
2328 version = self._get_version_by_id(pkg_id)
2329 #FIXME: We need more fine grained license information!
2330 origins = version.origins
2331 if (origins and
2332 origins[0].component in ["main", "universe"] and
2333 origins[0].origin in ["Debian", "Ubuntu"]):
2334 license = "free"
2335 else:
2336 license = "unknown"
2337 group = self._get_package_group(version.package)
2338 trans.emit_details(pkg_id, license, group, version.description,
2339 version.homepage, version.size)
2340
2341 def get_packages(self, trans, filters):
2342 """Implement org.freedesktop.PackageKit.Transaction.GetPackages()"""
2343 pklog.info("Get all packages")
2344 self.progress = 101
2345
2346 for pkg in self._iterate_packages():
2347 if self._is_package_visible(pkg, filters):
2348 self._emit_package(trans, pkg)
2349
2350 def resolve(self, trans, filters, packages):
2351 """Implement org.freedesktop.PackageKit.Transaction.Resolve()"""
2352 pklog.info("Resolve()")
2353 trans.status = aptd_enums.STATUS_QUERY
2354 trans.progress = 101
2355 self.cancellable = False
2356
2357 for name_raw in packages:
2358 #FIXME: Python-apt doesn't allow unicode as key. See #542965
2359 name = str(name_raw)
2360 try:
2361 # Check if the name is a valid package id
2362 version = self._get_version_by_id(name)
2363 except ValueError:
2364 pass
2365 else:
2366 if self._package_is_visible(version.package, filters):
2367 self._emit_pkg_version(trans, version)
2368 continue
2369 # The name seems to be a normal name
2370 try:
2371 self._emit_visible_package(trans, filters, self._cache[name])
2372 except KeyError:
2373 raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
2374 "Package name %s could not be "
2375 "resolved.", name)
2376
2377 def get_depends(self, trans, filters, package_ids, recursive):
2378 """Emit all dependencies of the given package ids.
2379
2380 Doesn't support recursive dependency resolution.
2381 """
2382 def emit_blocked_dependency(base_dependency, pkg=None,
2383 filters=""):
2384 """Send a blocked package signal for the given
2385 apt.package.BaseDependency.
2386 """
2387 if FILTER_INSTALLED in filters:
2388 return
2389 if pkg:
2390 summary = pkg.candidate.summary
2391 try:
2392 filters.remove(FILTER_NOT_INSTALLED)
2393 except ValueError:
2394 pass
2395 if not self._is_package_visible(pkg, filters):
2396 return
2397 else:
2398 summary = u""
2399 if base_dependency.relation:
2400 version = "%s%s" % (base_dependency.relation,
2401 base_dependency.version)
2402 else:
2403 version = base_dependency.version
2404 trans.emit_package("%s;%s;;" % (base_dependency.name, version),
2405 pk_enums.INFO_BLOCKED, summary)
2406
2407 def check_dependency(pkg, base_dep):
2408 """Check if the given apt.package.Package can satisfy the
2409 BaseDepenendcy and emit the corresponding package signals.
2410 """
2411 if not self._is_package_visible(pkg, filters):
2412 return
2413 if base_dep.version:
2414 satisfied = False
2415 # Sort the version list to check the installed
2416 # and candidate before the other ones
2417 ver_list = list(pkg.versions)
2418 if pkg.installed:
2419 ver_list.remove(pkg.installed)
2420 ver_list.insert(0, pkg.installed)
2421 if pkg.candidate:
2422 ver_list.remove(pkg.candidate)
2423 ver_list.insert(0, pkg.candidate)
2424 for dep_ver in ver_list:
2425 if apt_pkg.check_dep(dep_ver.version,
2426 base_dep.relation,
2427 base_dep.version):
2428 self._emit_pkg_version(trans, dep_ver)
2429 satisfied = True
2430 break
2431 if not satisfied:
2432 emit_blocked_dependency(base_dep, pkg, filters)
2433 else:
2434 self._emit_package(trans, pkg)
2435
2436 # Setup the transaction
2437 pklog.info("Get depends (%s,%s,%s)" % (filter, package_ids, recursive))
2438 self.status = aptd_enums.STATUS_RESOLVING_DEP
2439 trans.progress = 101
2440 self.cancellable = True
2441
2442 dependency_types = ["PreDepends", "Depends"]
2443 if apt_pkg.config["APT::Install-Recommends"]:
2444 dependency_types.append("Recommends")
2445 for id in package_ids:
2446 version = self._get_version_by_id(id)
2447 for dependency in version.get_dependencies(*dependency_types):
2448 # Walk through all or_dependencies
2449 for base_dep in dependency.or_dependencies:
2450 if self._cache.is_virtual_package(base_dep.name):
2451 # Check each proivider of a virtual package
2452 for provider in \
2453 self._cache.get_providing_packages(base_dep.name):
2454 check_dependency(provider, base_dep)
2455 elif base_dep.name in self._cache:
2456 check_dependency(self._cache[base_dep.name], base_dep)
2457 else:
2458 # The dependency does not exist
2459 emit_blocked_dependency(trans, base_dep, filters=filters)
2460
2461 def get_requires(self, trans, filters, package_ids, recursive):
2462 """Emit all packages which depend on the given ids.
2463
2464 Recursive searching is not supported.
2465 """
2466 pklog.info("Get requires (%s,%s,%s)" % (filter, package_ids, recursive))
2467 self.status = aptd_enums.STATUS_RESOLVING_DEP
2468 self.progress = 101
2469 self.cancellable = True
2470 for id in package_ids:
2471 version = self._get_version_by_id(id)
2472 for pkg in self._iterate_packages():
2473 if not self._is_package_visible(pkg, filters):
2474 continue
2475 if pkg.is_installed:
2476 pkg_ver = pkg.installed
2477 elif pkg.candidate:
2478 pkg_ver = pkg.candidate
2479 for dependency in pkg_ver.dependencies:
2480 satisfied = False
2481 for base_dep in dependency.or_dependencies:
2482 if version.package.name == base_dep.name or \
2483 base_dep.name in version.provides:
2484 satisfied = True
2485 break
2486 if satisfied:
2487 self._emit_package(trans, pkg)
2488 break
2489
2490 def download_packages(self, trans, store_in_cache, package_ids):
2491 """Implement the DownloadPackages functionality.
2492
2493 The store_in_cache parameter gets ignored.
2494 """
2495 def get_download_details(ids):
2496 """Calculate the start and end point of a package download
2497 progress.
2498 """
2499 total = 0
2500 downloaded = 0
2501 versions = []
2502 # Check if all ids are vaild and calculate the total download size
2503 for id in ids:
2504 pkg_ver = self._get_version_by_id(id)
2505 if not pkg_ver.downloadable:
2506 raise TransactionFailed(aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED,
2507 "package %s isn't downloadable" % id)
2508 total += pkg_ver.size
2509 versions.append((id, pkg_ver))
2510 for id, ver in versions:
2511 start = downloaded * 100 / total
2512 end = start + ver.size * 100 / total
2513 yield id, ver, start, end
2514 downloaded += ver.size
2515 pklog.info("Downloading packages: %s" % package_ids)
2516 trans.status = aptd_enums.STATUS_DOWNLOADING
2517 trans.cancellable = True
2518 trans.progress = 10
2519 # Check the destination directory
2520 if store_in_cache:
2521 dest = apt_pkg.config.find_dir("Dir::Cache::archives")
2522 else:
2523 dest = tempfile.mkdtemp(prefix="aptdaemon-download")
2524 if not os.path.isdir(dest) or not os.access(dest, os.W_OK):
2525 raise TransactionFailed(aptd_enums.ERROR_INTERNAL_ERROR,
2526 "The directory '%s' is not writable" % dest)
2527 # Start the download
2528 for id, ver, start, end in get_download_details(package_ids):
2529 progress = DaemonAcquireProgress(trans, start, end)
2530 self._emit_pkg_version(trans, ver, pk_enums.INFO_DOWNLOADING)
2531 try:
2532 ver.fetch_binary(dest, progress)
2533 except Exception as error:
2534 raise TransactionFailed(aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED,
2535 str(error))
2536 else:
2537 trans.emit_files(id,
2538 os.path.join(dest,
2539 os.path.basename(ver.filename)))
2540 self._emit_pkg_version(trans, ver, pk_enums.INFO_FINISHED)
2541
2542 def get_files(self, trans, package_ids):
2543 """Emit the Files signal which includes the files included in a package
2544 Apt only supports this for installed packages
2545 """
2546 for id in package_ids:
2547 pkg = self._get_package_by_id(id)
2548 files = ";".join(self._get_installed_files(pkg))
2549 trans.emit_files(id, files)
2550
2551 def what_provides(self, trans, filters, type, values):
2552 """Emit all dependencies of the given package ids.
2553
2554 Doesn't support recursive dependency resolution.
2555 """
2556 self._init_plugins()
2557
2558 supported_type = False
2559
2560 # run plugins
2561 for plugin in self._plugins.get("what_provides", []):
2562 pklog.debug("calling what_provides plugin %s %s" % (str(plugin), str(filters)))
2563 for search_item in values:
2564 try:
2565 for package in plugin(self._cache, type, search_item):
2566 self._emit_visible_package(trans, filters, package)
2567 supported_type = True
2568 except NotImplementedError:
2569 pass # keep supported_type as False
2570
2571 if not supported_type and type != pk_enums.PROVIDES_ANY:
2572 # none of the plugins felt responsible for this type
2573 raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
2574 "Query type '%s' is not supported" % type)
2575
2576
2577 # Helpers
2578
2579 def _get_id_from_version(self, version):
2580 """Return the package id of an apt.package.Version instance."""
2581 if version.origins:
2582 origin = version.origins[0].label
2583 else:
2584 origin = ""
2585 if version.architecture == apt_pkg.config.find("APT::Architecture") or \
2586 version.architecture == "all":
2587 name = version.package.name
2588 else:
2589 name = version.package.name.split(":")[0]
2590 id = "%s;%s;%s;%s" % (name, version.version,
2591 version.architecture, origin)
2592 return id
2593
2594 def _emit_package(self, trans, pkg, info=None, force_candidate=False):
2595 """
2596 Send the Package signal for a given apt package
2597 """
2598 if (not pkg.is_installed or force_candidate) and pkg.candidate:
2599 self._emit_pkg_version(trans, pkg.candidate, info)
2600 elif pkg.is_installed:
2601 self._emit_pkg_version(trans, pkg.installed, info)
2602 else:
2603 pklog.debug("Package %s hasn't got any version." % pkg.name)
2604
2605 def _emit_pkg_version(self, trans, version, info=None):
2606 """Emit the Package signal of the given apt.package.Version."""
2607 id = self._get_id_from_version(version)
2608 section = version.section.split("/")[-1]
2609 if not info:
2610 if version == version.package.installed:
2611 if section == "metapackages":
2612 info = pk_enums.INFO_COLLECTION_INSTALLED
2613 else:
2614 info = pk_enums.INFO_INSTALLED
2615 else:
2616 if section == "metapackages":
2617 info = pk_enums.INFO_COLLECTION_AVAILABLE
2618 else:
2619 info = pk_enums.INFO_AVAILABLE
2620 trans.emit_package(info, id, version.summary)
2621
2622 def _emit_all_visible_pkg_versions(self, trans, filters, pkg):
2623 """Emit all available versions of a package."""
2624 if self._is_package_visible(pkg, filters):
2625 if pk_enums.FILTER_NEWEST in filters:
2626 if pkg.candidate:
2627 self._emit_pkg_version(trans, pkg.candidate)
2628 elif pkg.installed:
2629 self._emit_pkg_version(trans, pkg.installed)
2630 else:
2631 for version in pkg.versions:
2632 self._emit_pkg_version(trans, version)
2633
2634 def _emit_visible_package(self, trans, filters, pkg, info=None):
2635 """
2636 Filter and emit a package
2637 """
2638 if self._is_package_visible(pkg, filters):
2639 self._emit_package(trans, pkg, info)
2640
2641 def _emit_visible_packages(self, trans, filters, pkgs, info=None):
2642 """
2643 Filter and emit packages
2644 """
2645 for pkg in pkgs:
2646 if self._is_package_visible(pkg, filters):
2647 self._emit_package(trans, pkg, info)
2648
2649 def _emit_visible_packages_by_name(self, trans, filters, pkgs, info=None):
2650 """
2651 Find the packages with the given namens. Afterwards filter and emit
2652 them
2653 """
2654 for name_raw in pkgs:
2655 #FIXME: Python-apt doesn't allow unicode as key. See #542965
2656 name = str(name_raw)
2657 if self._cache.has_key(name) and \
2658 self._is_package_visible(self._cache[name], filters):
2659 self._emit_package(trans, self._cache[name], info)
2660
2661 def _is_package_visible(self, pkg, filters):
2662 """
2663 Return True if the package should be shown in the user interface
2664 """
2665 if filters == [pk_enums.FILTER_NONE]:
2666 return True
2667 for filter in filters:
2668 if (filter == pk_enums.FILTER_INSTALLED and not pkg.is_installed) or \
2669 (filter == pk_enums.FILTER_NOT_INSTALLED and pkg.is_installed) or \
2670 (filter == pk_enums.FILTER_SUPPORTED and not \
2671 self._is_package_supported(pkg)) or \
2672 (filter == pk_enums.FILTER_NOT_SUPPORTED and \
2673 self._is_package_supported(pkg)) or \
2674 (filter == pk_enums.FILTER_FREE and not self._is_package_free(pkg)) or \
2675 (filter == pk_enums.FILTER_NOT_FREE and \
2676 not self._is_package_not_free(pkg)) or \
2677 (filter == pk_enums.FILTER_GUI and not self._has_package_gui(pkg)) or \
2678 (filter == pk_enums.FILTER_NOT_GUI and self._has_package_gui(pkg)) or \
2679 (filter == pk_enums.FILTER_COLLECTIONS and not \
2680 self._is_package_collection(pkg)) or \
2681 (filter == pk_enums.FILTER_NOT_COLLECTIONS and \
2682 self._is_package_collection(pkg)) or\
2683 (filter == pk_enums.FILTER_DEVELOPMENT and not \
2684 self._is_package_devel(pkg)) or \
2685 (filter == pk_enums.FILTER_NOT_DEVELOPMENT and \
2686 self._is_package_devel(pkg)):
2687 return False
2688 return True
2689
2690 def _is_package_not_free(self, pkg):
2691 """
2692 Return True if we can be sure that the package's license isn't any
2693 free one
2694 """
2695 if not pkg.candidate:
2696 return False
2697 origins = pkg.candidate.origins
2698 return (origins and
2699 ((origins[0].origin == "Ubuntu" and
2700 candidate[0].component in ["multiverse", "restricted"]) or
2701 (origins[0].origin == "Debian" and
2702 origins[0].component in ["contrib", "non-free"])) and
2703 origins[0].trusted)
2704
2705 def _is_package_collection(self, pkg):
2706 """
2707 Return True if the package is a metapackge
2708 """
2709 section = pkg.section.split("/")[-1]
2710 return section == "metapackages"
2711
2712 def _is_package_free(self, pkg):
2713 """
2714 Return True if we can be sure that the package has got a free license
2715 """
2716 if not pkg.candidate:
2717 return False
2718 origins = pkg.candidate.origins
2719 return (origins and
2720 ((origins[0].origin == "Ubuntu" and
2721 candidate[0].component in ["main", "universe"]) or
2722 (origins[0].origin == "Debian" and
2723 origins[0].component == "main")) and
2724 origins[0].trusted)
2725
2726 def _has_package_gui(self, pkg):
2727 #FIXME: should go to a modified Package class
2728 #FIXME: take application data into account. perhaps checking for
2729 # property in the xapian database
2730 return pkg.section.split('/')[-1].lower() in ['x11', 'gnome', 'kde']
2731
2732 def _is_package_devel(self, pkg):
2733 #FIXME: should go to a modified Package class
2734 return pkg.name.endswith("-dev") or pkg.name.endswith("-dbg") or \
2735 pkg.section.split('/')[-1].lower() in ['devel', 'libdevel']
2736
2737 def _is_package_supported(self, pkg):
2738 if not pkg.candidate:
2739 return False
2740 origins = pkg.candidate.origins
2741 return (origins and
2742 ((origins[0].origin == "Ubuntu" and
2743 candidate[0].component in ["main", "restricted"]) or
2744 (origins[0].origin == "Debian" and
2745 origins[0].component == "main")) and
2746 origins[0].trusted)
2747
2748 def _get_package_by_id(self, id):
2749 """Return the apt.package.Package corresponding to the given
2750 package id.
2751
2752 If the package isn't available error out.
2753 """
2754 version = self._get_version_by_id(id)
2755 return version.package
2756
2757 def _get_version_by_id(self, id):
2758 """Return the apt.package.Version corresponding to the given
2759 package id.
2760
2761 If the version isn't available error out.
2762 """
2763 name, version_string, arch, data = id.split(";", 4)
2764 if arch and arch != apt_pkg.config.find("APT::Architecture") and \
2765 arch != "all":
2766 name += ":%s" % arch
2767 try:
2768 pkg = self._cache[name]
2769 except KeyError:
2770 raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
2771 "There isn't any package named %s",
2772 name)
2773 #FIXME:This requires a not yet released fix in python-apt
2774 try:
2775 version = pkg.versions[version_string]
2776 except:
2777 raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
2778 "Verion %s doesn't exist",
2779 version_string)
2780 if version.architecture != arch:
2781 raise TransactionFailed(aptd_enums.ERROR_NO_PACKAGE,
2782 "Version %s of %s isn't available "
2783 "for architecture %s",
2784 pkg.name, version.version, arch)
2785 return version
2786
2787 def _get_installed_files(self, pkg):
2788 """
2789 Return the list of unicode names of the files which have
2790 been installed by the package
2791
2792 This method should be obsolete by the apt.package.Package.installedFiles
2793 attribute as soon as the consolidate branch of python-apt gets merged
2794 """
2795 path = os.path.join(apt_pkg.config["Dir"],
2796 "var/lib/dpkg/info/%s.list" % pkg.name)
2797 try:
2798 list = open(path)
2799 files = list.read().decode().split("\n")
2800 list.close()
2801 except:
2802 return []
2803 return files
2804
2805 def _get_package_group(self, pkg):
2806 """
2807 Return the packagekit group corresponding to the package's section
2808 """
2809 section = pkg.section.split("/")[-1]
2810 if SECTION_GROUP_MAP.has_key(section):
2811 return SECTION_GROUP_MAP[section]
2812 else:
2813 pklog.debug("Unkown package section %s of %s" % (pkg.section,
2814 pkg.name))
2815 return pk_enums.GROUP_UNKNOWN
2816
2817 def _init_plugins(self):
2818 """Initialize PackageKit apt backend plugins.
2819
2820 Do nothing if plugins are already initialized.
2821 """
2822 if self._plugins is not None:
2823 return
2824
2825 if not pkg_resources:
2826 return
2827
2828 self._plugins = {} # plugin_name -> [plugin_fn1, ...]
2829
2830 # just look in standard Python paths for now
2831 dists, errors = pkg_resources.working_set.find_plugins(pkg_resources.Environment())
2832 for dist in dists:
2833 pkg_resources.working_set.add(dist)
2834 for plugin_name in ["what_provides"]:
2835 for entry_point in pkg_resources.iter_entry_points(
2836 "packagekit.apt.plugins", plugin_name):
2837 try:
2838 plugin = entry_point.load()
2839 except Exception as e:
2840 pklog.warning("Failed to load %s from plugin %s: %s" % (
2841 plugin_name, str(entry_point.dist), str(e)))
2842 continue
2843 pklog.debug("Loaded %s from plugin %s" % (
2844 plugin_name, str(entry_point.dist)))
2845 self._plugins.setdefault(plugin_name, []).append(plugin)
2846
2847 def _apply_changes(self, trans, fetch_range=(15, 50),
2848 install_range=(50, 90)):
2849 """Apply changes and emit RequireRestart accordingly."""
2850 aptdaemon.worker.AptWorker._apply_changes(self, trans,
2851 fetch_range,
2852 install_range)
2853 if (hasattr(trans, "pktrans") and
2854 (trans.role == aptd_enums.ROLE_UPGRADE_SYSTEM or
2855 trans.packages[aptd_enums.PKGS_UPGRADE] or
2856 trans.depends[aptd_enums.PKGS_UPGRADE])):
2857 self._emit_require_restart(trans)
2858
2859
2860if META_RELEASE_SUPPORT:
2861
2862 class GMetaRelease(GObject.GObject, MetaReleaseCore):
2863
2864 __gsignals__ = {"download-done": (GObject.SignalFlags.RUN_FIRST,
2865 None,
2866 ())}
2867
2868 def __init__(self):
2869 GObject.GObject.__init__(self)
2870 MetaReleaseCore.__init__(self, False, False)
2871
2872 def download(self):
2873 MetaReleaseCore.download(self)
2874 self.emit("download-done")
2875
2876
2877def get_pk_exit_enum(enum):
2878 try:
2879 return MAP_EXIT_ENUM[enum]
2880 except KeyError:
2881 return pk_enums.EXIT_UNKNOWN
2882
2883def get_pk_status_enum(enum):
2884 try:
2885 return MAP_STATUS_ENUM[enum]
2886 except KeyError:
2887 return pk_enums.STATUS_UNKNOWN
2888
2889def get_pk_package_enum(enum):
2890 try:
2891 return MAP_PACKAGE_ENUM[enum]
2892 except KeyError:
2893 return pk_enums.INFO_UNKNOWN
2894
2895def get_pk_error_enum(enum):
2896 try:
2897 return MAP_ERROR_ENUM[enum]
2898 except KeyError:
2899 return pk_enums.ERROR_UNKNOWN
2900
2901def get_aptd_package_id(pk_id):
2902 """Convert a PackageKit Package ID to the apt syntax.
2903 e.g. xterm;235;i386;installed to xterm:i386=235
2904 """
2905 name, version, arch, data = pk_id.split(";")
2906 id = name
2907 if arch != apt_pkg.config.find("APT::Architecture") and arch != "all":
2908 id += ":%s" % arch
2909 if version:
2910 id += "=%s" % version
2911 return id
2912
2913def get_pk_package_id(pk_id, data=""):
2914 """Convert an AptDaemon package ID to the PackageKit syntax.
2915 e.g. xterm:i368=235; to xterm;235;i386;installed
2916 """
2917 #FIXME add arch support
2918 name, version, release = \
2919 aptdaemon.worker.AptWorker._split_package_id(pk_id)
2920 try:
2921 name, arch = name.split(":", 1)
2922 except ValueError:
2923 arch = ""
2924 if version is None:
2925 version = ""
2926 if release is None:
2927 release = ""
2928 return "%s;%s;%s;%s" % (name, version, arch, data or release)
2929
2930def defer_idle(func, *args):
2931 func(*args)
2932 return False
2933
2934if __name__ == '__main__':
2935 main()
2936
2937# vim: ts=4 et sts=4
02938
=== added directory '.pc/fix-lp-971748.patch'
=== added directory '.pc/fix-lp-971748.patch/aptdaemon'
=== added file '.pc/fix-lp-971748.patch/aptdaemon/networking.py'
--- .pc/fix-lp-971748.patch/aptdaemon/networking.py 1970-01-01 00:00:00 +0000
+++ .pc/fix-lp-971748.patch/aptdaemon/networking.py 2012-08-11 01:29:19 +0000
@@ -0,0 +1,262 @@
1# networking - Monitor the network status
2#
3# Copyright (c) 2010 Mohamed Amine IL Idrissi
4# Copyright (c) 2011 Canonical
5# Copyright (c) 2011 Sebastian Heinlein
6#
7# Author: Alex Chiang <achiang@canonical.com>
8# Michael Vogt <michael.vogt@ubuntu.com>
9# Mohamed Amine IL Idrissi <ilidrissiamine@gmail.com>
10# Sebastian Heinlein <devel@glatzor.de>
11
12# This program is free software; you can redistribute it and/or
13# modify it under the terms of the GNU General Public License as
14# published by the Free Software Foundation; either version 2 of the
15# License, or (at your option) any later version.
16#
17# This program is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20# GNU General Public License for more details.
21#
22# You should have received a copy of the GNU General Public License
23# along with this program; if not, write to the Free Software
24# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25# USA
26
27import defer
28from defer import Deferred, inline_callbacks, return_value
29from gi.repository import GObject
30from gi.repository import Gio
31import dbus
32from dbus.mainloop.glib import DBusGMainLoop
33DBusGMainLoop(set_as_default=True)
34import logging
35import os
36import packagekit.enums as pk_enums
37
38log = logging.getLogger("AptDaemon.NetMonitor")
39
40
41class NetworkMonitorBase(GObject.GObject):
42
43 """Check the network state."""
44
45 __gsignals__ = {"network-state-changed": (GObject.SignalFlags.RUN_FIRST,
46 None,
47 (GObject.TYPE_STRING,))}
48
49 def __init__(self):
50 log.debug("Initializing network monitor")
51 GObject.GObject.__init__(self)
52 self._state = pk_enums.NETWORK_ONLINE
53
54 def _set_state(self, enum):
55 if self._state != enum:
56 log.debug("Network state changed: %s", enum)
57 self._state = enum
58 self.emit("network-state-changed", enum)
59
60 def _get_state(self):
61 return self._state
62
63 state = property(_get_state, _set_state)
64
65 @inline_callbacks
66 def get_network_state(self):
67 """Update the network state."""
68 return_value(self._state)
69
70
71class ProcNetworkMonitor(NetworkMonitorBase):
72
73 """Use the route information of the proc filesystem to detect
74 the network state.
75 """
76
77 def __init__(self):
78 log.debug("Initializing proc based network monitor")
79 NetworkMonitorBase.__init__(self)
80 self._state = pk_enums.NETWORK_OFFLINE
81 self._file = Gio.File.new_for_path("/proc/net/route")
82 self._monitor = Gio.File.monitor(self._file,
83 Gio.FileMonitorFlags.NONE,
84 None)
85 self._monitor.connect("changed",
86 self._on_route_file_changed)
87
88 def _on_route_file_changed(self, *args):
89 self.state = self._parse_route_file()
90
91 def _parse_route_file(self):
92 """Parse the route file - taken from PackageKit"""
93 with open("/proc/net/route") as route_file:
94 for line in route_file.readlines():
95 rows = line.split("\t")
96 # The header line?
97 if rows[0] == "Iface":
98 continue
99 # A loopback device?
100 elif rows[0] == "lo":
101 continue
102 # Correct number of rows?
103 elif len(rows) != 11:
104 continue
105 # The route is a default gateway
106 elif rows[1] == "00000000":
107 break
108 # A gateway is set
109 elif rows[2] != "00000000":
110 break
111 else:
112 return pk_enums.NETWORK_OFFLINE
113 return pk_enums.NETWORK_ONLINE
114
115 @inline_callbacks
116 def get_network_state(self):
117 """Update the network state."""
118 self.state = self._parse_route_file()
119
120
121class NetworkManagerMonitor(NetworkMonitorBase):
122
123 """Use NetworkManager to monitor network state."""
124
125 NM_DBUS_IFACE = "org.freedesktop.NetworkManager"
126 NM_ACTIVE_CONN_DBUS_IFACE = NM_DBUS_IFACE + ".Connection.Active"
127 NM_DEVICE_DBUS_IFACE = NM_DBUS_IFACE + ".Device"
128
129 # The device type is unknown
130 NM_DEVICE_TYPE_UNKNOWN = 0
131 # The device is wired Ethernet device
132 NM_DEVICE_TYPE_ETHERNET = 1
133 # The device is an 802.11 WiFi device
134 NM_DEVICE_TYPE_WIFI = 2
135 # The device is a GSM-based cellular WAN device
136 NM_DEVICE_TYPE_GSM = 3
137 # The device is a CDMA/IS-95-based cellular WAN device
138 NM_DEVICE_TYPE_CDMA = 4
139
140 def __init__(self):
141 log.debug("Initializing NetworkManager monitor")
142 NetworkMonitorBase.__init__(self)
143 self._state = pk_enums.NETWORK_UNKNOWN
144 self.bus = dbus.SystemBus()
145 self.proxy = self.bus.get_object("org.freedesktop.NetworkManager",
146 "/org/freedesktop/NetworkManager")
147 self.proxy.connect_to_signal("PropertiesChanged",
148 self._on_nm_properties_changed,
149 dbus_interface=self.NM_DBUS_IFACE)
150 self.bus.add_signal_receiver(self._on_nm_active_conn_props_changed,
151 signal_name="PropertiesChanged",
152 dbus_interface=self.NM_ACTIVE_CONN_DBUS_IFACE)
153
154 @staticmethod
155 def get_dbus_property(proxy, interface, property):
156 """Small helper to get the property value of a dbus object."""
157 props = dbus.Interface(proxy, "org.freedesktop.DBus.Properties")
158 deferred = Deferred()
159 props.Get(interface, property,
160 reply_handler=deferred.callback,
161 error_handler=deferred.errback)
162 return deferred
163
164 @inline_callbacks
165 def _on_nm_properties_changed(self, props):
166 """Callback if NetworkManager properties changed."""
167 if "ActiveConnections" in props:
168 if not props["ActiveConnections"]:
169 log.debug("There aren't any active connections")
170 self.state = pk_enums.NETWORK_OFFLINE
171 else:
172 self.state = yield self.get_network_state()
173
174 @inline_callbacks
175 def _on_nm_active_conn_props_changed(self, props):
176 """Callback if properties of the active connection changed."""
177 if not "Default" in props:
178 raise StopIteration
179 self.state = yield self.get_network_state()
180
181 @inline_callbacks
182 def get_network_state(self):
183 """Query NetworkManager about the network state."""
184 state = pk_enums.NETWORK_UNKNOWN
185 try:
186 active_conns = yield self.get_dbus_property(self.proxy,
187 self.NM_DBUS_IFACE,
188 "ActiveConnections")
189 except dbus.DBusException:
190 log.warning("Failed to determinate network state")
191 return_value(state)
192
193 for conn in active_conns:
194 conn_obj = self.bus.get_object(self.NM_DBUS_IFACE, conn)
195 try:
196 is_default = yield self.get_dbus_property(conn_obj,
197 self.NM_ACTIVE_CONN_DBUS_IFACE,
198 "Default")
199 if not is_default:
200 continue
201 devs = yield self.get_dbus_property(conn_obj,
202 self.NM_ACTIVE_CONN_DBUS_IFACE,
203 "Devices")
204 except dbus.DBusException:
205 log.warning("Failed to determinate network state")
206 break
207 priority_device_type = -1
208 for dev in devs:
209 try:
210 dev_obj = self.bus.get_object(self.NM_DBUS_IFACE, dev)
211 dev_type = yield self.get_dbus_property(dev_obj,
212 self.NM_DEVICE_DBUS_IFACE,
213 "DeviceType")
214 except dbus.DBusException:
215 log.warning("Failed to determinate network state")
216 return_value(pk_enums.NETWORK_UNKNOWN)
217 # prioterizse device types, since a bridged GSM/CDMA connection
218 # should be returned as a GSM/CDMA one
219 # The NM_DEVICE_TYPE_* enums are luckly ordered in this sense.
220 if dev_type <= priority_device_type:
221 continue
222 priority_device_type = dev_type
223
224 if dev_type in (self.NM_DEVICE_TYPE_GSM,
225 self.NM_DEVICE_TYPE_CDMA):
226 state = pk_enums.NETWORK_MOBILE
227 elif dev_type == self.NM_DEVICE_TYPE_ETHERNET:
228 state = pk_enums.NETWORK_WIRED
229 elif dev_type == self.NM_DEVICE_TYPE_WIFI:
230 state = pk_enums.NETWORK_WIFI
231 elif dev_type == self.NM_DEVICE_TYPE_UNKNOWN:
232 state = pk_enums.NETWORK_OFFLINE
233 else:
234 state = pk_enums.NETWORK_ONLINE
235 return_value(state)
236
237
238def get_network_monitor(fallback=False):
239 """Return a network monitor."""
240 if fallback:
241 return ProcNetworkMonitor()
242 try:
243 return NetworkManagerMonitor()
244 except dbus.DBusException:
245 pass
246 if os.path.exists("/proc/net/route"):
247 return ProcNetworkMonitor()
248 return NetworkMonitorBase()
249
250
251if __name__ == "__main__":
252 @inline_callbacks
253 def _call_monitor():
254 state = yield monitor.get_network_state()
255 print("Initial network state: %s" % state)
256 log_handler = logging.StreamHandler()
257 log.addHandler(log_handler)
258 log.setLevel(logging.DEBUG)
259 monitor = get_network_monitor(True)
260 _call_monitor()
261 loop = GObject.MainLoop()
262 loop.run()
0263
=== added file '.pc/fix-lp-971748.patch/aptdaemon/pkcompat.py'
--- .pc/fix-lp-971748.patch/aptdaemon/pkcompat.py 1970-01-01 00:00:00 +0000
+++ .pc/fix-lp-971748.patch/aptdaemon/pkcompat.py 2012-08-11 01:29:19 +0000
@@ -0,0 +1,2940 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3"""
4Provides a limited compatibility layer to PackageKit
5
6Copyright (C) 2007 Ali Sabil <ali.sabil@gmail.com>
7Copyright (C) 2007 Tom Parker <palfrey@tevp.net>
8Copyright (C) 2008-2011 Sebastian Heinlein <glatzor@ubuntu.com>
9
10Licensed under the GNU General Public License Version 2
11
12This program is free software; you can redistribute it and/or modify
13it under the terms of the GNU General Public License as published by
14the Free Software Foundation; either version 2 of the License, or
15(at your option) any later version.
16"""
17
18__author__ = "Sebastian Heinlein <devel@glatzor.de>"
19
20import datetime
21import glob
22import gzip
23import locale
24import logging
25import os
26import re
27import subprocess
28import tempfile
29import time
30import traceback
31import uuid
32
33import apt
34import apt_pkg
35from defer import inline_callbacks, return_value
36from defer.utils import dbus_deferred_method
37import dbus
38from gi.repository import GObject
39import lsb_release
40import packagekit.enums as pk_enums
41
42# for optional plugin support
43try:
44 import pkg_resources
45except ImportError:
46 pkg_resources = None
47
48from aptdaemon import policykit1
49import aptdaemon.core
50from aptdaemon.core import APTDAEMON_TRANSACTION_DBUS_INTERFACE
51import aptdaemon.enums as aptd_enums
52from aptdaemon.errors import TransactionFailed, TransactionCancelled
53from aptdaemon.progress import DaemonAcquireProgress
54import aptdaemon.worker
55import aptdaemon.networking
56
57GObject.threads_init()
58
59pklog = logging.getLogger("AptDaemon.PackageKit")
60
61# Check if update-manager-core is installed to get aware of the
62# latest distro releases
63try:
64 from UpdateManager.Core.MetaRelease import MetaReleaseCore
65except ImportError:
66 META_RELEASE_SUPPORT = False
67else:
68 META_RELEASE_SUPPORT = True
69
70# Xapian database is optionally used to speed up package description search
71XAPIAN_DB_PATH = os.environ.get("AXI_DB_PATH", "/var/lib/apt-xapian-index")
72XAPIAN_DB = XAPIAN_DB_PATH + "/index"
73XAPIAN_DB_VALUES = XAPIAN_DB_PATH + "/values"
74XAPIAN_SUPPORT = False
75try:
76 import xapian
77except ImportError:
78 pass
79else:
80 if os.access(XAPIAN_DB, os.R_OK):
81 pklog.debug("Use XAPIAN for the search")
82 XAPIAN_SUPPORT = True
83
84# Regular expressions to detect bug numbers in changelogs according to the
85# Debian Policy Chapter 4.4. For details see the footnote 16:
86# http://www.debian.org/doc/debian-policy/footnotes.html#f16
87MATCH_BUG_CLOSES_DEBIAN=r"closes:\s*(?:bug)?\#?\s?\d+(?:,\s*(?:bug)?\#?\s?\d+)*"
88MATCH_BUG_NUMBERS=r"\#?\s?(\d+)"
89# URL pointing to a bug in the Debian bug tracker
90HREF_BUG_DEBIAN="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s"
91
92MATCH_BUG_CLOSES_UBUNTU = r"lp:\s+\#\d+(?:,\s*\#\d+)*"
93HREF_BUG_UBUNTU = "https://bugs.launchpad.net/bugs/%s"
94
95# Regular expression to find cve references
96MATCH_CVE="CVE-\d{4}-\d{4}"
97HREF_CVE="http://web.nvd.nist.gov/view/vuln/detail?vulnId=%s"
98
99# Map Debian sections to the PackageKit group name space
100SECTION_GROUP_MAP = {
101 "admin" : pk_enums.GROUP_ADMIN_TOOLS,
102 "base" : pk_enums.GROUP_SYSTEM,
103 "comm" : pk_enums.GROUP_COMMUNICATION,
104 "devel" : pk_enums.GROUP_PROGRAMMING,
105 "doc" : pk_enums.GROUP_DOCUMENTATION,
106 "editors" : pk_enums.GROUP_PUBLISHING,
107 "electronics" : pk_enums.GROUP_ELECTRONICS,
108 "embedded" : pk_enums.GROUP_SYSTEM,
109 "games" : pk_enums.GROUP_GAMES,
110 "gnome" : pk_enums.GROUP_DESKTOP_GNOME,
111 "graphics" : pk_enums.GROUP_GRAPHICS,
112 "hamradio" : pk_enums.GROUP_COMMUNICATION,
113 "interpreters" : pk_enums.GROUP_PROGRAMMING,
114 "kde" : pk_enums.GROUP_DESKTOP_KDE,
115 "libdevel" : pk_enums.GROUP_PROGRAMMING,
116 "libs" : pk_enums.GROUP_SYSTEM,
117 "mail" : pk_enums.GROUP_INTERNET,
118 "math" : pk_enums.GROUP_SCIENCE,
119 "misc" : pk_enums.GROUP_OTHER,
120 "net" : pk_enums.GROUP_NETWORK,
121 "news" : pk_enums.GROUP_INTERNET,
122 "oldlibs" : pk_enums.GROUP_LEGACY,
123 "otherosfs" : pk_enums.GROUP_SYSTEM,
124 "perl" : pk_enums.GROUP_PROGRAMMING,
125 "python" : pk_enums.GROUP_PROGRAMMING,
126 "science" : pk_enums.GROUP_SCIENCE,
127 "shells" : pk_enums.GROUP_SYSTEM,
128 "sound" : pk_enums.GROUP_MULTIMEDIA,
129 "tex" : pk_enums.GROUP_PUBLISHING,
130 "text" : pk_enums.GROUP_PUBLISHING,
131 "utils" : pk_enums.GROUP_ACCESSORIES,
132 "web" : pk_enums.GROUP_INTERNET,
133 "x11" : pk_enums.GROUP_DESKTOP_OTHER,
134 "unknown" : pk_enums.GROUP_UNKNOWN,
135 "alien" : pk_enums.GROUP_UNKNOWN,
136 "translations" : pk_enums.GROUP_LOCALIZATION,
137 "metapackages" : pk_enums.GROUP_COLLECTIONS }
138
139PACKAGEKIT_DBUS_INTERFACE = "org.freedesktop.PackageKit"
140PACKAGEKIT_DBUS_SERVICE = "org.freedesktop.PackageKit"
141PACKAGEKIT_DBUS_PATH = "/org/freedesktop/PackageKit"
142
143PACKAGEKIT_TRANS_DBUS_INTERFACE = "org.freedesktop.PackageKit.Transaction"
144PACKAGEKIT_TRANS_DBUS_SERVICE = "org.freedesktop.PackageKit.Transaction"
145
146MAP_EXIT_ENUM = {
147 aptd_enums.EXIT_SUCCESS: pk_enums.EXIT_SUCCESS,
148 aptd_enums.EXIT_CANCELLED: pk_enums.EXIT_CANCELLED,
149 aptd_enums.EXIT_FAILED: pk_enums.EXIT_FAILED,
150 aptd_enums.EXIT_FAILED: pk_enums.EXIT_FAILED,
151 aptd_enums.EXIT_PREVIOUS_FAILED:
152 pk_enums.EXIT_FAILED
153 }
154
155MAP_STATUS_ENUM = {
156 aptd_enums.STATUS_WAITING: pk_enums.STATUS_WAIT,
157 aptd_enums.STATUS_RUNNING: pk_enums.STATUS_RUNNING,
158 aptd_enums.STATUS_CANCELLING: pk_enums.STATUS_CANCEL,
159 aptd_enums.STATUS_CLEANING_UP: pk_enums.STATUS_CLEANUP,
160 aptd_enums.STATUS_COMMITTING: pk_enums.STATUS_COMMIT,
161 aptd_enums.STATUS_DOWNLOADING: pk_enums.STATUS_DOWNLOAD,
162 aptd_enums.STATUS_DOWNLOADING_REPO: pk_enums.STATUS_DOWNLOAD_REPOSITORY,
163 aptd_enums.STATUS_FINISHED: pk_enums.STATUS_FINISHED,
164 aptd_enums.STATUS_LOADING_CACHE: pk_enums.STATUS_LOADING_CACHE,
165 aptd_enums.STATUS_RESOLVING_DEP: pk_enums.STATUS_DEP_RESOLVE,
166 aptd_enums.STATUS_RUNNING: pk_enums.STATUS_RUNNING,
167 aptd_enums.STATUS_WAITING_LOCK:
168 pk_enums.STATUS_WAITING_FOR_LOCK,
169 aptd_enums.STATUS_WAITING_MEDIUM: pk_enums.STATUS_UNKNOWN,
170 aptd_enums.STATUS_WAITING_CONFIG_FILE_PROMPT:
171 pk_enums.STATUS_UNKNOWN
172}
173
174MAP_ERROR_ENUM = {
175 aptd_enums.ERROR_CACHE_BROKEN: pk_enums.ERROR_NO_CACHE,
176 aptd_enums.ERROR_DEP_RESOLUTION_FAILED:
177 pk_enums.ERROR_DEP_RESOLUTION_FAILED,
178 aptd_enums.ERROR_INCOMPLETE_INSTALL: pk_enums.ERROR_NO_CACHE,
179 aptd_enums.ERROR_INVALID_PACKAGE_FILE:
180 pk_enums.ERROR_PACKAGE_CORRUPT,
181 aptd_enums.ERROR_KEY_NOT_INSTALLED: pk_enums.ERROR_GPG_FAILURE,
182 aptd_enums.ERROR_KEY_NOT_REMOVED: pk_enums.ERROR_GPG_FAILURE,
183 aptd_enums.ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE:
184 pk_enums.ERROR_PACKAGE_FAILED_TO_REMOVE,
185 aptd_enums.ERROR_NO_CACHE: pk_enums.ERROR_NO_CACHE,
186 aptd_enums.ERROR_NO_LOCK: pk_enums.ERROR_CANNOT_GET_LOCK,
187 aptd_enums.ERROR_NO_PACKAGE: pk_enums.ERROR_PACKAGE_NOT_FOUND,
188 aptd_enums.ERROR_PACKAGE_ALREADY_INSTALLED:
189 pk_enums.ERROR_PACKAGE_ALREADY_INSTALLED,
190 aptd_enums.ERROR_PACKAGE_DOWNLOAD_FAILED:
191 pk_enums.ERROR_PACKAGE_DOWNLOAD_FAILED,
192 aptd_enums.ERROR_PACKAGE_MANAGER_FAILED:
193 pk_enums.ERROR_TRANSACTION_ERROR,
194 aptd_enums.ERROR_PACKAGE_NOT_INSTALLED:
195 pk_enums.ERROR_PACKAGE_NOT_INSTALLED,
196 aptd_enums.ERROR_PACKAGE_UNAUTHENTICATED:
197 pk_enums.ERROR_BAD_GPG_SIGNATURE,
198 aptd_enums.ERROR_PACKAGE_UPTODATE:
199 pk_enums.ERROR_NO_PACKAGES_TO_UPDATE,
200 aptd_enums.ERROR_REPO_DOWNLOAD_FAILED:
201 pk_enums.ERROR_REPO_NOT_AVAILABLE,
202 aptd_enums.ERROR_UNREADABLE_PACKAGE_FILE:
203 pk_enums.ERROR_INVALID_PACKAGE_FILE,
204 aptd_enums.ERROR_SYSTEM_ALREADY_UPTODATE:
205 pk_enums.ERROR_NO_PACKAGES_TO_UPDATE,
206 }
207
208MAP_PACKAGE_ENUM = {
209 aptd_enums.PKG_CONFIGURING:
210 pk_enums.INFO_INSTALLING,
211 aptd_enums.PKG_DISAPPEARING:
212 pk_enums.INFO_UNKNOWN,
213 aptd_enums.PKG_INSTALLED:
214 pk_enums.INFO_FINISHED,
215 aptd_enums.PKG_INSTALLING:
216 pk_enums.INFO_INSTALLING,
217 aptd_enums.PKG_PREPARING_INSTALL:
218 pk_enums.INFO_PREPARING,
219 aptd_enums.PKG_PREPARING_PURGE:
220 pk_enums.INFO_PREPARING,
221 aptd_enums.PKG_PREPARING_REMOVE:
222 pk_enums.INFO_PREPARING,
223 aptd_enums.PKG_PURGED:
224 pk_enums.INFO_FINISHED,
225 aptd_enums.PKG_PURGING:
226 pk_enums.INFO_REMOVING,
227 aptd_enums.PKG_REMOVED:
228 pk_enums.INFO_FINISHED,
229 aptd_enums.PKG_REMOVING:
230 pk_enums.INFO_REMOVING,
231 aptd_enums.PKG_RUNNING_TRIGGER:
232 pk_enums.INFO_CLEANUP,
233 aptd_enums.PKG_UNKNOWN:
234 pk_enums.INFO_UNKNOWN,
235 aptd_enums.PKG_UNPACKING:
236 pk_enums.INFO_DECOMPRESSING,
237 aptd_enums.PKG_UPGRADING:
238 pk_enums.INFO_UPDATING,
239 }
240
241
242class PackageKit(aptdaemon.core.DBusObject):
243
244 """Provides a limited set of the PackageKit system D-Bus API."""
245
246 SUPPORTED_ROLES = [pk_enums.ROLE_REFRESH_CACHE,
247 pk_enums.ROLE_UPDATE_SYSTEM,
248 pk_enums.ROLE_SIMULATE_UPDATE_PACKAGES,
249 pk_enums.ROLE_UPDATE_PACKAGES,
250 pk_enums.ROLE_SIMULATE_REMOVE_PACKAGES,
251 pk_enums.ROLE_INSTALL_PACKAGES,
252 pk_enums.ROLE_SIMULATE_INSTALL_PACKAGES,
253 pk_enums.ROLE_INSTALL_PACKAGES,
254 pk_enums.ROLE_GET_DISTRO_UPGRADES,
255 pk_enums.ROLE_GET_UPDATES,
256 pk_enums.ROLE_GET_UPDATE_DETAIL,
257 pk_enums.ROLE_GET_PACKAGES,
258 pk_enums.ROLE_GET_DETAILS,
259 pk_enums.ROLE_GET_DEPENDS,
260 pk_enums.ROLE_GET_REQUIRES,
261 pk_enums.ROLE_SEARCH_NAME,
262 pk_enums.ROLE_SEARCH_DETAILS,
263 pk_enums.ROLE_SEARCH_GROUP,
264 pk_enums.ROLE_SEARCH_FILE,
265 pk_enums.ROLE_WHAT_PROVIDES,
266 pk_enums.ROLE_DOWNLOAD_PACKAGES]
267
268 SUPPORTED_FILTERS = [pk_enums.FILTER_INSTALLED,
269 pk_enums.FILTER_NOT_INSTALLED,
270 pk_enums.FILTER_FREE,
271 pk_enums.FILTER_NOT_FREE,
272 pk_enums.FILTER_GUI,
273 pk_enums.FILTER_NOT_GUI,
274 pk_enums.FILTER_COLLECTIONS,
275 pk_enums.FILTER_NOT_COLLECTIONS,
276 pk_enums.FILTER_SUPPORTED,
277 pk_enums.FILTER_NOT_SUPPORTED,
278 pk_enums.FILTER_NEWEST]
279
280 def __init__(self, queue, connect=True, bus=None):
281 """Initialize a new PackageKit compatibility layer.
282
283 Keyword arguments:
284 connect -- if the daemon should connect to the D-Bus (default is True)
285 bus -- the D-Bus to connect to (defaults to the system bus)
286 """
287 pklog.info("Initializing PackageKit compat layer")
288 bus_name = None
289 bus_path = None
290 if connect == True:
291 if bus is None:
292 bus = dbus.SystemBus()
293 self.bus = bus
294 bus_path = PACKAGEKIT_DBUS_PATH
295 bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, self.bus)
296 aptdaemon.core.DBusObject.__init__(self, bus_name, bus_path)
297 self._updates_changed_timeout_id = None
298 self._updates_changed = False
299 self.queue = queue
300 self.queue.worker.connect("transaction-done", self._on_transaction_done)
301 self.queue.connect("queue-changed", self._on_queue_changed)
302 self._distro_id = None
303 self.netmon = aptdaemon.networking.get_network_monitor()
304 self.netmon.connect("network-state-changed",
305 self._on_network_state_changed)
306 self.netmon.get_network_state()
307
308 # SIGNALS
309
310 # pylint: disable-msg=C0103,C0322
311 @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
312 signature="")
313 def RestartSchedule(self):
314 """A system restart has been sceduled."""
315 pass
316
317 # pylint: disable-msg=C0103,C0322
318 @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
319 signature="")
320 def Changed(self):
321 """This signal is emitted when a property on the interface changes."""
322 pass
323
324 # pylint: disable-msg=C0103,C0322
325 @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
326 signature="as")
327 def TransactionListChanged(self, transactions):
328 """The transaction list has changed, because either a transaction
329 has finished or a new transaction created.
330
331 :param transactions: A list of transaction ID's.
332 :type transactions: as
333 """
334 pklog.debug("Emitting TransactionListChanged signal: %s", transactions)
335
336 # pylint: disable-msg=C0103,C0322
337 @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
338 signature="")
339 def UpdatesChanged(self):
340 """This signal is emitted when the number of updates has changed."""
341 pklog.debug("Emitting UpdatesChanged signal")
342
343 # pylint: disable-msg=C0103,C0322
344 @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
345 signature="")
346 def RepoListChanged(self):
347 """This signal is emitted when the repository list has changed."""
348 pass
349
350 # pylint: disable-msg=C0103,C0322
351 @dbus.service.signal(dbus_interface=PACKAGEKIT_DBUS_INTERFACE,
352 signature="")
353 def Changed(self):
354 """This signal is emitted when a property on the interface changes."""
355 pklog.debug("Emitting PackageKit Changed()")
356
357 # METHODS
358
359 # pylint: disable-msg=C0103,C0322
360 @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
361 in_signature="s", out_signature="s")
362 def CanAuthorize(self, action_id):
363 """Allows a client to find out if it would be allowed to authorize
364 an action.
365
366 :param action_id: The action ID, e.g.
367 org.freedesktop.packagekit.system-network-proxy-configure
368 :returns: The result, either yes, no or interactive.
369 """
370 #FIXME: We need to map packagekit and aptdaemon polices
371 return "interactive"
372
373 # pylint: disable-msg=C0103,C0322
374 @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
375 in_signature="s", out_signature="")
376 def StateHasChanged(self, reason):
377 """This method suggests to PackageKit that the package backend state
378 may have changed. This allows plugins to the native package manager
379 to suggest that PackageKit drops it's caches.
380
381 :param reason:
382 The reason of the state change. Valid reasons are resume or
383 posttrans. Resume is given a lower priority than posttrans.
384 """
385 pklog.debug("StateHasChanged() was called: %s", reason)
386 self._updates_changed = True
387 if reason == "cache-update":
388 self._check_updates_changed(timeout=30)
389 elif reason == "resume":
390 self._check_updates_changed(timeout=180)
391
392 # pylint: disable-msg=C0103,C0322
393 @dbus_deferred_method(PACKAGEKIT_DBUS_INTERFACE,
394 in_signature="", out_signature="s",
395 sender_keyword="sender")
396 def GetTid(self, sender):
397 """Gets a new transaction ID from the daemon.
398
399 :returns: The tid, e.g. 45_dafeca_checkpoint32
400 """
401 return self._get_tid(sender)
402
403 @inline_callbacks
404 def _get_tid(self, sender):
405 pid, uid, cmdline = \
406 yield policykit1.get_proc_info_from_dbus_name(sender, self.bus)
407 pktrans = PackageKitTransaction(pid, uid, cmdline, self.queue, sender)
408 return_value(pktrans.tid)
409
410 # pylint: disable-msg=C0103,C0322
411 @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
412 in_signature="", out_signature="as")
413 def GetTransactionList(self):
414 """Gets the transaction list of any transactions that are in
415 progress.
416
417 :returns: A list of transaction ID's
418 """
419 pklog.debug("GetTransactionList() was called")
420 return self._get_transaction_list()
421
422 # HELPERS
423
424 def _get_properties(self, iface):
425 """Helper to get the properties of a D-Bus interface."""
426 if iface == PACKAGEKIT_DBUS_INTERFACE:
427 return {# Claim that we are a stable version
428 "VersionMajor": dbus.UInt32(6),
429 "VersionMinor": dbus.UInt32(18),
430 "VersionMicro": dbus.UInt32(0),
431 "BackendName": dbus.String("aptdaemon"),
432 "BackendDescription": dbus.String("Compatibility layer"),
433 "BackendAuthor": dbus.String(__author__),
434 "Filters": dbus.String(";".join(self.SUPPORTED_FILTERS)),
435 "Groups": dbus.String(";".join(SECTION_GROUP_MAP.values())),
436 "Roles": dbus.String(";".join(self.SUPPORTED_ROLES)),
437 "Locked": dbus.Boolean(False),
438 "NetworkState": dbus.String(self.netmon.state),
439 "DistroId": dbus.String(self._get_distro_id()),
440 }
441 else:
442 return {}
443
444 def _get_distro_id(self):
445 """Return information about the distibution."""
446 if self._distro_id is None:
447 info = lsb_release.get_distro_information()
448 arch = subprocess.Popen(["dpkg", "--print-architecture"],
449 stdout=subprocess.PIPE).communicate()[0]
450 try:
451 self._distro_id = "%s;%s;%s" % (info["ID"], info["CODENAME"], arch)
452 except KeyError:
453 self._distro_id = "unknown;unknown;%s" % arch
454 return self._distro_id
455
456 def _on_network_state_changed(self, mon, state):
457 self.Changed()
458 self.PropertiesChanged(PACKAGEKIT_DBUS_INTERFACE,
459 {"Network": state}, [])
460
461 def _on_queue_changed(self, queue):
462 self.TransactionListChanged(self._get_transaction_list())
463 self._check_updates_changed()
464
465 def _get_transaction_list(self):
466 pk_transactions = []
467 for trans in self.queue.items:
468 # We currently only emit PackageKit transaction
469 #FIXME: Should we use MergedTransaction for all transactions and
470 # ROLE_UNKOWN for aptdaemon only transactions?
471 try:
472 pk_transactions.append(trans.pktrans.tid)
473 except AttributeError:
474 pass
475 try:
476 pk_transactions.append(self.queue.worker.trans.pktrans.tid)
477 except AttributeError:
478 pass
479 return pk_transactions
480
481 def _on_transaction_done(self, worker, trans):
482 # If a cache modifing transaction is completed schedule an
483 # UpdatesChanged signal
484 if trans.role in (aptd_enums.ROLE_INSTALL_FILE,
485 aptd_enums.ROLE_INSTALL_PACKAGES,
486 aptd_enums.ROLE_REMOVE_PACKAGES,
487 aptd_enums.ROLE_UPGRADE_PACKAGES,
488 aptd_enums.ROLE_COMMIT_PACKAGES,
489 aptd_enums.ROLE_UPGRADE_SYSTEM,
490 aptd_enums.ROLE_FIX_BROKEN_DEPENDS):
491 self._updates_changed = True
492 self._check_updates_changed()
493 elif trans.role == aptd_enums.ROLE_UPDATE_CACHE:
494 self._updates_changed = True
495 self._check_updates_changed(timeout=30)
496
497 def _check_updates_changed(self, timeout=60):
498 """After the queue was processed schedule a delayed UpdatesChanged
499 signal if required.
500 """
501 if not self.queue.items and self._updates_changed:
502 if self._updates_changed_timeout_id:
503 # If we already have a scheduled UpdatesChanged signal
504 # delay it even further
505 pklog.debug("UpdatesChanged signal re-scheduled")
506 GObject.source_remove(self._updates_changed_timeout_id)
507 else:
508 pklog.debug("UpdatesChanged signal scheduled")
509 self._updates_changed_timeout_id = \
510 GObject.timeout_add_seconds(timeout,
511 self._delayed_updates_changed)
512
513 def _delayed_updates_changed(self):
514 """Emit the UpdatesChanged signal and clear the timeout."""
515 self.UpdatesChanged()
516 self._updates_changed_timeout_id = None
517 self._updates_changed = False
518 return False
519
520
521class MergedTransaction(aptdaemon.core.Transaction):
522
523 """Overlay of an Aptdaemon transaction which also provides the
524 PackageKit object and its interfaces.
525 """
526
527 def __init__(self, pktrans, role, queue, connect=True,
528 bus=None, packages=None, kwargs=None):
529 aptdaemon.core.Transaction.__init__(self, pktrans.tid[1:], role, queue,
530 pktrans.pid, pktrans.uid,
531 pktrans.cmdline, pktrans.sender,
532 connect, bus, packages, kwargs)
533 self.pktrans = pktrans
534 self.run_time = 0
535
536 def _set_status(self, enum):
537 aptdaemon.core.Transaction._set_status(self, enum)
538 self.pktrans.status = get_pk_status_enum(enum)
539
540 status = property(aptdaemon.core.Transaction._get_status, _set_status)
541
542 def _set_progress(self, percent):
543 aptdaemon.core.Transaction._set_progress(self, percent)
544 self.pktrans.percentage = self._progress
545
546 progress = property(aptdaemon.core.Transaction._get_progress, _set_progress)
547
548 def _set_progress_details(self, details):
549 aptdaemon.core.Transaction._set_progress_details(self, details)
550 self.pktrans.speed = int(details[4])
551 self.pktrans.remaining_time = int(details[5])
552 self.pktrans.elapsed_time = int(time.time() - self.pktrans.start_time)
553
554 progress_details = property(aptdaemon.core.Transaction._get_progress_details,
555 _set_progress_details)
556
557 def _set_progress_package(self, progress):
558 aptdaemon.core.Transaction._set_progress_package(self, progress)
559 pkg_name, enum = progress
560 self.emit_package(get_pk_package_enum(enum),
561 get_pk_package_id(pkg_name),
562 "")
563
564 progress_package = property(aptdaemon.core.Transaction._get_progress_package,
565 _set_progress_package)
566
567
568 def _set_exit(self, enum):
569 aptdaemon.core.Transaction._set_exit(self, enum)
570 self.pktrans.exit = get_pk_exit_enum(enum)
571
572 exit = property(aptdaemon.core.Transaction._get_exit, _set_exit)
573
574 def _set_error(self, excep):
575 aptdaemon.core.Transaction._set_error(self, excep)
576 self.pktrans.ErrorCode(get_pk_error_enum(excep.code),
577 self._error_property[1])
578
579 error = property(aptdaemon.core.Transaction._get_error, _set_error)
580
581 def _remove_from_connection_no_raise(self):
582 aptdaemon.core.Transaction._remove_from_connection_no_raise(self)
583 self.pktrans.Destroy()
584 try:
585 self.pktrans.remove_from_connection()
586 except LookupError as error:
587 pklog.debug("remove_from_connection() raised LookupError: %s",
588 error)
589 finally:
590 self.pktrans.trans = None
591 self.pktrans = None
592 return False
593
594 def emit_details(self, package_id, license, group, detail, url, size):
595 self.pktrans.Details(package_id, license, group, detail, url, size)
596
597 def emit_files(self, id, file_list):
598 self.pktrans.Files(id, file_list)
599
600 def emit_package(self, info, id, summary):
601 self.pktrans.Package(info, id, summary)
602 self.pktrans.last_package = id
603
604 def emit_update_detail(self, package_id, updates, obsoletes, vendor_url,
605 bugzilla_url, cve_url, restart, update_text,
606 changelog, state, issued, updated):
607 self.pktrans.UpdateDetail(package_id, updates, obsoletes, vendor_url,
608 bugzilla_url, cve_url, restart, update_text,
609 changelog, state, issued, updated)
610
611
612class PackageKitTransaction(aptdaemon.core.DBusObject):
613
614 """Provides a PackageKit transaction object."""
615
616 def __init__(self, pid, uid, cmdline, queue, sender,
617 connect=True, bus=None):
618 pklog.info("Initializing PackageKit transaction")
619 bus_name = None
620 bus_path = None
621 self.tid = "/%s" % uuid.uuid4().get_hex()
622 if connect == True:
623 if bus is None:
624 bus = dbus.SystemBus()
625 self.bus = bus
626 bus_path = self.tid
627 bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, bus)
628 aptdaemon.core.DBusObject.__init__(self, bus_name, bus_path)
629 self.queue = queue
630 self.hints = {}
631 self.start_time = time.time()
632 self._elapsed_time = 0
633 self._remaining_time = 0
634 self._speed = 0
635 self._caller_active = True
636 self._allow_cancel = False
637 self._percentage = 0
638 self._subpercentage = 0
639 self._status = pk_enums.STATUS_SETUP
640 self._last_package = ""
641 self.uid = uid
642 self.pid = pid
643 self.cmdline = cmdline
644 self.role = pk_enums.ROLE_UNKNOWN
645 self.sender = sender
646 self.trans = None
647
648 @property
649 def allow_cancel(self):
650 return self._allow_cancel
651
652 @allow_cancel.setter
653 def allow_cancel(self, value):
654 self._allow_cancel = dbus.Boolean(value)
655 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
656 {"AllowCancel": self._allow_cancel}, [])
657 self.Changed()
658
659 @property
660 def last_package(self):
661 return self._last_package
662
663 @last_package.setter
664 def last_package(self, value):
665 self._last_package = dbus.String(value)
666 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
667 {"LastPackage": self._last_package}, [])
668 self.Changed()
669
670 @property
671 def caller_active(self):
672 return self._caller_active
673
674 @caller_active.setter
675 def caller_active(self, value):
676 self._caller_active = dbus.Boolean(value)
677 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
678 {"CallerActive": self._caller_active}, [])
679 self.Changed()
680
681 @property
682 def percentage(self):
683 return self._percentage
684
685 @percentage.setter
686 def percentage(self, progress):
687 self._percentage = dbus.UInt32(progress)
688 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
689 {"Percentage": self._percentage}, [])
690 self.Changed()
691
692 @property
693 def subpercentage(self):
694 return self._subpercentage
695
696 @subpercentage.setter
697 def subpercentage(self, progress):
698 self._subpercentage = dbus.UInt32(progress)
699 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
700 {"SubPercentage": self._subpercentage}, [])
701 self.Changed()
702
703 @property
704 def status(self):
705 return self._status
706
707 @status.setter
708 def status(self, enum):
709 self._status = dbus.String(enum)
710 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
711 {"Status": self._status}, [])
712 self.Changed()
713
714 @property
715 def elapsed_time(self):
716 return self._elapsed_time
717
718 @elapsed_time.setter
719 def elapsed_time(self, ela):
720 self._elpased_time = dbus.UInt32(ela)
721 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
722 {"ElapsedTime": self._elapsed_time}, [])
723 self.Changed()
724
725 @property
726 def remaining_time(self):
727 return self._remaining_time
728
729 @remaining_time.setter
730 def remaining_time(self, value):
731 self._elpased_time = dbus.UInt32(value)
732 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
733 {"RemainingTime": self._remaining_time}, [])
734 self.Changed()
735
736 @property
737 def speed(self):
738 return self._speed
739
740 @speed.setter
741 def speed(self, speed):
742 self._speed = dbus.UInt32(speed)
743 self.PropertiesChanged(PACKAGEKIT_TRANS_DBUS_INTERFACE,
744 {"AllowCancel": self._speed}, [])
745 self.Changed()
746
747 @property
748 def exit(self):
749 return self._exit
750
751 @exit.setter
752 def exit(self, enum):
753 self._exit = exit
754 self.run_time = int((time.time() - self.start_time) * 1000)
755 # The time could go backwards ...
756 if self.run_time < 0:
757 self.run_time = 0
758 if enum == pk_enums.EXIT_CANCELLED:
759 self.ErrorCode(pk_enums.ERROR_TRANSACTION_CANCELLED, "")
760 self.status = pk_enums.STATUS_FINISHED
761 self.Finished(enum, self.run_time)
762
763
764 # SIGNALS
765
766 # pylint: disable-msg=C0103,C0322
767 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
768 signature="ssbsusus")
769 def Transaction(self, old_tid, timespec, succeeded, role, duration, data,
770 uid, cmdline):
771 """This signal is sent when more details are required about a
772 specific transaction.
773
774 :param old_tid: The transaction ID of the old transaction.
775 :param timespec: The timespec of the old transaction in ISO8601 format.
776 :param succeeded: If the transaction succeeded.
777 :param role: The role enumerated type.
778 :param duration: The duration of the transaction in milliseconds.
779 :param data: Any data associated
780 :param uid: The user ID of the user that scheduled the action.
781 :param cmdline: The command line of the tool that scheduled the action,
782 e.g. /usr/bin/gpk-application.
783 """
784 pass
785
786 # pylint: disable-msg=C0103,C0322
787 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
788 signature="ss")
789 def ErrorCode(self, code, details):
790 """This signal is used to report errors back to the session program.
791 Errors should only be send on fatal abort.
792
793 :param code: Enumerated type, e.g. no-network.
794 :param details: Long description or error, e.g. "failed to connect"
795
796 :type code: s
797 :type details: s
798 """
799 pass
800
801 # pylint: disable-msg=C0103,C0322
802 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
803 signature="")
804 def Changed(self):
805 """This signal is emitted when a property on the interface changes."""
806 pklog.debug("Emitting PackageKitTransaction Changed()")
807
808 # pylint: disable-msg=C0103,C0322
809 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
810 signature="")
811 def Destroy(self):
812 """This signal is sent when the transaction has been destroyed
813 and is no longer available for use."""
814 pklog.debug("Emmitting Destroy()")
815
816 # pylint: disable-msg=C0103,C0322
817 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
818 signature="su")
819 def Finished(self, exit, runtime):
820 """This signal is used to signal that the transaction has finished.
821 :param exit: The PkExitEnum describing the exit status of the
822 transaction.
823 :param runtime: The amount of time in milliseconds that the
824 transaction ran for.
825
826 :type exit: s
827 :type runtime: u
828 """
829 pklog.debug("Emitting Finished: %s, %s", exit, runtime)
830 pass
831
832 # pylint: disable-msg=C0103,C0322
833 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
834 signature="ssssst")
835 def Details(self, package_id, license, group, detail, url, size):
836 """This signal allows the backend to convey more details about the
837 package.
838
839 :param package_id: The package ID
840
841 :param license:
842 The license string, e.g. GPLv2+ or BSD and (MPLv1.1 or GPLv2+).
843 Moredetails about the correct way to format licensing strings can
844 be found on the Fedora packaging wiki.
845 :param group:
846 The enumerated package group description
847 :param detail:
848 The multi-line package description. If formatting is required,
849 then markdown syntax should be used, e.g. This is **critically**
850 important
851 :param url:
852 The upstream project homepage
853 :param size:
854 The size of the package in bytes. This should be the size of the
855 entire package file, not the size of the files installed on the
856 system. If the package is not installed, and already downloaded
857 and present in the package manager cache, then this value should
858 be set to zero.
859 """
860 pklog.debug("Emmitting Details signal for %s", package_id)
861
862 # pylint: disable-msg=C0103,C0322
863 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
864 signature="ss")
865 def Files(self, package_id, file_list):
866 """This signal is used to push file lists from the backend to the
867 session.
868
869 :param package_id:
870 The Package ID that called the method.
871 :param file_list:
872 The file list, with each file seporated with ;.
873 """
874 pklog.debug("Emitting Files signal: %s, %s", package_id, file_list)
875
876 # pylint: disable-msg=C0103,C0322
877 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
878 signature="ssssssssssss")
879 def UpdateDetail(self, package_id, updates, obsoletes, vendor_url,
880 bugzilla_url, cve_url, restart, update_text, changelog,
881 state, issued, updated):
882 """This signal is sent when more details are required about a
883 specific update.
884
885 :param package_id: The package ID
886 :param updates:
887 A list of package_id's that are to be updated, seporated by
888 &. This odd delimited was chosen as \t is already being used
889 in the spawned backends, and & is a banned character in a
890 package_id.
891 :param obsoletes:
892 A list of package_id's that are to be obsoleted, separated by &
893 :param vendor_url:
894 A URL with more details on the update, e.g. a page with more
895 information on the update. The format of this command should
896 be http://www.foo.org/page.html?4567;Update to SELinux
897 :param bugzilla_url:
898 A bugzilla URL with more details on the update. If no URL is
899 available then this field should be left empty.
900 :param cve_url:
901 A CVE URL with more details on the security advisory.
902 :param restart:
903 A valid restart type, e.g. system.
904 :param update_text:
905 The update text describing the update. If formatting is required,
906 then markdown syntax should be used, e.g. This is **critically**
907 important.
908 :param changelog:
909 The ChangeLog text describing the changes since the last version.
910 :param state:
911 The state of the update, e.g. stable or testing.
912 :param issued:
913 The ISO8601 encoded date that the update was issued.
914 :param updated:
915 The ISO8601 encoded date that the update was updated.
916 """
917 pklog.debug("Emmitting UpdateDetail signal for %s", package_id)
918
919 # pylint: disable-msg=C0103,C0322
920 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
921 signature="sss")
922 def Package(self, info, package_id, summary):
923 """This signal allows the backend to communicate packages to the
924 session.
925
926 If updating, as packages are updated then emit them to the screen.
927 This allows a summary to be presented after the transaction.
928 When returning results from a search always return installed
929 before available for the same package name.
930
931 :param info: A valid info string enumerated type
932 :param package_id: This identifier is of the form
933 name;version;arch;data in a single string and is meant to
934 represent a single package unique across all local and remote
935 data stores. For a remote, not-installed package the data
936 field should be set as the repository identifier or repository
937 name. The data field for an installed package must be prefixed
938 with installed as this is used to identify which packages are
939 installable or installed in the client tools. As a special
940 extension, if the package manager is able to track which
941 repository a package was originally installed from, then the data
942 field can be set to installed:REPO-NAME which allows the frontend
943 client to advise the user of the package origin. The data field
944 for a non-installed local package must be local as this signifies
945 a repository name is not available and that package resides
946 locally on the client system rather than in any specific
947 repository.
948 :param summary: The one line package summary, e.g. Clipart for
949 OpenOffice
950 """
951 pklog.debug("Emmitting Package signal: info=%s id=%s summary='%s'",
952 info, package_id, summary[:10])
953
954 # pylint: disable-msg=C0103,C0322
955 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
956 signature="sss")
957 def DistroUpgrade(self, type, name, summary):
958 """This signal allows the backend to communicate distribution upgrades
959 to the session.
960 :param type: A valid upgrade string enumerated type, e.g. stable
961 or unstable
962 :param name: The short name of the distribution, e.g. Fedora Core
963 10 RC1
964 :param summary: The multi-line description of the release
965 """
966 pass
967
968 # pylint: disable-msg=C0103,C0322
969 @dbus.service.signal(dbus_interface=PACKAGEKIT_TRANS_DBUS_INTERFACE,
970 signature="ss")
971 def RequireRestart(self, restart_type, package_id):
972 """This signal is sent when the session client should notify the user
973 that a restart is required to get all changes into effect.
974
975 :param package_id:
976 The Package ID of the package tiggering the restart
977 :param file_list:
978 One of system, application or session
979 """
980 pklog.debug("Emitting RequireRestart signal: %s, %s",
981 restart_type, package_id)
982
983 # METHODS
984
985 # pylint: disable-msg=C0103,C0322
986 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
987 in_signature="as", out_signature="")
988 def SetHints(self, hints):
989 """This method allows the calling session to set transaction hints
990 for the package manager which can change as the transaction runs.
991
992 This method can be sent before the transaction has been run or
993 whilst it is running. There is no limit to the number of times
994 this method can be sent, although some backends may only use the
995 values that were set before the transaction was started.
996
997 Each parameter value is optional.
998
999 :param hints: The values as an array of strings, for example
1000 ['locale=en_GB.utf8','interactive=false','cache-age=3600']
1001 """
1002 for hint in hints:
1003 key, value = hint.split("=", 1)
1004 if key not in ["locale", "idle", "background", "interactive",
1005 "cache-age", "frontend-socket"]:
1006 raise Exception("Invalid option %s" % key)
1007 self.hints[key] = value
1008
1009 # pylint: disable-msg=C0103,C0322
1010 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1011 in_signature="", out_signature="",
1012 sender_keyword="sender")
1013 def Cancel(self, sender):
1014 """This method cancels a transaction that is already running."""
1015 if self.trans:
1016 return self.trans._cancel(sender)
1017
1018 # pylint: disable-msg=C0103,C0322
1019 @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
1020 in_signature="asbb", out_signature="",
1021 sender_keyword="sender")
1022 def RemovePackages(self, package_ids, allow_deps, autoremove, sender):
1023 """This method removes packages from the local system.
1024
1025 This method typically emits Progress, Status and Error and Package.
1026
1027 Package enumerated types should be downloading, updating, installing or removing.
1028
1029 :param package_ids: An array of package IDs.
1030 :param allow_deps:
1031 Either true or false. If true allow other packages to be removed
1032 with the package, but false should cause the script to abort if
1033 other packages are dependant on the package.
1034 :param autoremove:
1035 Either true or false. This option is only really interesting on
1036 embedded devices with a limited amount of flash storage. It
1037 suggests to the packagekit backend that dependencies installed at
1038 the same time as the package should also be removed if they are not
1039 required by anything else. For instance, if you install OpenOffice,
1040 it might download libneon as a dependency. When auto_remove is set
1041 to true, and you remove OpenOffice then libneon will also get
1042 removed automatically.
1043 """
1044 pklog.debug("RemovePackages() was called")
1045 self.role = pk_enums.ROLE_REMOVE_PACKAGES
1046 return self._remove_packages(package_ids, allow_deps, autoremove,
1047 sender)
1048
1049 @inline_callbacks
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches