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