Merge lp:~vorlon/ubuntu/quantal/aptdaemon/py3 into lp:ubuntu/quantal/aptdaemon

Proposed by Steve Langasek on 2012-06-13
Status: Merged
Merged at revision: 105
Proposed branch: lp:~vorlon/ubuntu/quantal/aptdaemon/py3
Merge into: lp:ubuntu/quantal/aptdaemon
Diff against target: 155465 lines (+83209/-31522)
152 files modified
.pc/.version (+1/-0)
.pc/applied-patches (+2/-0)
.pc/disable_simulate_test.patch/tests/test_simulate.py (+74/-0)
.pc/test-suite-fixes/aptdaemon/test.py (+296/-0)
.pc/test-suite-fixes/aptdaemon/worker.py (+1544/-0)
NEWS (+31/-2)
README.PackageKit (+4/-5)
README.tests (+3/-2)
aptd (+1/-1)
aptdaemon/client.py (+17/-13)
aptdaemon/config.py (+1/-1)
aptdaemon/console.py (+50/-45)
aptdaemon/core.py (+17/-17)
aptdaemon/errors.py (+14/-7)
aptdaemon/gtk3widgets.py (+3/-3)
aptdaemon/gtkwidgets.py (+2/-2)
aptdaemon/lock.py (+1/-1)
aptdaemon/networking.py (+3/-2)
aptdaemon/pkcompat.py (+105/-69)
aptdaemon/pkenums.py (+326/-0)
aptdaemon/policykit1.py (+2/-1)
aptdaemon/progress.py (+132/-79)
aptdaemon/test.py (+79/-20)
aptdaemon/utils.py (+3/-3)
aptdaemon/worker.py (+66/-65)
aptdcon (+1/-1)
debian/aptdaemon.install (+2/-2)
debian/changelog (+39/-0)
debian/control (+93/-49)
debian/patches/disable_simulate_test.patch (+12/-0)
debian/patches/series (+2/-0)
debian/patches/test-suite-fixes (+53/-0)
debian/python-aptdaemon.pkcompat.install (+2/-1)
debian/python-aptdaemon.test.install (+1/-1)
debian/python3-aptdaemon.gtk3widgets.examples (+1/-0)
debian/python3-aptdaemon.gtk3widgets.install (+1/-0)
debian/python3-aptdaemon.install (+16/-0)
debian/python3-aptdaemon.pkcompat.docs (+1/-0)
debian/python3-aptdaemon.pkcompat.install (+4/-0)
debian/python3-aptdaemon.test.examples (+1/-0)
debian/python3-aptdaemon.test.install (+18/-0)
debian/rules (+24/-4)
doc/source/aptdaemon.gtk3widgets.rst (+5/-0)
doc/source/aptdaemon.gtkwidgets.rst (+0/-5)
doc/source/index.rst (+1/-1)
gtk-demo.py (+1/-1)
gtk3-demo.py (+4/-7)
po/af.po (+785/-415)
po/am.po (+788/-375)
po/ar.po (+772/-322)
po/ast.po (+815/-452)
po/az.po (+1362/-0)
po/be.po (+1002/-574)
po/bg.po (+817/-433)
po/bn.po (+1001/-516)
po/br.po (+785/-415)
po/bs.po (+988/-482)
po/ca.po (+903/-477)
po/ca@valencia.po (+1450/-0)
po/crh.po (+774/-324)
po/cs.po (+927/-510)
po/cy.po (+1364/-0)
po/da.po (+812/-425)
po/de.po (+888/-495)
po/dv.po (+778/-337)
po/el.po (+825/-434)
po/en_AU.po (+957/-544)
po/en_CA.po (+842/-470)
po/en_GB.po (+867/-504)
po/eo.po (+909/-496)
po/es.po (+819/-457)
po/et.po (+885/-470)
po/eu.po (+885/-484)
po/fa.po (+772/-322)
po/fi.po (+825/-451)
po/fil.po (+1362/-0)
po/fo.po (+1362/-0)
po/fr.po (+856/-484)
po/gd.po (+1454/-0)
po/gl.po (+814/-450)
po/he.po (+800/-432)
po/hi.po (+908/-499)
po/hr.po (+772/-322)
po/hu.po (+809/-444)
po/hy.po (+1362/-0)
po/id.po (+849/-455)
po/is.po (+781/-336)
po/it.po (+833/-446)
po/ja.po (+824/-442)
po/kk.po (+805/-432)
po/km.po (+1434/-0)
po/kn.po (+774/-324)
po/ko.po (+917/-529)
po/ku.po (+774/-353)
po/ky.po (+1362/-0)
po/ln.po (+1362/-0)
po/lt.po (+913/-488)
po/lv.po (+954/-521)
po/ml.po (+809/-365)
po/ms.po (+902/-488)
po/my.po (+1362/-0)
po/nb.po (+804/-450)
po/nds.po (+777/-350)
po/ne.po (+773/-361)
po/nl.po (+825/-453)
po/nn.po (+893/-418)
po/oc.po (+898/-470)
po/pl.po (+836/-441)
po/pt.po (+969/-545)
po/pt_BR.po (+831/-466)
po/ro.po (+889/-490)
po/ru.po (+866/-494)
po/shn.po (+1362/-0)
po/si.po (+812/-353)
po/sk.po (+839/-440)
po/sl.po (+842/-478)
po/sq.po (+898/-476)
po/sr.po (+989/-559)
po/sv.po (+810/-445)
po/ta.po (+840/-390)
po/te.po (+1378/-0)
po/th.po (+893/-462)
po/tr.po (+817/-448)
po/ug.po (+832/-405)
po/uk.po (+911/-489)
po/ur.po (+1362/-0)
po/uz.po (+1362/-0)
po/vi.po (+975/-564)
po/zh_CN.po (+811/-442)
po/zh_HK.po (+793/-406)
po/zh_TW.po (+791/-425)
setup.py (+6/-1)
tests/_test_py2_string_handling.py (+94/-0)
tests/fakeroot-apt-key (+2/-0)
tests/repo/Packages (+147/-148)
tests/repo/Release (+16/-4)
tests/repo/Release.gpg (+8/-8)
tests/repo/glatzor.gpg (+107/-51)
tests/test_client.py (+31/-0)
tests/test_configparser.py (+5/-0)
tests/test_dbus_type.py (+6/-4)
tests/test_debconf.py (+31/-26)
tests/test_index.py (+2/-3)
tests/test_lock.py (+7/-8)
tests/test_lock_location.py (+6/-1)
tests/test_pk.py (+157/-26)
tests/test_progress.py (+5/-0)
tests/test_py2_string_handling.py (+38/-0)
tests/test_simulate.py (+1/-0)
tests/test_unicodedecoding.py (+0/-94)
tests/test_valid_package_names.py (+8/-3)
tests/test_worker.py (+44/-21)
To merge this branch: bzr merge lp:~vorlon/ubuntu/quantal/aptdaemon/py3
Reviewer Review Type Date Requested Status
Canonical Foundations Team 2012-06-13 Pending
Review via email: mp+109981@code.launchpad.net

Description of the Change

All ready for merge, passes the tests... feel free to upload if it checks
out in the morning and it's blocking anyone, otherwise I'll plan to upload
when I come online myself.

To post a comment you must log in.
105. By Steve Langasek on 2012-06-13

test/test_pk.py: increase the sleep on startup, to allow longer for
fake-polkitd to start up.

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/.version'
3--- .pc/.version 1970-01-01 00:00:00 +0000
4+++ .pc/.version 2012-06-13 16:29:18 +0000
5@@ -0,0 +1,1 @@
6+2
7
8=== added file '.pc/applied-patches'
9--- .pc/applied-patches 1970-01-01 00:00:00 +0000
10+++ .pc/applied-patches 2012-06-13 16:29:18 +0000
11@@ -0,0 +1,2 @@
12+disable_simulate_test.patch
13+test-suite-fixes
14
15=== added directory '.pc/disable_simulate_test.patch'
16=== added directory '.pc/disable_simulate_test.patch/tests'
17=== added file '.pc/disable_simulate_test.patch/tests/test_simulate.py'
18--- .pc/disable_simulate_test.patch/tests/test_simulate.py 1970-01-01 00:00:00 +0000
19+++ .pc/disable_simulate_test.patch/tests/test_simulate.py 2012-06-13 16:29:18 +0000
20@@ -0,0 +1,74 @@
21+#!/usr/bin/env python
22+# -*- coding: utf-8 -*-
23+"""Tests if the daemon forces a simualte during run."""
24+
25+import logging
26+import time
27+import unittest
28+
29+from gi.repository import GObject
30+import dbus
31+
32+import aptdaemon.client
33+import aptdaemon.loop
34+import aptdaemon.enums
35+
36+import aptdaemon.test
37+
38+DEBUG=True
39+
40+
41+class DaemonTest(aptdaemon.test.AptDaemonTestCase):
42+
43+ """Test the python client."""
44+
45+ def setUp(self):
46+ """Setup a chroot, run the aptdaemon and a fake PolicyKit daemon."""
47+ # Setup chroot
48+ self.chroot = aptdaemon.test.Chroot()
49+ self.chroot.setup()
50+ self.addCleanup(self.chroot.remove)
51+ # Start aptdaemon with the chroot on the session bus
52+ self.start_dbus_daemon()
53+ self.bus = dbus.bus.BusConnection(self.dbus_address)
54+ self.start_session_aptd(self.chroot.path)
55+ # Start the fake PolikcyKit daemon
56+ self.start_fake_polkitd()
57+ time.sleep(1)
58+
59+ def _on_finished(self, trans, exit):
60+ """Callback to stop the mainloop after a transaction is done."""
61+ aptdaemon.loop.mainloop.quit()
62+
63+ def test_detect_unauthenticated(self):
64+ """Test if the installation of an unauthenticated packages fails
65+ if simulate hasn't been called explicitly before.
66+ """
67+ self.chroot.add_test_repository(copy_sig=False)
68+ self.client = aptdaemon.client.AptClient(self.bus)
69+ trans = self.client.install_packages(["silly-base"])
70+ trans.connect("finished", self._on_finished)
71+ trans.run()
72+ aptdaemon.loop.mainloop.run()
73+ self.assertEqual(trans.exit, aptdaemon.enums.EXIT_FAILED)
74+ self.assertEqual(trans.error.code,
75+ aptdaemon.enums.ERROR_PACKAGE_UNAUTHENTICATED)
76+ self.assertEqual(trans.unauthenticated, ["silly-base"])
77+
78+ def test_environment(self):
79+ """Ensure that the test environment works."""
80+ self.chroot.add_test_repository()
81+ self.client = aptdaemon.client.AptClient(self.bus)
82+ trans = self.client.install_packages(["silly-base"])
83+ trans.connect("finished", self._on_finished)
84+ trans.run()
85+ aptdaemon.loop.mainloop.run()
86+ self.assertEqual(trans.exit, aptdaemon.enums.EXIT_SUCCESS)
87+
88+
89+if __name__ == "__main__":
90+ if DEBUG:
91+ logging.basicConfig(level=logging.DEBUG)
92+ unittest.main()
93+
94+# vim: ts=4 et sts=4
95
96=== added directory '.pc/test-suite-fixes'
97=== added directory '.pc/test-suite-fixes/aptdaemon'
98=== added file '.pc/test-suite-fixes/aptdaemon/test.py'
99--- .pc/test-suite-fixes/aptdaemon/test.py 1970-01-01 00:00:00 +0000
100+++ .pc/test-suite-fixes/aptdaemon/test.py 2012-06-13 16:29:18 +0000
101@@ -0,0 +1,296 @@
102+#!/usr/bin/env python
103+# -*- coding: utf-8 -*-
104+"""Small helpers for the test suite."""
105+# Copyright (C) 2011 Sebastian Heinlein <devel@glatzor.de>
106+#
107+# Licensed under the GNU General Public License Version 2
108+#
109+# This program is free software; you can redistribute it and/or modify
110+# it under the terms of the GNU General Public License as published by
111+# the Free Software Foundation; either version 2 of the License, or
112+# at your option) any later version.
113+#
114+# This program is distributed in the hope that it will be useful,
115+# but WITHOUT ANY WARRANTY; without even the implied warranty of
116+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
117+# GNU General Public License for more details.
118+#
119+# You should have received a copy of the GNU General Public License
120+# along with this program; if not, write to the Free Software
121+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
122+# Licensed under the GNU General Public License Version 2
123+
124+__author__ = "Sebastian Heinlein <devel@glatzor.de>"
125+__all__ = ("get_tests_dir", "Chroot", "AptDaemonTestCase")
126+
127+import inspect
128+import os
129+import shutil
130+import subprocess
131+import sys
132+import time
133+import tempfile
134+import unittest
135+
136+if sys.version_info.major > 2:
137+ from http.server import HTTPServer
138+ from http.server import SimpleHTTPRequestHandler as HTTPRequestHandler
139+else:
140+ from BaseHTTPServer import HTTPServer
141+ from SimpleHTTPServer import SimpleHTTPRequestHandler as HTTPRequestHandler
142+
143+import apt_pkg
144+import apt.auth
145+
146+PY3K = sys.version_info.major > 2
147+
148+
149+class Chroot(object):
150+
151+ """Provides a chroot which can be used by APT."""
152+
153+ def __init__(self, prefix="tmp"):
154+ self.path = tempfile.mkdtemp(prefix)
155+
156+ def setup(self):
157+ """Setup the chroot and modify the apt configuration."""
158+ for subdir in ["alternatives", "info", "parts", "updates", "triggers"]:
159+ path = os.path.join(self.path, "var", "lib", "dpkg", subdir)
160+ os.makedirs(path)
161+ for fname in ["status", "available"]:
162+ with open(os.path.join(self.path, "var", "lib", "dpkg", fname),
163+ "w"):
164+ pass
165+ os.makedirs(os.path.join(self.path, "var/cache/apt/archives/partial"))
166+ os.makedirs(os.path.join(self.path, "var/lib/apt/lists"))
167+ os.makedirs(os.path.join(self.path, "var/lib/apt/lists/partial"))
168+ os.makedirs(os.path.join(self.path, "etc/apt/apt.conf.d"))
169+ os.makedirs(os.path.join(self.path, "etc/apt/sources.list.d"))
170+ os.makedirs(os.path.join(self.path, "etc/apt/preferences.d"))
171+ os.makedirs(os.path.join(self.path, "var/log"))
172+ os.makedirs(os.path.join(self.path, "media"))
173+
174+ # Make apt use the new chroot
175+ dpkg_wrapper = os.path.join(get_tests_dir(), "dpkg-wrapper.sh")
176+ apt_key_wrapper = os.path.join(get_tests_dir(), "fakeroot-apt-key")
177+ config_path = os.path.join(self.path, "etc/apt/apt.conf.d/10chroot")
178+ with open(config_path, "w") as cnf:
179+ cnf.write("Dir::Bin::DPkg %s;" % dpkg_wrapper)
180+ cnf.write("Dir::Bin::Apt-Key %s;" % apt_key_wrapper)
181+ apt_pkg.read_config_file(apt_pkg.config, config_path)
182+ apt_pkg.init_system()
183+
184+ def remove(self):
185+ """Remove the files of the chroot."""
186+ apt_pkg.config.clear("Dir")
187+ apt_pkg.config.clear("Dir::State::Status")
188+ apt_pkg.init()
189+ shutil.rmtree(self.path)
190+
191+ def add_trusted_key(self):
192+ """Add glatzor's key to the trusted ones."""
193+ apt.auth.add_key_from_file(os.path.join(get_tests_dir(),
194+ "repo/glatzor.gpg"))
195+
196+ def install_debfile(self, path, force_depends=False):
197+ """Install a package file into the chroot."""
198+ cmd_list = ["fakeroot", "dpkg", "--root", self.path,
199+ "--log=%s/var/log/dpkg.log" % self.path]
200+ if force_depends:
201+ cmd_list.append("--force-depends")
202+ cmd_list.extend(["--install", path])
203+ cmd = subprocess.Popen(cmd_list,
204+ env={"PATH": "/sbin:/bin:/usr/bin:/usr/sbin"})
205+ cmd.communicate()
206+
207+ def add_test_repository(self, copy_list=True, copy_sig=True):
208+ """Add the test repository to the to the chroot."""
209+ return self.add_repository(os.path.join(get_tests_dir(), "repo"),
210+ copy_list, copy_sig)
211+
212+ def add_cdrom_repository(self):
213+ """Emulate a repository on removable device."""
214+ # Create the content of a fake cdrom
215+ media_path = os.path.join(self.path, "tmp/fake-cdrom")
216+ # The cdom gets identified by the info file
217+ os.makedirs(os.path.join(media_path, ".disk"))
218+ with open(os.path.join(media_path, ".disk/info"), "w") as info:
219+ info.write("This is a fake CDROM")
220+ # Copy the test repository "on" the cdrom
221+ shutil.copytree(os.path.join(get_tests_dir(), "repo"),
222+ os.path.join(media_path, "repo"))
223+
224+ # Call apt-cdrom add
225+ mount_point = self.mount_cdrom()
226+ os.system("apt-cdrom add -m -d %s "
227+ "-o 'Debug::Acquire::cdrom'=True "
228+ "-o 'Acquire::cdrom::AutoDetect'=False "
229+ "-o 'Dir'=%s" % (mount_point, self.path))
230+ self.unmount_cdrom()
231+
232+ config_path = os.path.join(self.path, "etc/apt/apt.conf.d/11cdrom")
233+ with open(config_path, "w") as cnf:
234+ cnf.write('Debug::Acquire::cdrom True;\n'
235+ 'Acquire::cdrom::AutoDetect False;\n'
236+ 'Acquire::cdrom::NoMount True;\n'
237+ 'Acquire::cdrom::mount "%s";' % mount_point)
238+
239+ def mount_cdrom(self):
240+ """Copy the repo information to the CDROM mount point."""
241+ mount_point = os.path.join(self.path, "media/cdrom")
242+ os.symlink(os.path.join(self.path, "tmp/fake-cdrom"), mount_point)
243+ return mount_point
244+
245+ def unmount_cdrom(self):
246+ """Remove all files from the mount point."""
247+ os.unlink(os.path.join(self.path, "media/cdrom"))
248+
249+ def add_repository(self, path, copy_list=True, copy_sig=True):
250+ """Add a sources.list entry to the chroot."""
251+ # Add a sources list
252+ lst_path = os.path.join(self.path, "etc/apt/sources.list")
253+ with open(lst_path, "w") as lst_file:
254+ lst_file.write("deb file://%s ./ # Test repository" % path)
255+ if copy_list:
256+ filename = apt_pkg.uri_to_filename("file://%s/." % path)
257+ shutil.copy(os.path.join(path, "Packages"),
258+ "%s/var/lib/apt/lists/%s_Packages" % (self.path,
259+ filename))
260+ if os.path.exists(os.path.join(path, "Release")):
261+ shutil.copy(os.path.join(path, "Release"),
262+ "%s/var/lib/apt/lists/%s_Release" % (self.path,
263+ filename))
264+ if copy_sig and os.path.exists(os.path.join(path, "Release.gpg")):
265+ shutil.copy(os.path.join(path, "Release.gpg"),
266+ "%s/var/lib/apt/lists/%s_Release.gpg" % (self.path,
267+ filename))
268+
269+
270+class AptDaemonTestCase(unittest.TestCase):
271+
272+ @classmethod
273+ def setupClass(cls):
274+ # Start with a clean APT configuration to remove changes
275+ # of previous tests
276+ for key in set([key.split("::")[0] for key in apt_pkg.config.keys()]):
277+ apt_pkg.config.clear(key)
278+ apt_pkg.init_config()
279+
280+ def start_fake_polkitd(self, options="all"):
281+ """Start a fake PolicyKit daemon.
282+
283+ :param allowed_actions: comma separated list of allowed actions.
284+ Defaults to all
285+ """
286+ try:
287+ env = os.environ.copy()
288+ env["DBUS_SYSTEM_BUS_ADDRESS"] = self.dbus_address
289+ except AttributeError:
290+ env=None
291+ dir = get_tests_dir()
292+ proc = subprocess.Popen([os.path.join(dir, "fake-polkitd.py"),
293+ "--allowed-actions", options],
294+ env=env)
295+ self.addCleanup(self._kill_process, proc)
296+ return proc
297+
298+ def start_session_aptd(self, chroot="/"):
299+ """Start an aptdaemon which listens on the session D-Bus.
300+
301+ :param chroot: path to the chroot
302+ """
303+ try:
304+ env = os.environ.copy()
305+ env["DBUS_SYSTEM_BUS_ADDRESS"] = self.dbus_address
306+ except AttributeError:
307+ env = None
308+ dir = get_tests_dir()
309+ if dir == "/usr/share/aptdaemon/tests":
310+ path = "/usr/sbin/aptd"
311+ else:
312+ path = os.path.join(dir, "../aptd")
313+ proc = subprocess.Popen(["python3", path, "--debug",
314+ "--disable-timeout", "--disable-plugins",
315+ "--chroot", chroot],
316+ env=env)
317+ self.addCleanup(self._kill_process, proc)
318+ return proc
319+
320+ def start_dbus_daemon(self):
321+ """Start a private D-Bus daemon and return its process and address."""
322+ proc, dbus_address = start_dbus_daemon()
323+ self.addCleanup(self._kill_process, proc)
324+ self.dbus_address = dbus_address
325+
326+ def start_keyserver(self, filename=None):
327+ """Start a fake keyserver on hkp://localhost:19191
328+
329+ Keyword arguments:
330+ filename -- Optional path to a GnuPG pulic key file which should
331+ be returned by lookups. By default the key of the test repo
332+ is used.
333+ """
334+ dir = tempfile.mkdtemp(prefix="keyserver-test-")
335+ self.addCleanup(shutil.rmtree, dir)
336+ os.mkdir(os.path.join(dir, "pks"))
337+ if filename is None:
338+ filename = os.path.join(get_tests_dir(), "repo/glatzor.gpg")
339+ shutil.copy(filename, os.path.join(dir, "pks", "lookup"))
340+
341+ pid = os.fork()
342+ if pid == 0:
343+ # quiesce server log
344+ os.dup2(os.open('/dev/null', os.O_WRONLY), sys.stderr.fileno())
345+ os.chdir(dir)
346+ httpd = HTTPServer(('localhost', 19191), HTTPRequestHandler)
347+ httpd.serve_forever()
348+ os._exit(0)
349+ else:
350+ self.addCleanup(self._kill_pid, pid)
351+
352+ # wait a bit until server is ready
353+ time.sleep(0.5)
354+
355+ def _kill_pid(self, pid):
356+ os.kill(pid, 15)
357+ os.wait()
358+
359+ def _kill_process(self, proc):
360+ proc.kill()
361+ proc.wait()
362+
363+
364+def get_tests_dir():
365+ """Return the absolute path to the tests directory."""
366+ # Try to detect a relative tests dir if we are running from the source
367+ # directory
368+ try:
369+ path = inspect.getsourcefile(sys.modules["aptdaemon.test"])
370+ except KeyError as error:
371+ path = inspect.getsourcefile(inspect.currentframe())
372+ path = os.path.realpath(path)
373+ relative_path = os.path.join(os.path.dirname(path), "../tests")
374+ if os.path.exists(os.path.join(relative_path, "repo/Packages")):
375+ return os.path.normpath(relative_path)
376+ # Fallback to an absolute path
377+ elif os.path.exists("/usr/share/aptdaemon/tests/repo/Packages"):
378+ return "/usr/share/aptdaemon/tests"
379+ else:
380+ raise Exception("Could not find tests direcotry")
381+
382+def start_dbus_daemon():
383+ """Start a private D-Bus daemon and return its process and address."""
384+ config_path = os.path.join(get_tests_dir(), "dbus.conf")
385+ proc = subprocess.Popen(["dbus-daemon", "--nofork",
386+ "--print-address", "--config-file",
387+ config_path],
388+ stdout=subprocess.PIPE)
389+ output = proc.stdout.readline().strip()
390+ if PY3K:
391+ dbus_address = output.decode()
392+ else:
393+ dbus_address = output
394+ return proc, dbus_address
395+
396+
397+# vim: ts=4 et sts=4
398
399=== added file '.pc/test-suite-fixes/aptdaemon/worker.py'
400--- .pc/test-suite-fixes/aptdaemon/worker.py 1970-01-01 00:00:00 +0000
401+++ .pc/test-suite-fixes/aptdaemon/worker.py 2012-06-13 16:29:18 +0000
402@@ -0,0 +1,1544 @@
403+#!/usr/bin/env python
404+# -*- coding: utf-8 -*-
405+"""Provides AptWorker which processes transactions."""
406+# Copyright (C) 2008-2009 Sebastian Heinlein <devel@glatzor.de>
407+#
408+# This program is free software; you can redistribute it and/or modify
409+# it under the terms of the GNU General Public License as published by
410+# the Free Software Foundation; either version 2 of the License, or
411+# any later version.
412+#
413+# This program is distributed in the hope that it will be useful,
414+# but WITHOUT ANY WARRANTY; without even the implied warranty of
415+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
416+# GNU General Public License for more details.
417+#
418+# You should have received a copy of the GNU General Public License along
419+# with this program; if not, write to the Free Software Foundation, Inc.,
420+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
421+
422+__author__ = "Sebastian Heinlein <devel@glatzor.de>"
423+
424+__all__ = ("AptWorker", "DummyWorker")
425+
426+import contextlib
427+import logging
428+import os
429+import platform
430+import re
431+import shutil
432+import sys
433+import tempfile
434+import time
435+import traceback
436+from urllib.parse import urlsplit, urlunsplit
437+
438+import apt
439+import apt.auth
440+import apt.cache
441+import apt.debfile
442+import apt_pkg
443+import aptsources
444+import aptsources.distro
445+from aptsources.sourceslist import SourcesList
446+from gi.repository import GObject
447+import pkg_resources
448+import subprocess
449+
450+from .enums import *
451+from .errors import *
452+from . import lock
453+from .loop import mainloop
454+from .progress import DaemonOpenProgress, \
455+ DaemonInstallProgress, \
456+ DaemonAcquireProgress, \
457+ DaemonAcquireRepoProgress, \
458+ DaemonDpkgInstallProgress, \
459+ DaemonDpkgReconfigureProgress, \
460+ DaemonDpkgRecoverProgress, \
461+ DaemonForkProgress
462+
463+log = logging.getLogger("AptDaemon.Worker")
464+
465+# Just required to detect translatable strings. The translation is done by
466+# core.Transaction.gettext
467+_ = lambda s: s
468+
469+
470+class AptWorker(GObject.GObject):
471+
472+ """Worker which processes transactions from the queue."""
473+
474+ __gsignals__ = {"transaction-done":(GObject.SignalFlags.RUN_FIRST,
475+ None,
476+ (GObject.TYPE_PYOBJECT,)),
477+ "transaction-simulated":(GObject.SignalFlags.RUN_FIRST,
478+ None,
479+ (GObject.TYPE_PYOBJECT,))}
480+
481+ # the basedir under which license keys can be stored
482+ LICENSE_KEY_ROOTDIR = "/opt/"
483+
484+ def __init__(self, chroot=None, load_plugins=True):
485+ """Initialize a new AptWorker instance."""
486+ GObject.GObject.__init__(self)
487+ self.trans = None
488+ self.last_action_timestamp = time.time()
489+ self._cache = None
490+ # Store the the tid of the transaction whose changes are currently
491+ # marked in the cache
492+ self.marked_tid = None
493+
494+ # Change to a given chroot
495+ if chroot:
496+ apt_conf_file = os.path.join(chroot, "etc/apt/apt.conf")
497+ if os.path.exists(apt_conf_file):
498+ apt_pkg.read_config_file(apt_pkg.config, apt_conf_file)
499+ apt_conf_dir = os.path.join(chroot, "etc/apt/apt.conf.d")
500+ if os.path.isdir(apt_conf_dir):
501+ apt_pkg.read_config_dir(apt_pkg.config, apt_conf_dir)
502+ apt_pkg.config["Dir"] = chroot
503+ apt_pkg.config["Dir::State::Status"] = os.path.join(chroot,
504+ "var/lib/dpkg/status")
505+ apt_pkg.config.clear("DPkg::Post-Invoke")
506+ apt_pkg.config.clear("DPkg::Options")
507+ apt_pkg.config["DPkg::Options::"] = "--root=%s" % chroot
508+ apt_pkg.config["DPkg::Options::"] = "--log=%s/var/log/dpkg.log" % \
509+ chroot
510+ status_file = apt_pkg.config.find_file("Dir::State::status")
511+ lock.status_lock.path = os.path.join(os.path.dirname(status_file),
512+ "lock")
513+ archives_dir = apt_pkg.config.find_dir("Dir::Cache::Archives")
514+ lock.archive_lock.path = os.path.join(archives_dir, "lock")
515+ lists_dir = apt_pkg.config.find_dir("Dir::State::lists")
516+ lock.lists_lock.path = os.path.join(lists_dir, "lock")
517+ apt_pkg.init_system()
518+
519+ self._status_orig = apt_pkg.config.find_file("Dir::State::status")
520+ self._status_frozen = None
521+ self.plugins = {}
522+ if load_plugins:
523+ self._load_plugins()
524+
525+ def _load_plugins(self):
526+ """Load the plugins from setuptools' entry points."""
527+ plugin_dirs = [os.path.join(os.path.dirname(__file__), "plugins")]
528+ env = pkg_resources.Environment(plugin_dirs)
529+ dists, errors = pkg_resources.working_set.find_plugins(env)
530+ for dist in dists:
531+ pkg_resources.working_set.add(dist)
532+ for name in ["modify_cache_after", "modify_cache_before",
533+ "get_license_key"]:
534+ for ept in pkg_resources.iter_entry_points("aptdaemon.plugins",
535+ name):
536+ try:
537+ self.plugins.setdefault(name, []).append(ept.load())
538+ except:
539+ log.critical("Failed to load %s plugin: "
540+ "%s" % (name, ept.dist))
541+ else:
542+ log.debug("Loaded %s plugin: %s", name, ept.dist)
543+
544+ def _call_plugins(self, name, resolver=None):
545+ """Call all plugins of a given type."""
546+ if not resolver:
547+ # If the resolver of the original task isn't available we create
548+ # a new one and protect the already marked changes
549+ resolver = apt.cache.ProblemResolver(self._cache)
550+ for pkg in self._cache.get_changes():
551+ resolver.clear(pkg)
552+ resolver.protect(pkg)
553+ if pkg.marked_delete:
554+ resolver.remove(pkg)
555+ if not name in self.plugins:
556+ log.debug("There isn't any registered %s plugin" % name)
557+ return False
558+ for plugin in self.plugins[name]:
559+ log.debug("Calling %s plugin: %s", name, plugin)
560+ try:
561+ plugin(resolver, self._cache)
562+ except Exception as error:
563+ log.critical("Failed to call %s plugin:\n%s" % (plugin, error))
564+ return True
565+
566+ def run(self, transaction):
567+ """Process the given transaction in the background.
568+
569+ Keyword argument:
570+ transaction -- core.Transcation instance to run
571+ """
572+ log.info("Processing transaction %s", transaction.tid)
573+ if self.trans:
574+ raise Exception("There is already a running transaction")
575+ self.trans = transaction
576+ GObject.idle_add(self._process_transaction, transaction)
577+
578+ def _emit_transaction_simulated(self, trans):
579+ """Emit the transaction-simulated signal.
580+
581+ Keyword argument:
582+ trans -- the simulated transaction
583+ """
584+ log.debug("Emitting transaction-simulated: %s", trans.tid)
585+ self.emit("transaction-simulated", trans)
586+
587+ def _emit_transaction_done(self, trans):
588+ """Emit the transaction-done signal.
589+
590+ Keyword argument:
591+ trans -- the finished transaction
592+ """
593+ log.debug("Emitting transaction-done: %s", trans.tid)
594+ self.emit("transaction-done", trans)
595+
596+ def _process_transaction(self, trans):
597+ """Run the worker"""
598+ self.last_action_timestamp = time.time()
599+ trans.status = STATUS_RUNNING
600+ trans.progress = 11
601+ try:
602+ lock.wait_for_lock(trans)
603+ # Prepare the package cache
604+ if trans.role == ROLE_FIX_INCOMPLETE_INSTALL or \
605+ not self.is_dpkg_journal_clean():
606+ self.fix_incomplete_install(trans)
607+ # Process transaction which don't require a cache
608+ if trans.role == ROLE_ADD_VENDOR_KEY_FILE:
609+ self.add_vendor_key_from_file(trans, **trans.kwargs)
610+ elif trans.role == ROLE_ADD_VENDOR_KEY_FROM_KEYSERVER:
611+ self.add_vendor_key_from_keyserver(trans, **trans.kwargs)
612+ elif trans.role == ROLE_REMOVE_VENDOR_KEY:
613+ self.remove_vendor_key(trans, **trans.kwargs)
614+ elif trans.role == ROLE_ADD_REPOSITORY:
615+ self.add_repository(trans, **trans.kwargs)
616+ elif trans.role == ROLE_ENABLE_DISTRO_COMP:
617+ self.enable_distro_comp(trans, **trans.kwargs)
618+ elif trans.role == ROLE_RECONFIGURE:
619+ self.reconfigure(trans, trans.packages[PKGS_REINSTALL],
620+ **trans.kwargs)
621+ elif trans.role == ROLE_CLEAN:
622+ self.clean(trans)
623+ # Check if the transaction has been just simulated. So we could
624+ # skip marking the changes a second time.
625+ elif trans.role in (ROLE_REMOVE_PACKAGES, ROLE_INSTALL_PACKAGES,
626+ ROLE_UPGRADE_PACKAGES, ROLE_COMMIT_PACKAGES,
627+ ROLE_UPGRADE_SYSTEM,
628+ ROLE_FIX_BROKEN_DEPENDS) and \
629+ self.marked_tid == trans.tid:
630+ self._apply_changes(trans)
631+ trans.exit = EXIT_SUCCESS
632+ return False
633+ else:
634+ self._open_cache(trans)
635+ # Process transaction which can handle a broken dep cache
636+ if trans.role == ROLE_FIX_BROKEN_DEPENDS:
637+ self.fix_broken_depends(trans)
638+ elif trans.role == ROLE_UPDATE_CACHE:
639+ self.update_cache(trans, **trans.kwargs)
640+ # Process the transactions which require a consistent cache
641+ elif trans.role == ROLE_ADD_LICENSE_KEY:
642+ self.add_license_key(trans, **trans.kwargs)
643+ elif self._cache and self._cache.broken_count:
644+ broken = [pkg.name for pkg in self._cache if pkg.is_now_broken]
645+ raise TransactionFailed(ERROR_CACHE_BROKEN,
646+ self._get_broken_details(trans))
647+ if trans.role == ROLE_PK_QUERY:
648+ self.query(trans)
649+ elif trans.role == ROLE_INSTALL_FILE:
650+ self.install_file(trans, **trans.kwargs)
651+ elif trans.role in [ROLE_REMOVE_PACKAGES, ROLE_INSTALL_PACKAGES,
652+ ROLE_UPGRADE_PACKAGES, ROLE_COMMIT_PACKAGES]:
653+ self.commit_packages(trans, *trans.packages)
654+ elif trans.role == ROLE_UPGRADE_SYSTEM:
655+ self.upgrade_system(trans, **trans.kwargs)
656+ except TransactionCancelled:
657+ trans.exit = EXIT_CANCELLED
658+ except TransactionFailed as excep:
659+ trans.error = excep
660+ trans.exit = EXIT_FAILED
661+ except (KeyboardInterrupt, SystemExit):
662+ trans.exit = EXIT_CANCELLED
663+ except Exception as excep:
664+ tbk = traceback.format_exc()
665+ trans.error = TransactionFailed(ERROR_UNKNOWN, tbk)
666+ trans.exit = EXIT_FAILED
667+ try:
668+ from . import crash
669+ except ImportError:
670+ pass
671+ else:
672+ crash.create_report("%s: %s" % (type(excep), str(excep)),
673+ tbk, trans)
674+ else:
675+ trans.exit = EXIT_SUCCESS
676+ finally:
677+ trans.progress = 100
678+ self.last_action_timestamp = time.time()
679+ tid = trans.tid[:]
680+ self.trans = None
681+ self.marked_tid = None
682+ self._emit_transaction_done(trans)
683+ lock.release()
684+ log.info("Finished transaction %s", tid)
685+ return False
686+
687+ def commit_packages(self, trans, install, reinstall, remove, purge, upgrade,
688+ downgrade, simulate=False):
689+ """Perform a complex package operation.
690+
691+ Keyword arguments:
692+ trans - the transaction
693+ install - list of package names to install
694+ reinstall - list of package names to reinstall
695+ remove - list of package names to remove
696+ purge - list of package names to purge including configuration files
697+ upgrade - list of package names to upgrade
698+ downgrade - list of package names to upgrade
699+ simulate -- if True the changes won't be applied
700+ """
701+ log.info("Committing packages: %s, %s, %s, %s, %s, %s",
702+ install, reinstall, remove, purge, upgrade, downgrade)
703+ with self._cache.actiongroup():
704+ resolver = apt.cache.ProblemResolver(self._cache)
705+ self._mark_packages_for_installation(install, resolver)
706+ self._mark_packages_for_installation(reinstall, resolver,
707+ reinstall=True)
708+ self._mark_packages_for_removal(remove, resolver)
709+ self._mark_packages_for_removal(purge, resolver, purge=True)
710+ self._mark_packages_for_upgrade(upgrade, resolver)
711+ self._mark_packages_for_downgrade(downgrade, resolver)
712+ self._resolve_depends(trans, resolver)
713+ self._check_obsoleted_dependencies(trans, resolver)
714+ if not simulate:
715+ self._apply_changes(trans)
716+
717+ def _resolve_depends(self, trans, resolver):
718+ """Resolve the dependencies using the given ProblemResolver."""
719+ self._call_plugins("modify_cache_before", resolver)
720+ resolver.install_protect()
721+ try:
722+ resolver.resolve()
723+ except SystemError:
724+ raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED,
725+ self._get_broken_details(trans, now=False))
726+ if self._call_plugins("modify_cache_after", resolver):
727+ try:
728+ resolver.resolve()
729+ except SystemError:
730+ details = self._get_broken_details(trans, now=False)
731+ raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED, details)
732+
733+ @staticmethod
734+ def _split_package_id(package):
735+ """Return the name, the version number and the release of the
736+ specified package."""
737+ if "=" in package:
738+ name, version = package.split("=", 1)
739+ release = None
740+ elif "/" in package:
741+ name, release = package.split("/", 1)
742+ version = None
743+ else:
744+ name = package
745+ version = release = None
746+ return name, version, release
747+
748+ def _get_unauthenticated(self):
749+ """Return a list of unauthenticated package names """
750+ unauthenticated = []
751+ for pkg in self._iterate_packages():
752+ if (pkg.marked_install or
753+ pkg.marked_downgrade or
754+ pkg.marked_upgrade or
755+ pkg.marked_reinstall):
756+ trusted = False
757+ for origin in pkg.candidate.origins:
758+ trusted |= origin.trusted
759+ if not trusted:
760+ unauthenticated.append(pkg.name)
761+ return unauthenticated
762+
763+ def _mark_packages_for_installation(self, packages, resolver,
764+ reinstall=False):
765+ """Mark packages for installation."""
766+ for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
767+ for pkg in packages]:
768+ try:
769+ pkg = self._cache[pkg_name]
770+ except KeyError:
771+ raise TransactionFailed(ERROR_NO_PACKAGE,
772+ _("Package %s isn't available"),
773+ pkg_name)
774+ if reinstall:
775+ if not pkg.is_installed:
776+ raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
777+ _("Package %s isn't installed"),
778+ pkg.name)
779+ if pkg_ver and pkg.installed.version != pkg_ver:
780+ raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
781+ _("The version %s of %s isn't "
782+ "installed"),
783+ pkg_ver, pkg_name)
784+ else:
785+ # Fail if the user requests to install the same version
786+ # of an already installed package.
787+ if (pkg.is_installed and
788+ # Compare version numbers
789+ pkg_ver and pkg_ver == pkg.installed.version and
790+ # Optionally compare the origin if specified
791+ (not pkg_rel or
792+ pkg_rel in [origin.archive for
793+ origin in pkg.installed.origins])):
794+ raise TransactionFailed(ERROR_PACKAGE_ALREADY_INSTALLED,
795+ _("Package %s is already "
796+ "installed"), pkg_name)
797+ pkg.mark_install(False, True, True)
798+ resolver.clear(pkg)
799+ resolver.protect(pkg)
800+ if pkg_ver:
801+ try:
802+ pkg.candidate = pkg.versions[pkg_ver]
803+ except KeyError:
804+ raise TransactionFailed(ERROR_NO_PACKAGE,
805+ _("The version %s of %s isn't "
806+ "available."), pkg_ver, pkg_name)
807+ elif pkg_rel:
808+ self._set_candidate_release(pkg, pkg_rel)
809+
810+
811+ def enable_distro_comp(self, trans, component):
812+ """Enable given component in the sources list.
813+
814+ Keyword arguments:
815+ trans -- the corresponding transaction
816+ component -- a component, e.g. main or universe
817+ """
818+ trans.progress = 101
819+ trans.status = STATUS_COMMITTING
820+ old_umask = os.umask(0o022)
821+ try:
822+ sourceslist = SourcesList()
823+ distro = aptsources.distro.get_distro()
824+ distro.get_sources(sourceslist)
825+ distro.enable_component(component)
826+ sourceslist.save()
827+ finally:
828+ os.umask(old_umask)
829+
830+ def add_repository(self, trans, src_type, uri, dist, comps, comment, sourcesfile):
831+ """Add given repository to the sources list.
832+
833+ Keyword arguments:
834+ trans -- the corresponding transaction
835+ src_type -- the type of the entry (deb, deb-src)
836+ uri -- the main repository uri (e.g. http://archive.ubuntu.com/ubuntu)
837+ dist -- the distribution to use (e.g. karmic, "/")
838+ comps -- a (possible empty) list of components (main, restricted)
839+ comment -- an (optional) comment
840+ sourcesfile -- an (optinal) filename in sources.list.d
841+ """
842+ trans.progress = 101
843+ trans.status = STATUS_COMMITTING
844+
845+ if sourcesfile:
846+ if not sourcesfile.endswith(".list"):
847+ sourcesfile += ".list"
848+ dir = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
849+ sourcesfile = os.path.join(dir, os.path.basename(sourcesfile))
850+ else:
851+ sourcesfile = None
852+ # Store any private login information in a separate auth.conf file
853+ if re.match("(http|https|ftp)://\S+?:\S+?@\S+", uri):
854+ uri = self._store_and_strip_password_from_uri(uri)
855+ auth_conf_path = apt_pkg.config.find_file("Dir::etc::netrc")
856+ if not comment:
857+ comment = "credentials stored in %s" % auth_conf_path
858+ else:
859+ comment += "; credentials stored in %s" % auth_conf_path
860+ try:
861+ sources = SourcesList()
862+ entry = sources.add(src_type, uri, dist, comps, comment,
863+ file=sourcesfile)
864+ if entry.invalid:
865+ #FIXME: Introduce new error codes
866+ raise RepositoryInvalidError()
867+ except:
868+ log.exception("adding repository")
869+ raise
870+ else:
871+ sources.save()
872+
873+ def _store_and_strip_password_from_uri(self, uri):
874+ """Extract the credentials from an URI. Store the password in
875+ auth.conf and return the URI without any password information.
876+ """
877+ try:
878+ res = urlsplit(uri)
879+ except ValueError as error:
880+ log.warn("Failed to urlsplit '%s'", error)
881+ return uri
882+ netloc_public = res.netloc.replace("%s:%s@" % (res.username,
883+ res.password),
884+ "")
885+
886+ # write auth.conf
887+ auth_conf_path = apt_pkg.config.find_file("Dir::etc::netrc")
888+ old_umask = os.umask(0o027)
889+ try:
890+ with open(auth_conf_path, "a") as auth_conf:
891+ auth_conf.write("""machine %s
892+login %s
893+password %s\n\n""" % (netloc_public + res.path, res.username, res.password))
894+ except OSError as error:
895+ log.warn("Failed to write auth.conf: '%s'" % error)
896+ finally:
897+ os.umask(old_umask)
898+
899+ # Return URI without user/pass
900+ return urlunsplit((res.scheme, netloc_public, res.path, res.query,
901+ res.fragment))
902+
903+ def add_vendor_key_from_keyserver(self, trans, keyid, keyserver):
904+ """Add the signing key from the given (keyid, keyserver) to the
905+ trusted vendors.
906+
907+ Keyword argument:
908+ trans -- the corresponding transaction
909+ keyid - the keyid of the key (e.g. 0x0EB12F05)
910+ keyserver - the keyserver (e.g. keyserver.ubuntu.com)
911+ """
912+ log.info("Adding vendor key from keyserver: %s %s", keyid, keyserver)
913+ # Perform some sanity checks
914+ try:
915+ res = urlsplit(keyserver)
916+ except ValueError:
917+ raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
918+ #TRANSLATORS: %s is the URL of GnuPG
919+ # keyserver
920+ _("The keyserver URL is invalid: %s"),
921+ keyserver)
922+ if res.scheme not in ["hkp", "ldap", "ldaps", "http", "https"]:
923+ raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
924+ #TRANSLATORS: %s is the URL of GnuPG
925+ # keyserver
926+ _("Invalid protocol of the server: %s"),
927+ keyserver)
928+ try:
929+ int(keyid, 16)
930+ except ValueError:
931+ raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
932+ #TRANSLATORS: %s is the id of a GnuPG key
933+ # e.g. E08ADE95
934+ _("Invalid key id: %s"), keyid)
935+ trans.status = STATUS_DOWNLOADING
936+ trans.progress = 101
937+ last_pulse = time.time()
938+ with DaemonForkProgress(trans) as progress:
939+ progress.run(apt.auth.add_key_from_keyserver, keyid, keyserver)
940+ if progress._child_exit != 0:
941+ #TRANSLATORS: The first %s is the key id and the second the server
942+ raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
943+ _("Failed to download and install the key "
944+ "%s from %s:\n%s"),
945+ keyid, keyserver, progress.output)
946+
947+ def add_vendor_key_from_file(self, trans, path):
948+ """Add the signing key from the given file to the trusted vendors.
949+
950+ Keyword argument:
951+ path -- absolute path to the key file
952+ """
953+ log.info("Adding vendor key from file: %s", path)
954+ trans.progress = 101
955+ trans.status = STATUS_COMMITTING
956+ with DaemonForkProgress(trans) as progress:
957+ progress.run(apt.auth.add_key_from_file, path)
958+ if progress._child_exit != 0:
959+ raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
960+ _("Key file %s couldn't be installed: %s"),
961+ path, progress.output)
962+
963+ def remove_vendor_key(self, trans, fingerprint):
964+ """Remove repository key.
965+
966+ Keyword argument:
967+ trans -- the corresponding transaction
968+ fingerprint -- fingerprint of the key to remove
969+ """
970+ log.info("Removing vendor key: %s", fingerprint)
971+ trans.progress = 101
972+ trans.status = STATUS_COMMITTING
973+ try:
974+ int(fingerprint, 16)
975+ except ValueError:
976+ raise TransactionFailed(ERROR_KEY_NOT_REMOVED,
977+ #TRANSLATORS: %s is the id of a GnuPG key
978+ # e.g. E08ADE95
979+ _("Invalid key id: %s"), fingerprint)
980+ with DaemonForkProgress(trans) as progress:
981+ progress.run(apt.auth.remove_key, fingerprint)
982+ if progress._child_exit != 0:
983+ raise TransactionFailed(ERROR_KEY_NOT_REMOVED,
984+ _("Key with fingerprint %s couldn't be "
985+ "removed: %s"), fingerprint,
986+ progress.output)
987+
988+ def install_file(self, trans, path, force, simulate=False):
989+ """Install local package file.
990+
991+ Keyword argument:
992+ trans -- the corresponding transaction
993+ path -- absolute path to the package file
994+ force -- if installing an invalid package is allowed
995+ simulate -- if True the changes won't be committed but the debfile
996+ instance will be returned
997+ """
998+ log.info("Installing local package file: %s", path)
999+ # Check if the dpkg can be installed at all
1000+ trans.status = STATUS_RESOLVING_DEP
1001+ deb = self._check_deb_file(path, force, trans.uid)
1002+ # Check for required changes and apply them before
1003+ (install, remove, unauth) = deb.required_changes
1004+ self._call_plugins("modify_cache_after")
1005+ if simulate:
1006+ return deb
1007+ with self._frozen_status():
1008+ if len(install) > 0 or len(remove) > 0:
1009+ dpkg_range = (64, 99)
1010+ self._apply_changes(trans, fetch_range=(15, 33),
1011+ install_range=(34, 63))
1012+ # Install the dpkg file
1013+ deb_progress = DaemonDpkgInstallProgress(trans, begin=64, end=95)
1014+ res = deb.install(deb_progress)
1015+ encoding = sys.getfilesystemencoding()
1016+ trans.output += deb_progress.output
1017+ if res:
1018+ raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
1019+ trans.output)
1020+
1021+ def _mark_packages_for_removal(self, packages, resolver, purge=False):
1022+ """Mark packages for installation."""
1023+ for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
1024+ for pkg in packages]:
1025+ try:
1026+ pkg = self._cache[pkg_name]
1027+ except KeyError:
1028+ raise TransactionFailed(ERROR_NO_PACKAGE,
1029+ _("Package %s isn't available"),
1030+ pkg_name)
1031+ if not pkg.is_installed and not pkg.installed_files:
1032+ raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
1033+ _("Package %s isn't installed"),
1034+ pkg_name)
1035+ if pkg.essential == True:
1036+ raise TransactionFailed(ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE,
1037+ _("Package %s cannot be removed."),
1038+ pkg_name)
1039+ if pkg_ver and pkg.installed != pkg_ver:
1040+ raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
1041+ _("The version %s of %s is not "
1042+ "installed"), pkg_ver, pkg_name)
1043+ pkg.mark_delete(False, purge)
1044+ resolver.clear(pkg)
1045+ resolver.protect(pkg)
1046+ resolver.remove(pkg)
1047+
1048+ def _check_obsoleted_dependencies(self, trans, resolver=None):
1049+ """Mark obsoleted dependencies of to be removed packages for removal."""
1050+ if not trans.remove_obsoleted_depends:
1051+ return
1052+ if not resolver:
1053+ resolver = apt.cache.ProblemResolver(self._cache)
1054+ installed_deps = set()
1055+ with self._cache.actiongroup():
1056+ for pkg in self._iterate_packages():
1057+ if pkg.marked_delete:
1058+ installed_deps = self._installed_dependencies(pkg.name,
1059+ installed_deps)
1060+ for dep_name in installed_deps:
1061+ if dep_name in self._cache:
1062+ pkg = self._cache[dep_name]
1063+ if pkg.is_installed and pkg.is_auto_removable:
1064+ pkg.mark_delete(False)
1065+ # do an additional resolver run to ensure that the autoremove
1066+ # never leaves the cache in an inconsistent state, see bug
1067+ # LP: #659111 for the rational, essentially this may happen
1068+ # if a package is marked install during problem resolving but
1069+ # is later no longer required. the resolver deals with that
1070+ self._resolve_depends(trans, resolver)
1071+
1072+ def _installed_dependencies(self, pkg_name, all_deps=None):
1073+ """Recursively return all installed dependencies of a given package."""
1074+ #FIXME: Should be part of python-apt, since it makes use of non-public
1075+ # API. Perhaps by adding a recursive argument to
1076+ # apt.package.Version.get_dependencies()
1077+ if not all_deps:
1078+ all_deps = set()
1079+ if not pkg_name in self._cache:
1080+ return all_deps
1081+ cur = self._cache[pkg_name]._pkg.current_ver
1082+ if not cur:
1083+ return all_deps
1084+ for sec in ("PreDepends", "Depends", "Recommends"):
1085+ try:
1086+ for dep in cur.depends_list[sec]:
1087+ dep_name = dep[0].target_pkg.name
1088+ if not dep_name in all_deps:
1089+ all_deps.add(dep_name)
1090+ all_deps |= self._installed_dependencies(dep_name,
1091+ all_deps)
1092+ except KeyError:
1093+ pass
1094+ return all_deps
1095+
1096+ def _mark_packages_for_downgrade(self, packages, resolver):
1097+ """Mark packages for downgrade."""
1098+ for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
1099+ for pkg in packages]:
1100+ try:
1101+ pkg = self._cache[pkg_name]
1102+ except KeyError:
1103+ raise TransactionFailed(ERROR_NO_PACKAGE,
1104+ _("Package %s isn't available"),
1105+ pkg_name)
1106+ if not pkg.is_installed:
1107+ raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
1108+ _("Package %s isn't installed"),
1109+ pkg_name)
1110+ pkg.mark_install(False, True, pkg.is_auto_installed)
1111+ resolver.clear(pkg)
1112+ resolver.protect(pkg)
1113+ if pkg_ver:
1114+ if pkg.installed and pkg.installed.version < pkg_ver:
1115+ #FIXME: We need a new error enum
1116+ raise TransactionFailed(ERROR_NO_PACKAGE,
1117+ _("The former version %s of %s " \
1118+ "is already installed"),
1119+ pkg.installed.version, pkg.name)
1120+ elif pkg.installed and pkg.installed.version == pkg_ver:
1121+ raise TransactionFailed(ERROR_PACKAGE_ALREADY_INSTALLED,
1122+ _("The version %s of %s "
1123+ "is already installed"),
1124+ pkg.installed.version, pkg.name)
1125+ try:
1126+ pkg.candidate = pkg.versions[pkg_ver]
1127+ except KeyError:
1128+ raise TransactionFailed(ERROR_NO_PACKAGE,
1129+ _("The version %s of %s isn't "
1130+ "available"), pkg_ver, pkg_name)
1131+ else:
1132+ raise TransactionFailed(ERROR_NO_PACKAGE,
1133+ _("You need to specify a version to " \
1134+ "downgrade %s to"), pkg_name)
1135+
1136+
1137+ def _mark_packages_for_upgrade(self, packages, resolver):
1138+ """Mark packages for upgrade."""
1139+ for pkg_name, pkg_ver, pkg_rel in [self._split_package_id(pkg)
1140+ for pkg in packages]:
1141+ try:
1142+ pkg = self._cache[pkg_name]
1143+ except KeyError:
1144+ raise TransactionFailed(ERROR_NO_PACKAGE,
1145+ _("Package %s isn't available"),
1146+ pkg_name)
1147+ if not pkg.is_installed:
1148+ raise TransactionFailed(ERROR_PACKAGE_NOT_INSTALLED,
1149+ _("Package %s isn't installed"),
1150+ pkg_name)
1151+ pkg.mark_install(False, True, pkg.is_auto_installed)
1152+ resolver.clear(pkg)
1153+ resolver.protect(pkg)
1154+ if pkg_ver:
1155+ if (pkg.installed and
1156+ apt_pkg.version_compare(pkg.installed.version,
1157+ pkg_ver) == 1):
1158+ raise TransactionFailed(ERROR_PACKAGE_UPTODATE,
1159+ _("The later version %s of %s "
1160+ "is already installed"),
1161+ pkg.installed.version, pkg.name)
1162+ elif (pkg.installed and
1163+ apt_pkg.version_compare(pkg.installed.version,
1164+ pkg_ver) == 0):
1165+ raise TransactionFailed(ERROR_PACKAGE_UPTODATE,
1166+ _("The version %s of %s "
1167+ "is already installed"),
1168+ pkg.installed.version, pkg.name)
1169+ try:
1170+ pkg.candidate = pkg.versions[pkg_ver]
1171+ except KeyError:
1172+ raise TransactionFailed(ERROR_NO_PACKAGE,
1173+ _("The version %s of %s isn't "
1174+ "available."), pkg_ver, pkg_name)
1175+
1176+ elif pkg_rel:
1177+ self._set_candidate_release(pkg, pkg_rel)
1178+
1179+ @staticmethod
1180+ def _set_candidate_release(pkg, release):
1181+ """Set the candidate of a package to the one from the given release."""
1182+ #FIXME: Should be moved to python-apt
1183+ # Check if the package is provided in the release
1184+ for version in pkg.versions:
1185+ if [origin for origin in version.origins
1186+ if origin.archive == release]:
1187+ break
1188+ else:
1189+ raise TransactionFailed(ERROR_NO_PACKAGE,
1190+ _("The package %s isn't available in "
1191+ "the %s release."), pkg.name, release)
1192+ pkg._pcache.cache_pre_change()
1193+ pkg._pcache._depcache.set_candidate_release(pkg._pkg, version._cand,
1194+ release)
1195+ pkg._pcache.cache_post_change()
1196+
1197+ def update_cache(self, trans, sources_list):
1198+ """Update the cache.
1199+
1200+ Keyword arguments:
1201+ trans -- the corresponding transaction
1202+ sources_list -- only update the repositories found in the sources.list
1203+ snippet by the given file name.
1204+ """
1205+ log.info("Updating cache")
1206+ def compare_pathes(first, second):
1207+ """Small helper to compare two pathes."""
1208+ return os.path.normpath(first) == os.path.normpath(second)
1209+ progress = DaemonAcquireRepoProgress(trans, begin=10, end=90)
1210+ if sources_list and not sources_list.startswith("/"):
1211+ dir = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
1212+ sources_list = os.path.join(dir, sources_list)
1213+ if sources_list:
1214+ # For security reasons (LP #722228) we only allow files inside
1215+ # sources.list.d as basedir
1216+ basedir = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
1217+ system_sources = apt_pkg.config.find_file("Dir::Etc::sourcelist")
1218+ if "/" in sources_list:
1219+ sources_list = os.path.abspath(sources_list)
1220+ # Check if the sources_list snippet is in the sourceparts
1221+ # directory
1222+ common_prefix = os.path.commonprefix([sources_list, basedir])
1223+ if not (compare_pathes(common_prefix, basedir) or
1224+ compare_pathes(sources_list, system_sources)):
1225+ raise AptDaemonError("Only alternative sources.list files "
1226+ "inside '%s' are allowed (not '%s')" \
1227+ % (basedir, sources_list))
1228+ else:
1229+ sources_list = os.path.join(basedir, sources_list)
1230+ try:
1231+ self._cache.update(progress, sources_list=sources_list)
1232+ except apt.cache.FetchFailedException as error:
1233+ # ListUpdate() method of apt handles a cancelled operation
1234+ # as a failed one, see LP #162441
1235+ if trans.cancelled:
1236+ raise TransactionCancelled()
1237+ else:
1238+ raise TransactionFailed(ERROR_REPO_DOWNLOAD_FAILED,
1239+ str(error))
1240+ except apt.cache.FetchCancelledException:
1241+ raise TransactionCancelled()
1242+ except apt.cache.LockFailedException:
1243+ raise TransactionFailed(ERROR_NO_LOCK)
1244+ self._open_cache(trans, begin=91, end=95)
1245+
1246+ def upgrade_system(self, trans, safe_mode=True, simulate=False):
1247+ """Upgrade the system.
1248+
1249+ Keyword argument:
1250+ trans -- the corresponding transaction
1251+ safe_mode -- if additional software should be installed or removed to
1252+ satisfy the dependencies the an updates
1253+ simulate -- if the changes should not be applied
1254+ """
1255+ log.info("Upgrade system with safe mode: %s" % safe_mode)
1256+ trans.status = STATUS_RESOLVING_DEP
1257+ #FIXME: What to do if already uptotdate? Add error code?
1258+ self._call_plugins("modify_cache_before")
1259+ try:
1260+ self._cache.upgrade(dist_upgrade=not safe_mode)
1261+ except SystemError as excep:
1262+ raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED, str(excep))
1263+ self._call_plugins("modify_cache_after")
1264+ self._check_obsoleted_dependencies(trans)
1265+ if not simulate:
1266+ self._apply_changes(trans)
1267+
1268+ def fix_incomplete_install(self, trans):
1269+ """Run dpkg --configure -a to recover from a failed installation.
1270+
1271+ Keyword arguments:
1272+ trans -- the corresponding transaction
1273+ """
1274+ log.info("Fixing incomplete installs")
1275+ trans.status = STATUS_CLEANING_UP
1276+ with self._frozen_status():
1277+ with DaemonDpkgRecoverProgress(trans) as progress:
1278+ progress.run()
1279+ trans.output += progress.output
1280+ if progress._child_exit != 0:
1281+ raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
1282+ trans.output)
1283+
1284+ def reconfigure(self, trans, packages, priority):
1285+ """Run dpkg-reconfigure to reconfigure installed packages.
1286+
1287+ Keyword arguments:
1288+ trans -- the corresponding transaction
1289+ packages -- list of packages to reconfigure
1290+ priority -- the lowest priority of question which should be asked
1291+ """
1292+ log.info("Reconfiguring packages")
1293+ with self._frozen_status():
1294+ with DaemonDpkgReconfigureProgress(trans) as progress:
1295+ progress.run(packages, priority)
1296+ trans.output += progress.output
1297+ if progress._child_exit != 0:
1298+ raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
1299+ trans.output)
1300+
1301+ def fix_broken_depends(self, trans, simulate=False):
1302+ """Try to fix broken dependencies.
1303+
1304+ Keyword arguments:
1305+ trans -- the corresponding transaction
1306+ simualte -- if the changes should not be applied
1307+ """
1308+ log.info("Fixing broken depends")
1309+ trans.status = STATUS_RESOLVING_DEP
1310+ try:
1311+ self._cache._depcache.fix_broken()
1312+ except SystemError:
1313+ raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED,
1314+ self._get_broken_details(trans))
1315+ if not simulate:
1316+ self._apply_changes(trans)
1317+
1318+ def _open_cache(self, trans, begin=1, end=5, quiet=False, status=None):
1319+ """Open the APT cache.
1320+
1321+ Keyword arguments:
1322+ trans -- the corresponding transaction
1323+ start -- the begin of the progress range
1324+ end -- the end of the the progress range
1325+ quiet -- if True do no report any progress
1326+ status -- an alternative dpkg status file
1327+ """
1328+ self.marked_tid = None
1329+ trans.status = STATUS_LOADING_CACHE
1330+ if not status:
1331+ status = self._status_orig
1332+ apt_pkg.config.set("Dir::State::status", status)
1333+ apt_pkg.init_system()
1334+ progress = DaemonOpenProgress(trans, begin=begin, end=end,
1335+ quiet=quiet)
1336+ try:
1337+ if not isinstance(self._cache, apt.cache.Cache):
1338+ self._cache = apt.cache.Cache(progress)
1339+ else:
1340+ self._cache.open(progress)
1341+ except SystemError as excep:
1342+ raise TransactionFailed(ERROR_NO_CACHE, str(excep))
1343+
1344+ def is_dpkg_journal_clean(self):
1345+ """Return False if there are traces of incomplete dpkg status
1346+ updates."""
1347+ status_updates = os.path.join(os.path.dirname(self._status_orig),
1348+ "updates/")
1349+ for dentry in os.listdir(status_updates):
1350+ if dentry.isdigit():
1351+ return False
1352+ return True
1353+
1354+ def _apply_changes(self, trans, fetch_range=(15, 50),
1355+ install_range=(50, 90)):
1356+ """Apply previously marked changes to the system.
1357+
1358+ Keyword arguments:
1359+ trans -- the corresponding transaction
1360+ fetch_range -- tuple containing the start and end point of the
1361+ download progress
1362+ install_range -- tuple containing the start and end point of the
1363+ install progress
1364+ """
1365+ changes = self._cache.get_changes()
1366+ if not changes:
1367+ return
1368+ # Do not allow to remove essential packages
1369+ for pkg in changes:
1370+ if pkg.marked_delete and (pkg.essential == True or \
1371+ (pkg.installed and \
1372+ pkg.installed.priority == "required") or\
1373+ pkg.name == "aptdaemon"):
1374+ raise TransactionFailed(ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE,
1375+ _("Package %s cannot be removed"),
1376+ pkg.name)
1377+ # Check if any of the cache changes get installed from an
1378+ # unauthenticated repository""
1379+ if not trans.allow_unauthenticated and trans.unauthenticated:
1380+ raise TransactionFailed(ERROR_PACKAGE_UNAUTHENTICATED,
1381+ " ".join(sorted(trans.unauthenticated)))
1382+ if trans.cancelled:
1383+ raise TransactionCancelled()
1384+ trans.cancellable = False
1385+ fetch_progress = DaemonAcquireProgress(trans, begin=fetch_range[0],
1386+ end=fetch_range[1])
1387+ inst_progress = DaemonInstallProgress(trans, begin=install_range[0],
1388+ end=install_range[1])
1389+ with self._frozen_status():
1390+ try:
1391+ self._cache.commit(fetch_progress, inst_progress)
1392+ except apt.cache.FetchFailedException as error:
1393+ raise TransactionFailed(ERROR_PACKAGE_DOWNLOAD_FAILED,
1394+ str(error))
1395+ except apt.cache.FetchCancelledException:
1396+ raise TransactionCancelled()
1397+ except SystemError as excep:
1398+ # Run dpkg --configure -a to recover from a failed transaction
1399+ trans.status = STATUS_CLEANING_UP
1400+ with DaemonDpkgRecoverProgress(trans, begin=90, end=95) as pro:
1401+ pro.run()
1402+ output = inst_progress.output + pro.output
1403+ trans.output += output
1404+ raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
1405+ "%s: %s" % (excep, trans.output))
1406+ else:
1407+ enc = sys.getfilesystemencoding()
1408+ trans.output += inst_progress.output
1409+
1410+ @contextlib.contextmanager
1411+ def _frozen_status(self):
1412+ """Freeze the status file to allow simulate operations during
1413+ a dpkg call."""
1414+ frozen_dir = tempfile.mkdtemp(prefix="aptdaemon-frozen-status")
1415+ shutil.copy(self._status_orig, frozen_dir)
1416+ self._status_frozen = os.path.join(frozen_dir, "status")
1417+ try:
1418+ yield
1419+ finally:
1420+ shutil.rmtree(frozen_dir)
1421+ self._status_frozen = None
1422+
1423+ def query(self, trans):
1424+ """Process a PackageKit query transaction."""
1425+ raise NotImplementedError
1426+
1427+ def simulate(self, trans):
1428+ """Return the dependencies which will be installed by the transaction,
1429+ the content of the dpkg status file after the transaction would have
1430+ been applied, the download size and the required disk space.
1431+
1432+ Keyword arguments:
1433+ trans -- the transaction which should be simulated
1434+ """
1435+ log.info("Simulating trans: %s" % trans.tid)
1436+ trans.status = STATUS_RESOLVING_DEP
1437+ GObject.idle_add(self._simulate, trans)
1438+
1439+ def _simulate(self, trans):
1440+ try:
1441+ trans.depends, trans.download, trans.space, \
1442+ trans.unauthenticated = self.__simulate(trans)
1443+ except TransactionFailed as excep:
1444+ trans.error = excep
1445+ trans.exit = EXIT_FAILED
1446+ except Exception as excep:
1447+ tbk = traceback.format_exc()
1448+ trans.error = TransactionFailed(ERROR_UNKNOWN, tbk)
1449+ try:
1450+ from . import crash
1451+ except ImportError:
1452+ pass
1453+ else:
1454+ crash.create_report("%s: %s" % (type(excep), str(excep)),
1455+ tbk, trans)
1456+ trans.exit = EXIT_FAILED
1457+ else:
1458+ trans.status = STATUS_SETTING_UP
1459+ trans.simulated = time.time()
1460+ self.marked_tid = trans.tid
1461+ finally:
1462+ self._emit_transaction_simulated(trans)
1463+ self.last_action_timestamp = time.time()
1464+ return False
1465+
1466+ def __simulate(self, trans):
1467+ depends = [[], [], [], [], [], [], []]
1468+ unauthenticated = []
1469+ skip_pkgs = []
1470+ size = 0
1471+ installs = reinstalls = removals = purges = upgrades = upgradables = \
1472+ downgrades = []
1473+
1474+ # Only handle transaction which change packages
1475+ #FIXME: Add support for ROLE_FIX_INCOMPLETE_INSTALL
1476+ if trans.role not in [ROLE_INSTALL_PACKAGES, ROLE_UPGRADE_PACKAGES,
1477+ ROLE_UPGRADE_SYSTEM, ROLE_REMOVE_PACKAGES,
1478+ ROLE_COMMIT_PACKAGES, ROLE_INSTALL_FILE,
1479+ ROLE_FIX_BROKEN_DEPENDS]:
1480+ return depends, 0, 0, []
1481+
1482+ # If a transaction is currently running use the former status file
1483+ if self._status_frozen:
1484+ status_path = self._status_frozen
1485+ else:
1486+ status_path = self._status_orig
1487+ self._open_cache(trans, quiet=True, status=status_path)
1488+ if trans.role == ROLE_FIX_BROKEN_DEPENDS:
1489+ self.fix_broken_depends(trans, simulate=True)
1490+ elif self._cache.broken_count:
1491+ raise TransactionFailed(ERROR_CACHE_BROKEN,
1492+ self._get_broken_details(trans))
1493+ elif trans.role == ROLE_UPGRADE_SYSTEM:
1494+ for pkg in self._iterate_packages():
1495+ if pkg.is_upgradable:
1496+ upgradables.append(pkg)
1497+ self.upgrade_system(trans, simulate=True, **trans.kwargs)
1498+ elif trans.role == ROLE_INSTALL_FILE:
1499+ deb = self.install_file(trans, simulate=True, **trans.kwargs)
1500+ skip_pkgs.append(deb.pkgname)
1501+ try:
1502+ # Sometimes a thousands comma is used in packages
1503+ # See LP #656633
1504+ size = int(deb["Installed-Size"].replace(",", "")) * 1024
1505+ # Some packages ship really large install sizes e.g.
1506+ # openvpn access server, see LP #758837
1507+ if size > sys.maxsize:
1508+ raise OverflowError("Size is too large: %s Bytes" % size)
1509+ except (KeyError, AttributeError, ValueError, OverflowError):
1510+ if not trans.kwargs["force"]:
1511+ msg = trans.gettext("The package doesn't provide a "
1512+ "valid Installed-Size control "
1513+ "field. See Debian Policy 5.6.20.")
1514+ raise TransactionFailed(ERROR_INVALID_PACKAGE_FILE, msg)
1515+ try:
1516+ pkg = self._cache[deb.pkgname]
1517+ except KeyError:
1518+ trans.packages = [[deb.pkgname], [], [], [], [], []]
1519+ else:
1520+ if pkg.is_installed:
1521+ # if we failed to get the size from the deb file do nor
1522+ # try to get the delta
1523+ if size != 0:
1524+ size -= pkg.installed.installed_size
1525+ trans.packages = [[], [deb.pkgname], [], [], [], []]
1526+ else:
1527+ trans.packages = [[deb.pkgname], [], [], [], [], []]
1528+ else:
1529+ #FIXME: ugly code to get the names of the packages
1530+ (installs, reinstalls, removals, purges,
1531+ upgrades, downgrades) = [[re.split("(=|/)", entry, 1)[0] \
1532+ for entry in lst] \
1533+ for lst in trans.packages]
1534+ self.commit_packages(trans, *trans.packages, simulate=True)
1535+
1536+ changes = self._cache.get_changes()
1537+ changes_names = []
1538+ # get the additional dependencies
1539+ for pkg in changes:
1540+ self._iterate_mainloop()
1541+ pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
1542+ if pkg.marked_upgrade and pkg.is_installed and \
1543+ not pkg.name in upgrades:
1544+ depends[PKGS_UPGRADE].append(pkg_str)
1545+ elif pkg.marked_reinstall and not pkg.name in reinstalls:
1546+ depends[PKGS_REINSTALL].append(pkg_str)
1547+ elif pkg.marked_downgrade and not pkg.name in downgrades:
1548+ depends[PKGS_DOWNGRADE].append(pkg_str)
1549+ elif pkg.marked_install and not pkg.name in installs:
1550+ depends[PKGS_INSTALL].append(pkg_str)
1551+ elif pkg.marked_delete and not pkg.name in removals:
1552+ pkg_str = "%s=%s" % (pkg.name, pkg.installed.version)
1553+ depends[PKGS_REMOVE].append(pkg_str)
1554+ #FIXME: add support for purges
1555+ changes_names.append(pkg.name)
1556+ # get the unauthenticated packages
1557+ unauthenticated = self._get_unauthenticated()
1558+ # Check for skipped upgrades
1559+ for pkg in upgradables:
1560+ if pkg.marked_keep:
1561+ pkg_str = "%s=%s" % (pkg.name, pkg.candidate.version)
1562+ depends[PKGS_KEEP].append(pkg_str)
1563+
1564+ # apt.cache.Cache.required_download requires a clean cache. Under some
1565+ # strange circumstances it can fail (most likely an interrupted
1566+ # debconf question), see LP#659438
1567+ # Running dpkg --configure -a fixes the situation
1568+ try:
1569+ required_download = self._cache.required_download
1570+ except SystemError as error:
1571+ raise TransactionFailed(ERROR_INCOMPLETE_INSTALL, str(error))
1572+
1573+ required_space = size + self._cache.required_space
1574+
1575+ return depends, required_download, required_space, unauthenticated
1576+
1577+ def _check_deb_file(self, path, force, uid):
1578+ """Perform some basic checks for the Debian package.
1579+
1580+ :param trans: The transaction instance.
1581+
1582+ :returns: An apt.debfile.Debfile instance.
1583+ """
1584+ #FIXME: Unblock lintian call
1585+ if not os.path.isfile(path):
1586+ raise TransactionFailed(ERROR_UNREADABLE_PACKAGE_FILE, path)
1587+ if not force and os.path.isfile("/usr/bin/lintian"):
1588+ tags_dir = os.path.join(apt_pkg.config.find_dir("Dir"),
1589+ "usr", "share", "aptdaemon")
1590+ try:
1591+ distro = platform.dist()[0]
1592+ except KeyError:
1593+ distro = None
1594+ else:
1595+ tags_file = os.path.join(tags_dir,
1596+ "lintian-nonfatal.tags.%s" % distro)
1597+ tags_fatal_file = os.path.join(tags_dir,
1598+ "lintian-fatal.tags.%s" % distro)
1599+ if not distro or not os.path.exists(tags_file):
1600+ log.debug("Using default lintian tags file")
1601+ tags_file = os.path.join(tags_dir, "lintian-nonfatal.tags")
1602+ if not distro or not os.path.exists(tags_fatal_file):
1603+ log.debug("Using default lintian fatal tags file")
1604+ tags_fatal_file = os.path.join(tags_dir, "lintian-fatal.tags")
1605+ # Run linitan as the user who initiated the transaction
1606+ # Once with non fatal checks and a second time with the fatal
1607+ # checks which are not allowed to be overriden
1608+ nonfatal_args = ["/usr/bin/lintian", "--tags-from-file",
1609+ tags_file, path]
1610+ fatal_args = ["/usr/bin/lintian", "--tags-from-file",
1611+ tags_fatal_file, "--no-override", path]
1612+ for lintian_args in (nonfatal_args, fatal_args):
1613+ proc = subprocess.Popen(lintian_args,
1614+ stderr=subprocess.STDOUT,
1615+ stdout=subprocess.PIPE, close_fds=True,
1616+ preexec_fn=lambda: os.setuid(uid))
1617+ while proc.poll() is None:
1618+ self._iterate_mainloop()
1619+ time.sleep(0.05)
1620+ #FIXME: Add an error to catch return state 2 (failure)
1621+ if proc.returncode == 1:
1622+ stdout = proc.stdout.read()
1623+ stdout.decode(sys.stdin.encoding or "UTF-8",
1624+ errors="replace")
1625+ raise TransactionFailed(ERROR_INVALID_PACKAGE_FILE,
1626+ "Lintian check results for %s:"
1627+ "\n%s" % (path, stdout))
1628+ try:
1629+ deb = apt.debfile.DebPackage(path, self._cache)
1630+ except IOError:
1631+ raise TransactionFailed(ERROR_UNREADABLE_PACKAGE_FILE, path)
1632+ except Exception as error:
1633+ raise TransactionFailed(ERROR_INVALID_PACKAGE_FILE, str(error))
1634+ try:
1635+ ret = deb.check()
1636+ except Exception as error:
1637+ raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED, str(error))
1638+ if not ret:
1639+ raise TransactionFailed(ERROR_DEP_RESOLUTION_FAILED,
1640+ deb._failure_string)
1641+ return deb
1642+
1643+ def clean(self, trans):
1644+ """Clean the download directories.
1645+
1646+ Keyword arguments:
1647+ trans -- the corresponding transaction
1648+ """
1649+ #FIXME: Use pkgAcquire.Clean(). Currently not part of python-apt.
1650+ trans.status = STATUS_CLEANING_UP
1651+ archive_path = apt_pkg.config.find_dir("Dir::Cache::archives")
1652+ for dir in [archive_path, os.path.join(archive_path, "partial")]:
1653+ for filename in os.listdir(dir):
1654+ if filename == "lock":
1655+ continue
1656+ path = os.path.join(dir, filename)
1657+ if os.path.isfile(path):
1658+ log.debug("Removing file %s", path)
1659+ os.remove(path)
1660+
1661+ def add_license_key(self, trans, pkg_name, json_token, server_name):
1662+ """Add a license key data to the given package.
1663+
1664+ Keyword arguemnts:
1665+ trans -- the coresponding transaction
1666+ pkg_name -- the name of the corresponding package
1667+ json_token -- the oauth token as json
1668+ server_name -- the server to use (ubuntu-production, ubuntu-staging)
1669+ """
1670+ # set transaction state to downloading
1671+ trans.status = STATUS_DOWNLOADING
1672+ try:
1673+ license_key, license_key_path = \
1674+ self.plugins["get_license_key"][0](trans.uid, pkg_name,
1675+ json_token, server_name)
1676+ except Exception as error:
1677+ logging.exception("get_license_key plugin failed")
1678+ raise TransactionFailed(ERROR_LICENSE_KEY_DOWNLOAD_FAILED,
1679+ str(error))
1680+ # ensure stuff is good
1681+ if not license_key_path or not license_key:
1682+ raise TransactionFailed(ERROR_LICENSE_KEY_DOWNLOAD_FAILED,
1683+ _("The license key is empty"))
1684+
1685+ # add license key if we have one
1686+ self._add_license_key_to_system(pkg_name, license_key, license_key_path)
1687+
1688+ def _add_license_key_to_system(self, pkg_name, license_key, license_key_path):
1689+ # fixup path
1690+ license_key_path = os.path.join(apt_pkg.config.find_dir("Dir"),
1691+ license_key_path.lstrip("/"))
1692+
1693+ # Check content of the key
1694+ if (license_key.strip().startswith("#!") or
1695+ license_key.startswith("\x7fELF")):
1696+ raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
1697+ _("The license key is not allowed to "
1698+ "contain executable code."))
1699+ # Check the path of the license
1700+ license_key_path = os.path.normpath(license_key_path)
1701+ license_key_path_rootdir = os.path.join(apt_pkg.config["Dir"],
1702+ self.LICENSE_KEY_ROOTDIR.lstrip("/"),
1703+ pkg_name)
1704+ if not license_key_path.startswith(license_key_path_rootdir):
1705+ raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
1706+ _("The license key path %s is invalid"),
1707+ license_key_path)
1708+ if os.path.lexists(license_key_path):
1709+ raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
1710+ _("The license key already exists: %s"),
1711+ license_key_path)
1712+ # Symlink attacks!
1713+ if os.path.realpath(license_key_path) != license_key_path:
1714+ raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
1715+ _("The location of the license key is "
1716+ "unsecure since it contains symbolic "
1717+ "links. The path %s maps to %s"),
1718+ license_key_path,
1719+ os.path.realpath(license_key_path))
1720+ # Check if the directory already exists
1721+ if not os.path.isdir(os.path.dirname(license_key_path)):
1722+ raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
1723+ _("The directory where to install the key "
1724+ "to doesn't exist yet: %s"),
1725+ license_key_path)
1726+ # write it
1727+ log.info("Writing license key to '%s'" % license_key_path)
1728+ old_umask = os.umask(18)
1729+ try:
1730+ with open(license_key_path, "w") as license_file:
1731+ license_file.write(license_key)
1732+ except IOError:
1733+ raise TransactionFailed(ERROR_LICENSE_KEY_INSTALL_FAILED,
1734+ _("Failed to write key file to: %s"),
1735+ license_key_path)
1736+ finally:
1737+ os.umask(old_umask)
1738+
1739+ def _iterate_mainloop(self):
1740+ """Process pending actions on the main loop."""
1741+ while GObject.main_context_default().pending():
1742+ GObject.main_context_default().iteration()
1743+
1744+ def _iterate_packages(self, interval=1000):
1745+ """Itarte von the packages of the cache and iterate on the
1746+ GObject main loop time for more responsiveness.
1747+
1748+ Keyword arguments:
1749+ interval - the number of packages after which we iterate on the
1750+ mainloop
1751+ """
1752+ for enum, pkg in enumerate(self._cache):
1753+ if not enum % interval:
1754+ self._iterate_mainloop()
1755+ yield pkg
1756+
1757+ def _get_broken_details(self, trans, now=True):
1758+ """Return a message which provides debugging information about
1759+ broken packages.
1760+
1761+ This method is basically a Python implementation of apt-get.cc's
1762+ ShowBroken.
1763+
1764+ Keyword arguments:
1765+ trans -- the corresponding transaction
1766+ now -- if we check currently broken dependecies or the installation
1767+ candidate
1768+ """
1769+ msg = trans.gettext("The following packages have unmet dependencies:")
1770+ msg += "\n\n"
1771+ for pkg in self._cache:
1772+ if not ((now and pkg.is_now_broken) or
1773+ (not now and pkg.is_inst_broken)):
1774+ continue
1775+ msg += "%s: " % pkg.name
1776+ if now:
1777+ version = pkg.installed
1778+ else:
1779+ version = pkg.candidate
1780+ indent = " " * (len(pkg.name) + 2)
1781+ dep_msg = ""
1782+ for dep in version.dependencies:
1783+ or_msg = ""
1784+ for base_dep in dep.or_dependencies:
1785+ if or_msg:
1786+ or_msg += "or\n"
1787+ or_msg += indent
1788+ # Check if it's an important dependency
1789+ # See apt-pkg/depcache.cc IsImportantDep
1790+ # See apt-pkg/pkgcache.cc IsCritical()
1791+ # FIXME: Add APT::Install-Recommends-Sections
1792+ if not (base_dep.rawtype in ["Depends", "PreDepends",
1793+ "Obsoletes", "DpkgBreaks",
1794+ "Conflicts"] or
1795+ (apt_pkg.config.find_b("APT::Install-Recommends",
1796+ False) and
1797+ base_dep.rawtype == "Recommends") or
1798+ (apt_pkg.config.find_b("APT::Install-Suggests",
1799+ False) and
1800+ base_dep.rawtype == "Suggests")):
1801+ continue
1802+ # Get the version of the target package
1803+ try:
1804+ pkg_dep = self._cache[base_dep.name]
1805+ except KeyError:
1806+ dep_version = None
1807+ else:
1808+ if now:
1809+ dep_version = pkg_dep.installed
1810+ else:
1811+ dep_version = pkg_dep.candidate
1812+ # We only want to display dependencies which cannot
1813+ # be satisfied
1814+ if dep_version and not apt_pkg.check_dep(base_dep.version,
1815+ base_dep.relation,
1816+ version.version):
1817+ break
1818+ or_msg = "%s: %s " % (base_dep.rawtype, base_dep.name)
1819+ if base_dep.version:
1820+ or_msg += "(%s %s) " % (base_dep.relation,
1821+ base_dep.version)
1822+ if self._cache.is_virtual_package(base_dep.name):
1823+ or_msg += trans.gettext("but it is a virtual package")
1824+ elif not dep_version:
1825+ if now:
1826+ or_msg += trans.gettext("but it is not installed")
1827+ else:
1828+ or_msg += trans.gettext("but it is not going to "
1829+ "be installed")
1830+ elif now:
1831+ #TRANSLATORS: %s is a version number
1832+ or_msg += trans.gettext("but %s is installed") % \
1833+ dep_version.version
1834+ else:
1835+ #TRANSLATORS: %s is a version number
1836+ or_msg += trans.gettext("but %s is to be installed") % \
1837+ dep_version.version
1838+ else:
1839+ # Only append an or-group if at least one of the
1840+ # dependencies cannot be satisfied
1841+ if dep_msg:
1842+ dep_msg += indent
1843+ dep_msg += or_msg
1844+ dep_msg += "\n"
1845+ msg += dep_msg
1846+ return msg
1847+
1848+ def is_reboot_required(self):
1849+ """If a reboot is required to get all changes into effect."""
1850+ return os.path.exists(os.path.join(apt_pkg.config.find_dir("Dir"),
1851+ "var/run/reboot-required"))
1852+
1853+
1854+class DummyWorker(AptWorker):
1855+
1856+ """Allows to test the daemon without making any changes to the system."""
1857+
1858+ def run(self, transaction):
1859+ """Process the given transaction in the background.
1860+
1861+ Keyword argument:
1862+ transaction -- core.Transcation instance to run
1863+ """
1864+ log.info("Processing transaction %s", transaction.tid)
1865+ if self.trans:
1866+ raise Exception("There is already a running transaction")
1867+ self.trans = transaction
1868+ self.last_action_timestamp = time.time()
1869+ self.trans.status = STATUS_RUNNING
1870+ self.trans.progress = 0
1871+ self.trans.cancellable = True
1872+ GObject.timeout_add(200, self._process_transaction, transaction)
1873+
1874+ def _process_transaction(self, trans):
1875+ """Run the worker"""
1876+ if trans.cancelled:
1877+ trans.exit = EXIT_CANCELLED
1878+ elif trans.progress == 100:
1879+ trans.exit = EXIT_SUCCESS
1880+ elif trans.role == ROLE_UPDATE_CACHE:
1881+ trans.exit = EXIT_FAILED
1882+ elif trans.role == ROLE_UPGRADE_PACKAGES:
1883+ trans.exit = EXIT_SUCCESS
1884+ elif trans.role == ROLE_UPGRADE_SYSTEM:
1885+ trans.exit = EXIT_CANCELLED
1886+ else:
1887+ if trans.role == ROLE_INSTALL_PACKAGES:
1888+ if trans.progress == 1:
1889+ trans.status = STATUS_RESOLVING_DEP
1890+ elif trans.progress == 5:
1891+ trans.status = STATUS_DOWNLOADING
1892+ elif trans.progress == 50:
1893+ trans.status = STATUS_COMMITTING
1894+ trans.status_details = "Heyas!"
1895+ elif trans.progress == 55:
1896+ trans.paused = True
1897+ trans.status = STATUS_WAITING_CONFIG_FILE_PROMPT
1898+ trans.config_file_conflict = "/etc/fstab", "/etc/mtab"
1899+ while trans.paused:
1900+ GObject.main_context_default().iteration()
1901+ trans.config_file_conflict_resolution = None
1902+ trans.config_file_conflict = None
1903+ trans.status = STATUS_COMMITTING
1904+ elif trans.progress == 60:
1905+ trans.required_medium = ("Debian Lenny 5.0 CD 1",
1906+ "USB CD-ROM")
1907+ trans.paused = True
1908+ trans.status = STATUS_WAITING_MEDIUM
1909+ while trans.paused:
1910+ GObject.main_context_default().iteration()
1911+ trans.status = STATUS_DOWNLOADING
1912+ elif trans.progress == 70:
1913+ trans.status_details = "Servus!"
1914+ elif trans.progress == 90:
1915+ trans.status_deatils = ""
1916+ trans.status = STATUS_CLEANING_UP
1917+ elif trans.role == ROLE_REMOVE_PACKAGES:
1918+ if trans.progress == 1:
1919+ trans.status = STATUS_RESOLVING_DEP
1920+ elif trans.progress == 5:
1921+ trans.status = STATUS_COMMITTING
1922+ trans.status_details = "Heyas!"
1923+ elif trans.progress == 50:
1924+ trans.status_details = "Hola!"
1925+ elif trans.progress == 70:
1926+ trans.status_details = "Servus!"
1927+ elif trans.progress == 90:
1928+ trans.status_deatils = ""
1929+ trans.status = STATUS_CLEANING_UP
1930+ trans.progress += 1
1931+ return True
1932+ trans.status = STATUS_FINISHED
1933+ self.last_action_timestamp = time.time()
1934+ tid = self.trans.tid[:]
1935+ trans = self.trans
1936+ self.trans = None
1937+ self._emit_transaction_done(trans)
1938+ log.info("Finished transaction %s", tid)
1939+ return False
1940+
1941+ def simulate(self, trans):
1942+ depends = [[], [], [], [], [], [], []]
1943+ return depends, 0, 0, []
1944+
1945+
1946+# vim:ts=4:sw=4:et
1947
1948=== modified file 'NEWS'
1949--- NEWS 2011-12-15 10:15:46 +0000
1950+++ NEWS 2012-06-13 16:29:18 +0000
1951@@ -1,4 +1,20 @@
1952-CHANGES (0.4x):
1953+CHANGES (0.5x):
1954+
1955+ * Enhancements:
1956+
1957+ - Python3 support
1958+
1959+ - Make use of apt.auth instead of softwareproperties.AptAuth
1960+
1961+ - Support more PackageKit transactions (InstallSignature, RepoEnable)
1962+
1963+ * API changes:
1964+
1965+ - aptdaemon.test.TestCase has now a start_keyserver() method to fake
1966+ a GnuPG key server
1967+
1968+
1969+CHANGES (0.45):
1970
1971 * Enhancements:
1972
1973@@ -9,6 +25,8 @@
1974 - Freeze (copy) the dpkg status file during a dpkg call to allow
1975 simulating other transactions with the frozen dpkg status
1976
1977+ - Share WhatProvides plugins with the Python APT PackageKit backend
1978+
1979 - Allow to install global license keys, see below
1980
1981 - Add compatibilty for py-gobject 3.0 to the client module by switching
1982@@ -35,6 +53,10 @@
1983
1984 * API changes:
1985
1986+ - what-provides plugin: Share this plugin with the Python APT backend
1987+ of PackageKit to allow other packages to specify providers for
1988+ mod aliases, GStreamer codecs or language support
1989+
1990 - get-license-key plugin: Add this new plugin which gets the uid,
1991 the package name, a json oauth token identifieng the customer
1992 and a server name to retrieve a license key and the path to store it to
1993@@ -57,7 +79,9 @@
1994 - org.freedesktop.PackageKit.transaction D-Bus interface: Initial
1995 implementaion
1996
1997- - aptdaemon.client: New AptClient.add_license_key method
1998+ - aptdaemon.client:
1999+ o New AptClient.add_license_key method
2000+ o Rename Transaction.disconnect() to Transaction._disconnect_from_dbus()
2001
2002 - aptdaemon.enums:
2003 o Add enums for package states (e.g. PKG_INSTALLING or
2004@@ -106,6 +130,11 @@
2005 - Use apt_pkg.version_compare to detect already upt-to-date packages
2006 instead of simple string comparison
2007 - Fix --downgrade option of aptdcon
2008+ - Fix not supported errors in pkcompat
2009+ - Fix cancelling transactions
2010+ - Sync all properties of a transaction in the client before emitting
2011+ the finished signal (LP#747172)
2012+ - Fixes to piping the terminal (LP #733090)
2013
2014
2015 CHANGES (0.43)
2016
2017=== modified file 'README.PackageKit'
2018--- README.PackageKit 2012-03-09 09:02:40 +0000
2019+++ README.PackageKit 2012-06-13 16:29:18 +0000
2020@@ -50,20 +50,19 @@
2021 - GetUpdateDetail
2022 - GetDistroUpgrades
2023 - UpgradeSystem
2024+ - WhatProvides (no builtin handling, only plugins)
2025+ - RepoEnable: (only enabling, not disabling)
2026+ - InstallSignature
2027
2028 Not yet supported roles:
2029
2030 - GetCategories: Curently groups are still used, would be nice to reuse the
2031 categories from software-center
2032 - GetRepoList: not implemented in the worker
2033- - RepoEnable: not implemented in the worker)
2034- - RepoSetData: not implemented in the worker)
2035+ - RepoSetData: not implemented in the worker
2036 - InstallFiles: not implemented in the worker
2037 - SimulateInstallFiles: not implemented in the worker
2038- - WhatProvides: not implemented in the worker. We could reuse code from
2039 sessioninstaller.
2040- - InstallSignature: not implemented in the worker. Could be mapped to
2041- AddVendorKeyFromFile.
2042
2043 Roles we won't support at all because of missing infrastructure in APT:
2044
2045
2046=== modified file 'README.tests'
2047--- README.tests 2010-07-12 09:46:15 +0000
2048+++ README.tests 2012-06-13 16:29:18 +0000
2049@@ -1,3 +1,4 @@
2050-Tests are supported via nosetests from the python-nose package.
2051+Tests are supported via nosetests3 from the python3-nose package.
2052
2053-Run them via nosetests.
2054+To run the tests you can either use the "python3 setup.py test" or
2055+the "nosetests3" command.
2056
2057=== modified file 'aptd'
2058--- aptd 2009-06-30 15:06:36 +0000
2059+++ aptd 2012-06-13 16:29:18 +0000
2060@@ -1,4 +1,4 @@
2061-#!/usr/bin/python
2062+#!/usr/bin/python3
2063 # -*- coding: utf-8 -*-
2064 """
2065 aptd - apt daemon
2066
2067=== modified file 'aptdaemon/client.py'
2068--- aptdaemon/client.py 2012-04-09 20:48:44 +0000
2069+++ aptdaemon/client.py 2012-06-13 16:29:18 +0000
2070@@ -67,12 +67,16 @@
2071 return value
2072
2073
2074-class MemoizedMixIn(MemoizedTransaction, GObject.GObjectMeta):
2075+class MemoizedMixInMeta(MemoizedTransaction, GObject.GObjectMeta):
2076
2077 """Helper meta class for merging"""
2078
2079-
2080-class AptTransaction(GObject.GObject):
2081+# This code is used to make meta classes work with Python 2 and 3 at the same
2082+# time, see http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/
2083+MemoizedMixIn = MemoizedMixInMeta("MemoizedMixIn", (GObject.GObject,), {})
2084+
2085+
2086+class AptTransaction(MemoizedMixIn):
2087
2088 """Represents an aptdaemon transaction.
2089
2090@@ -410,7 +414,6 @@
2091 dependencies before the transaction will be executed.
2092 """
2093
2094- __metaclass__ = MemoizedMixIn
2095
2096 __gsignals__ = {"finished": (GObject.SIGNAL_RUN_FIRST,
2097 GObject.TYPE_NONE,
2098@@ -426,10 +429,10 @@
2099 GObject.TYPE_PYOBJECT)),
2100 "download-changed": (GObject.SIGNAL_RUN_FIRST,
2101 GObject.TYPE_NONE,
2102- (GObject.TYPE_INT,)),
2103+ (GObject.TYPE_INT64,)),
2104 "space-changed": (GObject.SIGNAL_RUN_FIRST,
2105 GObject.TYPE_NONE,
2106- (GObject.TYPE_INT,)),
2107+ (GObject.TYPE_INT64,)),
2108 "error": (GObject.SIGNAL_RUN_FIRST,
2109 GObject.TYPE_NONE,
2110 (GObject.TYPE_STRING, GObject.TYPE_STRING)),
2111@@ -457,15 +460,17 @@
2112 "progress-details-changed": (GObject.SIGNAL_RUN_FIRST,
2113 GObject.TYPE_NONE,
2114 (GObject.TYPE_INT, GObject.TYPE_INT,
2115- GObject.TYPE_INT, GObject.TYPE_INT,
2116- GObject.TYPE_INT, GObject.TYPE_INT)),
2117+ GObject.TYPE_INT64,
2118+ GObject.TYPE_INT64,
2119+ GObject.TYPE_INT,
2120+ GObject.TYPE_INT64)),
2121 "progress-download-changed": (GObject.SIGNAL_RUN_FIRST,
2122 GObject.TYPE_NONE,
2123 (GObject.TYPE_STRING,
2124 GObject.TYPE_STRING,
2125 GObject.TYPE_STRING,
2126- GObject.TYPE_INT,
2127- GObject.TYPE_INT,
2128+ GObject.TYPE_INT64,
2129+ GObject.TYPE_INT64,
2130 GObject.TYPE_STRING)),
2131 "packages-changed": (GObject.SIGNAL_RUN_FIRST,
2132 GObject.TYPE_NONE,
2133@@ -554,8 +559,7 @@
2134 # main signals
2135 self._signal_matcher = \
2136 self._iface.connect_to_signal("PropertyChanged",
2137- self._on_property_changed,
2138- utf8_strings=True)
2139+ self._on_property_changed)
2140
2141 def _on_name_owner_changed(self, connection):
2142 """Fail the transaction if the daemon died."""
2143@@ -681,7 +685,7 @@
2144 :raises: dbus.DBusException
2145 """
2146 def sync_properties(prop_dict):
2147- for property_name, value in prop_dict.iteritems():
2148+ for property_name, value in prop_dict.items():
2149 self._on_property_changed(property_name, value)
2150 if reply_handler:
2151 reply_handler(self)
2152
2153=== modified file 'aptdaemon/config.py'
2154--- aptdaemon/config.py 2012-02-03 06:37:42 +0000
2155+++ aptdaemon/config.py 2012-06-13 16:29:18 +0000
2156@@ -228,7 +228,7 @@
2157 for filename in sorted(os.listdir("/etc/apt/apt.conf.d/")):
2158 lines = open("/etc/apt/apt.conf.d/%s" % filename).readlines()
2159 cw.parse(lines)
2160- print(cw.set_value("huhu::abc", "lumpi", "10glatzor"))
2161+ print((cw.set_value("huhu::abc", "lumpi", "10glatzor")))
2162
2163 if __name__ == "__main__":
2164 main()
2165
2166=== modified file 'aptdaemon/console.py'
2167--- aptdaemon/console.py 2012-04-09 20:48:44 +0000
2168+++ aptdaemon/console.py 2012-06-13 16:29:18 +0000
2169@@ -53,6 +53,8 @@
2170 ANSI_BOLD = chr(27) + "[1m"
2171 ANSI_RESET = chr(27) + "[0m"
2172
2173+PY3K = sys.version_info.major > 2
2174+
2175
2176 class ConsoleClient:
2177 """
2178@@ -442,70 +444,73 @@
2179 kepts = dep_kepts
2180 if installs:
2181 #TRANSLATORS: %s is the number of packages
2182- print(ngettext("The following NEW package will be installed "
2183+ print((ngettext("The following NEW package will be installed "
2184 "(%(count)s):",
2185 "The following NEW packages will be installed "
2186 "(%(count)s):",
2187- len(installs)) % {"count": len(installs)})
2188+ len(installs)) % {"count": len(installs)}))
2189 show_packages(installs)
2190 if upgrades:
2191 #TRANSLATORS: %s is the number of packages
2192- print(ngettext("The following package will be upgraded "
2193+ print((ngettext("The following package will be upgraded "
2194 "(%(count)s):",
2195 "The following packages will be upgraded "
2196 "(%(count)s):",
2197- len(upgrades)) % {"count": len(upgrades)})
2198+ len(upgrades)) % {"count": len(upgrades)}))
2199 show_packages(upgrades)
2200 if removals:
2201 #TRANSLATORS: %s is the number of packages
2202- print(ngettext("The following package will be REMOVED "
2203+ print((ngettext("The following package will be REMOVED "
2204 "(%(count)s):",
2205 "The following packages will be REMOVED "
2206 "(%(count)s):",
2207- len(removals)) % {"count": len(removals)})
2208+ len(removals)) % {"count": len(removals)}))
2209 #FIXME: mark purges
2210 show_packages(removals)
2211 if downgrades:
2212 #TRANSLATORS: %s is the number of packages
2213- print(ngettext("The following package will be DOWNGRADED "
2214+ print((ngettext("The following package will be DOWNGRADED "
2215 "(%(count)s):",
2216 "The following packages will be DOWNGRADED "
2217 "(%(count)s):",
2218- len(downgrades)) % {"count": len(downgrades)})
2219+ len(downgrades)) % {"count": len(downgrades)}))
2220 show_packages(downgrades)
2221 if reinstalls:
2222 #TRANSLATORS: %s is the number of packages
2223- print(ngettext("The following package will be reinstalled "
2224+ print((ngettext("The following package will be reinstalled "
2225 "(%(count)s):",
2226 "The following packages will be reinstalled "
2227 "(%(count)s):",
2228- len(reinstalls)) % {"count": len(reinstalls)})
2229+ len(reinstalls)) % {"count": len(reinstalls)}))
2230 show_packages(reinstalls)
2231 if kepts:
2232- print(ngettext("The following package has been kept back "
2233+ print((ngettext("The following package has been kept back "
2234 "(%(count)s):",
2235 "The following packages have been kept back "
2236 "(%(count)s):",
2237- len(kepts)) % {"count": len(kepts)})
2238+ len(kepts)) % {"count": len(kepts)}))
2239 show_packages(kepts)
2240
2241 if self._transaction.download:
2242- print(_("Need to get %sB of archives.") % \
2243- apt_pkg.size_to_str(self._transaction.download))
2244+ print((_("Need to get %sB of archives.") % \
2245+ apt_pkg.size_to_str(self._transaction.download)))
2246 if self._transaction.space > 0:
2247- print(_("After this operation, %sB of additional disk space "
2248+ print((_("After this operation, %sB of additional disk space "
2249 "will be used.") % \
2250- apt_pkg.size_to_str(self._transaction.space))
2251+ apt_pkg.size_to_str(self._transaction.space)))
2252 elif self._transaction.space < 0:
2253- print(_("After this operation, %sB of additional disk space "
2254+ print((_("After this operation, %sB of additional disk space "
2255 "will be freed.") % \
2256- apt_pkg.size_to_str(self._transaction.space))
2257+ apt_pkg.size_to_str(self._transaction.space)))
2258 if (not apt_pkg.config.find_b("APT::Get::Assume-Yes") and
2259 (self._transaction.space or self._transaction.download or
2260 installs or upgrades or downgrades or removals or kepts or
2261 reinstalls)):
2262 try:
2263- cont = raw_input(_("Do you want to continue [Y/n]?"))
2264+ if PY3K:
2265+ cont = input(_("Do you want to continue [Y/n]?"))
2266+ else:
2267+ cont = raw_input(_("Do you want to continue [Y/n]?"))
2268 except EOFError:
2269 cont = "n"
2270 #FIXME: Listen to changed dependencies!
2271@@ -532,100 +537,100 @@
2272
2273 epilog = _("To operate on more than one package put the package "
2274 "names in quotation marks:\naptdcon --install "
2275- "\"foo bar\"").decode(enc)
2276+ "\"foo bar\"")
2277 parser = OptionParser(version=aptdaemon.__version__, epilog=epilog)
2278 parser.add_option("-c", "--refresh", default="",
2279 action="store_true", dest="refresh",
2280- help=_("Refresh the cache").decode(enc))
2281+ help=_("Refresh the cache"))
2282 parser.add_option("", "--fix-depends", default="",
2283 action="store_true", dest="fix_depends",
2284 help=_("Try to resolve broken dependencies. "
2285 "Potentially dangerous operation since it could "
2286- "try to remove many packages.").decode(enc))
2287+ "try to remove many packages."))
2288 parser.add_option("", "--fix-install", default="",
2289 action="store_true", dest="fix_install",
2290 help=_("Try to finish a previous incompleted "
2291- "installation").decode(enc))
2292+ "installation"))
2293 parser.add_option("-i", "--install", default="",
2294 action="store", type="string", dest="install",
2295- help=_("Install the given packages").decode(enc))
2296+ help=_("Install the given packages"))
2297 parser.add_option("", "--reinstall", default="",
2298 action="store", type="string", dest="reinstall",
2299- help=_("Reinstall the given packages").decode(enc))
2300+ help=_("Reinstall the given packages"))
2301 parser.add_option("-r", "--remove", default="",
2302 action="store", type="string", dest="remove",
2303- help=_("Remove the given packages").decode(enc))
2304+ help=_("Remove the given packages"))
2305 parser.add_option("-p", "--purge", default="",
2306 action="store", type="string", dest="purge",
2307 help=_("Remove the given packages including "
2308- "configuration files").decode(enc))
2309+ "configuration files"))
2310 parser.add_option("-u", "--upgrade", default="",
2311 action="store", type="string", dest="upgrade",
2312- help=_("Install the given packages").decode(enc))
2313+ help=_("Install the given packages"))
2314 parser.add_option("", "--downgrade", default="",
2315 action="store", type="string", dest="downgrade",
2316- help=_("Downgrade the given packages").decode(enc))
2317+ help=_("Downgrade the given packages"))
2318 parser.add_option("", "--upgrade-system",
2319 action="store_true", dest="safe_upgrade",
2320 help=_("Deprecated: Please use "
2321- "--safe-upgrade").decode(enc))
2322+ "--safe-upgrade"))
2323 parser.add_option("", "--safe-upgrade",
2324 action="store_true", dest="safe_upgrade",
2325- help=_("Upgrade the system in a safe way").decode(enc))
2326+ help=_("Upgrade the system in a safe way"))
2327 parser.add_option("", "--full-upgrade",
2328 action="store_true", dest="full_upgrade",
2329 help=_("Upgrade the system, possibly installing and "
2330- "removing packages").decode(enc))
2331+ "removing packages"))
2332 parser.add_option("", "--add-vendor-key", default="",
2333 action="store", type="string", dest="add_vendor_key",
2334- help=_("Add the vendor to the trusted ones").decode(enc))
2335+ help=_("Add the vendor to the trusted ones"))
2336 parser.add_option("", "--add-vendor-key-from-keyserver", default="",
2337 action="store", type="string",
2338 help=_("Add the vendor keyid (also needs "
2339- "--keyserver)").decode(enc))
2340+ "--keyserver)"))
2341 parser.add_option("", "--keyserver", default="",
2342 action="store", type="string",
2343 help=_("Use the given keyserver for looking up "
2344- "keys").decode(enc))
2345+ "keys"))
2346 parser.add_option("", "--add-repository", default="",
2347 action="store", type="string", dest="add_repository",
2348 help=_("Add new repository from the given "
2349- "deb-line").decode(enc))
2350+ "deb-line"))
2351 parser.add_option("", "--sources-file", action="store", default="",
2352 type="string", dest="sources_file",
2353 help=_("Specify an alternative sources.list.d file to "
2354- "which repositories should be added.").decode(enc))
2355+ "which repositories should be added."))
2356 parser.add_option("", "--list-trusted-vendors", default="",
2357 action="store_true", dest="list_trusted_vendor_keys",
2358- help=_("List trusted vendor keys").decode(enc))
2359+ help=_("List trusted vendor keys"))
2360 parser.add_option("", "--remove-vendor-key", default="",
2361 action="store", type="string", dest="remove_vendor_key",
2362 help=_("Remove the trusted key of the given "
2363- "fingerprint").decode(enc))
2364+ "fingerprint"))
2365 parser.add_option("", "--clean",
2366 action="store_true", dest="clean",
2367- help=_("Remove downloaded package files").decode(enc))
2368+ help=_("Remove downloaded package files"))
2369 parser.add_option("", "--reconfigure", default="",
2370 action="store", type="string", dest="reconfigure",
2371 help=_("Reconfigure installed packages. Optionally the "
2372 "minimum priority of questions can be "
2373- "specified").decode(enc))
2374+ "specified"))
2375 parser.add_option("", "--priority", default="default",
2376 action="store", type="string", dest="priority",
2377 help=_("The minimum debconf priority of question to "
2378- "be displayed").decode(enc))
2379+ "be displayed"))
2380 parser.add_option("", "--hide-terminal",
2381 action="store_true", dest="hide_terminal",
2382- help=_("Do not attach to the apt terminal").decode(enc))
2383+ help=_("Do not attach to the apt terminal"))
2384 parser.add_option("", "--allow-unauthenticated",
2385 action="store_true", dest="allow_unauthenticated",
2386 default=False,
2387 help=_("Allow packages from unauthenticated "
2388- "sources").decode(enc))
2389+ "sources"))
2390 parser.add_option("-d", "--show-details",
2391 action="store_true", dest="details",
2392 help=_("Show additional information about the packages. "
2393- "Currently only the version number").decode(enc))
2394+ "Currently only the version number"))
2395 (options, args) = parser.parse_args()
2396 con = ConsoleClient(show_terminal=not options.hide_terminal,
2397 allow_unauthenticated=options.allow_unauthenticated,
2398
2399=== modified file 'aptdaemon/core.py'
2400--- aptdaemon/core.py 2012-04-09 20:48:44 +0000
2401+++ aptdaemon/core.py 2012-06-13 16:29:18 +0000
2402@@ -54,8 +54,8 @@
2403 import dbus.service
2404 import dbus.mainloop.glib
2405 import dbus.glib
2406-from softwareproperties.AptAuth import AptAuth
2407 import apt_pkg
2408+import apt.auth
2409
2410 from .config import ConfigWriter
2411 from . import errors
2412@@ -198,7 +198,7 @@
2413 xml = ElementTree.fromstring(data)
2414 for iface in xml.findall("interface"):
2415 props = self._get_properties(iface.attrib["name"])
2416- for key, value in props.iteritems():
2417+ for key, value in props.items():
2418 attrib = {"name": key}
2419 if key in self.WRITABLE_PROPERTIES:
2420 attrib["access"] = "readwrite"
2421@@ -346,7 +346,7 @@
2422 bus -- the DBus connection which should be used (defaults to system bus)
2423 """
2424 if tid is None:
2425- tid = uuid.uuid4().get_hex()
2426+ tid = uuid.uuid4().hex
2427 self.tid = "/org/debian/apt/transaction/%s" % tid
2428 if connect == True:
2429 self.bus = bus
2430@@ -380,9 +380,9 @@
2431 self._role = dbus.String(role)
2432 self._progress = dbus.Int32(0)
2433 # items_done, total_items, bytes_done, total_bytes, speed, time
2434- self._progress_details = dbus.Struct((0, 0, 0L, 0L, 0.0, 0L),
2435+ self._progress_details = dbus.Struct((0, 0, 0, 0, 0.0, 0),
2436 signature="iixxdx")
2437- self._progress_download = dbus.Struct(("", "", "", 0L, 0L, ""),
2438+ self._progress_download = dbus.Struct(("", "", "", 0, 0, ""),
2439 signature="sssxxs")
2440 self._progress_package = dbus.Struct(("", ""), signature="ss")
2441 self._exit = dbus.String(enums.EXIT_UNFINISHED)
2442@@ -485,7 +485,7 @@
2443 if not data.signature.startswith("s"):
2444 raise errors.InvalidMetaDataError("Only strings are accepted "
2445 "as keys.")
2446- for key, value in data.iteritems():
2447+ for key, value in data.items():
2448 if key in self._meta_data:
2449 raise errors.InvalidMetaDataError("The key %s already "
2450 "exists. It is not allowed "
2451@@ -1471,7 +1471,7 @@
2452 """Helper method which returns the tid of a new transaction."""
2453 pid, uid, cmdline = \
2454 yield policykit1.get_proc_info_from_dbus_name(sender, self.bus)
2455- tid = uuid.uuid4().get_hex()
2456+ tid = uuid.uuid4().hex
2457 trans = Transaction(tid, role, self.queue, pid, uid, cmdline, sender,
2458 packages=packages, kwargs=kwargs, bus=self.bus)
2459 self.queue.limbo[trans.tid] = trans
2460@@ -1926,11 +1926,11 @@
2461
2462 @inline_callbacks
2463 def _get_trusted_vendor_keys(self, sender):
2464- aptauth = AptAuth()
2465 action = policykit1.PK_ACTION_GET_TRUSTED_VENDOR_KEYS
2466 yield policykit1.check_authorization_by_name(sender, action,
2467 bus=self.bus)
2468- return_value([key.decode("utf-8", "ignore") for key in aptauth.list()])
2469+ fingerprints = [key.keyid for key in apt.auth.list_keys()]
2470+ return_value(fingerprints)
2471
2472 # pylint: disable-msg=C0103,C0322
2473 @dbus.service.method(APTDAEMON_DBUS_INTERFACE,
2474@@ -2144,40 +2144,40 @@
2475 default=False,
2476 action="store_true", dest="disable_timeout",
2477 help=_("Do not shutdown the daemon because of "
2478- "inactivity").decode(enc))
2479+ "inactivity"))
2480 parser.add_option("", "--disable-plugins",
2481 default=False,
2482 action="store_true", dest="disable_plugins",
2483- help=_("Do not load any plugins").decode(enc))
2484+ help=_("Do not load any plugins"))
2485 parser.add_option("-d", "--debug",
2486 default=False,
2487 action="store_true", dest="debug",
2488 help=_("Show internal processing "
2489- "information").decode(enc))
2490+ "information"))
2491 parser.add_option("-r", "--replace",
2492 default=False,
2493 action="store_true", dest="replace",
2494 help=_("Quit and replace an already running "
2495- "daemon").decode(enc))
2496+ "daemon"))
2497 parser.add_option("", "--session-bus",
2498 default=False,
2499 action="store_true", dest="session_bus",
2500 help=_("Listen on the DBus session bus (Only required "
2501- "for testing").decode(enc))
2502+ "for testing"))
2503 parser.add_option("", "--chroot", default=None,
2504 action="store", type="string", dest="chroot",
2505 help=_("Perform operations in the given "
2506- "chroot").decode(enc))
2507+ "chroot"))
2508 parser.add_option("-p", "--profile",
2509 default=False,
2510 action="store", type="string", dest="profile",
2511 help=_("Store profile stats in the specified "
2512- "file").decode(enc))
2513+ "file"))
2514 parser.add_option("--dummy",
2515 default=False,
2516 action="store_true", dest="dummy",
2517 help=_("Do not make any changes to the system (Only "
2518- "of use to developers)").decode(enc))
2519+ "of use to developers)"))
2520 options, args = parser.parse_args()
2521 if options.debug == True:
2522 log.setLevel(logging.DEBUG)
2523
2524=== modified file 'aptdaemon/errors.py'
2525--- aptdaemon/errors.py 2012-02-03 06:37:42 +0000
2526+++ aptdaemon/errors.py 2012-06-13 16:29:18 +0000
2527@@ -28,11 +28,15 @@
2528 "get_native_exception")
2529
2530 import inspect
2531+from functools import wraps
2532+import sys
2533+
2534 import dbus
2535-from functools import wraps
2536
2537 import aptdaemon.enums
2538
2539+PY3K = sys.version_info.major > 2
2540+
2541
2542 class AptDaemonError(dbus.DBusException):
2543
2544@@ -49,7 +53,10 @@
2545 """Overwrite the DBusException method, since it calls
2546 Exception.__str__() internally which doesn't support unicode or
2547 or non-ascii encodings."""
2548- return self._message.encode("UTF-8")
2549+ if PY3K:
2550+ return dbus.DBusException.get_dbus_message(self)
2551+ else:
2552+ return self._message.encode("UTF-8")
2553
2554
2555 class TransactionRoleAlreadySet(AptDaemonError):
2556@@ -101,7 +108,7 @@
2557
2558 def __str__(self):
2559 return "Transaction failed: %s\n%s" % \
2560- (aptdaemon.enums.get_role_error_from_enum(self.code),
2561+ (aptdaemon.enums.get_error_string_from_enum(self.code),
2562 self.details)
2563
2564
2565@@ -192,9 +199,7 @@
2566 if not isinstance(error, dbus.DBusException):
2567 return error
2568 dbus_name = error.get_dbus_name()
2569- # We have to use the deprecated message attribute to avoid encoding errors
2570- # See LP #846044
2571- dbus_msg = error.message
2572+ dbus_msg = error.get_dbus_message()
2573 if dbus_name == TransactionFailed._dbus_error_name:
2574 return TransactionFailed(*dbus_msg.split(":", 1))
2575 elif dbus_name == AuthorizationFailed._dbus_error_name:
2576@@ -211,7 +216,9 @@
2577
2578 def _convert_unicode(text, encoding="UTF-8"):
2579 """Always return an unicode."""
2580- if not isinstance(text, unicode):
2581+ if PY3K and not isinstance(text, str):
2582+ text = str(text, encoding, errors="ignore")
2583+ elif not PY3K and not isinstance(text, unicode):
2584 text = unicode(text, encoding, errors="ignore")
2585 return text
2586
2587
2588=== modified file 'aptdaemon/gtk3widgets.py'
2589--- aptdaemon/gtk3widgets.py 2012-03-14 13:26:31 +0000
2590+++ aptdaemon/gtk3widgets.py 2012-06-13 16:29:18 +0000
2591@@ -51,7 +51,7 @@
2592 _ = lambda msg: gettext.dgettext("aptdaemon", msg)
2593
2594 (COLUMN_ID,
2595- COLUMN_PACKAGE) = range(2)
2596+ COLUMN_PACKAGE) = list(range(2))
2597
2598
2599 class AptStatusIcon(Gtk.Image):
2600@@ -446,7 +446,7 @@
2601 of a transaction.
2602 """
2603
2604- COL_TEXT, COL_PROGRESS, COL_URI = range(3)
2605+ COL_TEXT, COL_PROGRESS, COL_URI = list(range(3))
2606
2607 def __init__(self, transaction=None):
2608 Gtk.TreeView.__init__(self)
2609@@ -484,7 +484,7 @@
2610 downloaded, message):
2611 """Callback for a changed download progress."""
2612 try:
2613- progress = downloaded * 100 / full_size
2614+ progress = int(downloaded * 100 / full_size)
2615 except ZeroDivisionError:
2616 progress = -1
2617 if status == DOWNLOAD_DONE:
2618
2619=== modified file 'aptdaemon/gtkwidgets.py'
2620--- aptdaemon/gtkwidgets.py 2012-02-03 06:37:42 +0000
2621+++ aptdaemon/gtkwidgets.py 2012-06-13 16:29:18 +0000
2622@@ -53,7 +53,7 @@
2623 _ = lambda msg: gettext.dgettext("aptdaemon", msg)
2624
2625 (COLUMN_ID,
2626- COLUMN_PACKAGE) = range(2)
2627+ COLUMN_PACKAGE) = list(range(2))
2628
2629
2630 class AptStatusIcon(gtk.Image):
2631@@ -440,7 +440,7 @@
2632 of a transaction.
2633 """
2634
2635- COL_TEXT, COL_PROGRESS, COL_URI = range(3)
2636+ COL_TEXT, COL_PROGRESS, COL_URI = list(range(3))
2637
2638 def __init__(self, transaction=None):
2639 gtk.TreeView.__init__(self)
2640
2641=== modified file 'aptdaemon/lock.py'
2642--- aptdaemon/lock.py 2012-03-14 13:26:31 +0000
2643+++ aptdaemon/lock.py 2012-06-13 16:29:18 +0000
2644@@ -110,7 +110,7 @@
2645 except IOError:
2646 return None
2647 finally:
2648- fd_lock_read
2649+ fd_lock_read.close()
2650 return None
2651
2652 apt_pkg.init()
2653
2654=== modified file 'aptdaemon/networking.py'
2655--- aptdaemon/networking.py 2012-05-11 15:56:04 +0000
2656+++ aptdaemon/networking.py 2012-06-13 16:29:18 +0000
2657@@ -33,7 +33,8 @@
2658 DBusGMainLoop(set_as_default=True)
2659 import logging
2660 import os
2661-import packagekit.enums as pk_enums
2662+
2663+from . import pkenums as pk_enums
2664
2665 log = logging.getLogger("AptDaemon.NetMonitor")
2666
2667@@ -259,7 +260,7 @@
2668 @inline_callbacks
2669 def _call_monitor():
2670 state = yield monitor.get_network_state()
2671- print("Initial network state: %s" % state)
2672+ print(("Initial network state: %s" % state))
2673 log_handler = logging.StreamHandler()
2674 log.addHandler(log_handler)
2675 log.setLevel(logging.DEBUG)
2676
2677=== modified file 'aptdaemon/pkcompat.py'
2678--- aptdaemon/pkcompat.py 2012-05-11 15:56:04 +0000
2679+++ aptdaemon/pkcompat.py 2012-06-13 16:29:18 +0000
2680@@ -37,7 +37,6 @@
2681 from defer.utils import dbus_deferred_method
2682 import dbus
2683 from gi.repository import GObject
2684-import packagekit.enums as pk_enums
2685
2686 # for optional plugin support
2687 try:
2688@@ -45,14 +44,15 @@
2689 except ImportError:
2690 pkg_resources = None
2691
2692-from aptdaemon import policykit1
2693-import aptdaemon.core
2694-from aptdaemon.core import APTDAEMON_TRANSACTION_DBUS_INTERFACE
2695-import aptdaemon.enums as aptd_enums
2696-from aptdaemon.errors import TransactionFailed, TransactionCancelled
2697-from aptdaemon.progress import DaemonAcquireProgress
2698-import aptdaemon.worker
2699-import aptdaemon.networking
2700+from . import policykit1
2701+from . import core
2702+from .core import APTDAEMON_TRANSACTION_DBUS_INTERFACE
2703+from . import enums as aptd_enums
2704+from .errors import TransactionFailed, TransactionCancelled
2705+from .progress import DaemonAcquireProgress
2706+from . import worker
2707+from . import networking
2708+from . import pkenums as pk_enums
2709
2710 GObject.threads_init()
2711
2712@@ -239,7 +239,7 @@
2713 }
2714
2715
2716-class PackageKit(aptdaemon.core.DBusObject):
2717+class PackageKit(core.DBusObject):
2718
2719 """Provides a limited set of the PackageKit system D-Bus API."""
2720
2721@@ -262,6 +262,8 @@
2722 pk_enums.ROLE_SEARCH_GROUP,
2723 pk_enums.ROLE_SEARCH_FILE,
2724 pk_enums.ROLE_WHAT_PROVIDES,
2725+ pk_enums.ROLE_REPO_ENABLE,
2726+ pk_enums.ROLE_INSTALL_SIGNATURE,
2727 pk_enums.ROLE_DOWNLOAD_PACKAGES]
2728 if META_RELEASE_SUPPORT:
2729 SUPPORTED_ROLES.append(pk_enums.ROLE_GET_DISTRO_UPGRADES)
2730@@ -294,14 +296,14 @@
2731 self.bus = bus
2732 bus_path = PACKAGEKIT_DBUS_PATH
2733 bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, self.bus)
2734- aptdaemon.core.DBusObject.__init__(self, bus_name, bus_path)
2735+ core.DBusObject.__init__(self, bus_name, bus_path)
2736 self._updates_changed_timeout_id = None
2737 self._updates_changed = False
2738 self.queue = queue
2739 self.queue.worker.connect("transaction-done", self._on_transaction_done)
2740 self.queue.connect("queue-changed", self._on_queue_changed)
2741 self._distro_id = None
2742- self.netmon = aptdaemon.networking.get_network_monitor()
2743+ self.netmon = networking.get_network_monitor()
2744 self.netmon.connect("network-state-changed",
2745 self._on_network_state_changed)
2746 self._get_network_state()
2747@@ -430,15 +432,15 @@
2748 def _get_properties(self, iface):
2749 """Helper to get the properties of a D-Bus interface."""
2750 if iface == PACKAGEKIT_DBUS_INTERFACE:
2751- return {# Claim that we are a stable version
2752- "VersionMajor": dbus.UInt32(6),
2753- "VersionMinor": dbus.UInt32(18),
2754+ return {# Claim that we are a current version
2755+ "VersionMajor": dbus.UInt32(7),
2756+ "VersionMinor": dbus.UInt32(4),
2757 "VersionMicro": dbus.UInt32(0),
2758 "BackendName": dbus.String("aptdaemon"),
2759 "BackendDescription": dbus.String("Compatibility layer"),
2760 "BackendAuthor": dbus.String(__author__),
2761 "Filters": dbus.String(";".join(self.SUPPORTED_FILTERS)),
2762- "Groups": dbus.String(";".join(SECTION_GROUP_MAP.values())),
2763+ "Groups": dbus.String(";".join(list(SECTION_GROUP_MAP.values()))),
2764 "Roles": dbus.String(";".join(self.SUPPORTED_ROLES)),
2765 "Locked": dbus.Boolean(False),
2766 "NetworkState": dbus.String(self.netmon.state),
2767@@ -460,7 +462,7 @@
2768 def _on_network_state_changed(self, mon, state):
2769 self.Changed()
2770 self.PropertiesChanged(PACKAGEKIT_DBUS_INTERFACE,
2771- {"Network": state}, [])
2772+ {"NetworkState": state}, [])
2773
2774 def _on_queue_changed(self, queue):
2775 self.TransactionListChanged(self._get_transaction_list())
2776@@ -522,7 +524,7 @@
2777 return False
2778
2779
2780-class MergedTransaction(aptdaemon.core.Transaction):
2781+class MergedTransaction(core.Transaction):
2782
2783 """Overlay of an Aptdaemon transaction which also provides the
2784 PackageKit object and its interfaces.
2785@@ -530,7 +532,7 @@
2786
2787 def __init__(self, pktrans, role, queue, connect=True,
2788 bus=None, packages=None, kwargs=None):
2789- aptdaemon.core.Transaction.__init__(self, pktrans.tid[1:], role, queue,
2790+ core.Transaction.__init__(self, pktrans.tid[1:], role, queue,
2791 pktrans.pid, pktrans.uid,
2792 pktrans.cmdline, pktrans.sender,
2793 connect, bus, packages, kwargs)
2794@@ -538,52 +540,52 @@
2795 self.run_time = 0
2796
2797 def _set_status(self, enum):
2798- aptdaemon.core.Transaction._set_status(self, enum)
2799+ core.Transaction._set_status(self, enum)
2800 self.pktrans.status = get_pk_status_enum(enum)
2801
2802- status = property(aptdaemon.core.Transaction._get_status, _set_status)
2803+ status = property(core.Transaction._get_status, _set_status)
2804
2805 def _set_progress(self, percent):
2806- aptdaemon.core.Transaction._set_progress(self, percent)
2807+ core.Transaction._set_progress(self, percent)
2808 self.pktrans.percentage = self._progress
2809
2810- progress = property(aptdaemon.core.Transaction._get_progress, _set_progress)
2811+ progress = property(core.Transaction._get_progress, _set_progress)
2812
2813 def _set_progress_details(self, details):
2814- aptdaemon.core.Transaction._set_progress_details(self, details)
2815+ core.Transaction._set_progress_details(self, details)
2816 self.pktrans.speed = int(details[4])
2817 self.pktrans.remaining_time = int(details[5])
2818 self.pktrans.elapsed_time = int(time.time() - self.pktrans.start_time)
2819
2820- progress_details = property(aptdaemon.core.Transaction._get_progress_details,
2821+ progress_details = property(core.Transaction._get_progress_details,
2822 _set_progress_details)
2823
2824 def _set_progress_package(self, progress):
2825- aptdaemon.core.Transaction._set_progress_package(self, progress)
2826+ core.Transaction._set_progress_package(self, progress)
2827 pkg_name, enum = progress
2828 self.emit_package(get_pk_package_enum(enum),
2829 get_pk_package_id(pkg_name),
2830 "")
2831
2832- progress_package = property(aptdaemon.core.Transaction._get_progress_package,
2833+ progress_package = property(core.Transaction._get_progress_package,
2834 _set_progress_package)
2835
2836
2837 def _set_exit(self, enum):
2838- aptdaemon.core.Transaction._set_exit(self, enum)
2839+ core.Transaction._set_exit(self, enum)
2840 self.pktrans.exit = get_pk_exit_enum(enum)
2841
2842- exit = property(aptdaemon.core.Transaction._get_exit, _set_exit)
2843+ exit = property(core.Transaction._get_exit, _set_exit)
2844
2845 def _set_error(self, excep):
2846- aptdaemon.core.Transaction._set_error(self, excep)
2847+ core.Transaction._set_error(self, excep)
2848 self.pktrans.ErrorCode(get_pk_error_enum(excep.code),
2849 self._error_property[1])
2850
2851- error = property(aptdaemon.core.Transaction._get_error, _set_error)
2852+ error = property(core.Transaction._get_error, _set_error)
2853
2854 def _remove_from_connection_no_raise(self):
2855- aptdaemon.core.Transaction._remove_from_connection_no_raise(self)
2856+ core.Transaction._remove_from_connection_no_raise(self)
2857 self.pktrans.Destroy()
2858 try:
2859 self.pktrans.remove_from_connection()
2860@@ -613,7 +615,7 @@
2861 changelog, state, issued, updated)
2862
2863
2864-class PackageKitTransaction(aptdaemon.core.DBusObject):
2865+class PackageKitTransaction(core.DBusObject):
2866
2867 """Provides a PackageKit transaction object."""
2868
2869@@ -622,14 +624,14 @@
2870 pklog.info("Initializing PackageKit transaction")
2871 bus_name = None
2872 bus_path = None
2873- self.tid = "/%s" % uuid.uuid4().get_hex()
2874+ self.tid = "/%s" % uuid.uuid4().hex
2875 if connect == True:
2876 if bus is None:
2877 bus = dbus.SystemBus()
2878 self.bus = bus
2879 bus_path = self.tid
2880 bus_name = dbus.service.BusName(PACKAGEKIT_DBUS_SERVICE, bus)
2881- aptdaemon.core.DBusObject.__init__(self, bus_name, bus_path)
2882+ core.DBusObject.__init__(self, bus_name, bus_path)
2883 self.queue = queue
2884 self.hints = {}
2885 self.start_time = time.time()
2886@@ -1745,9 +1747,9 @@
2887 self.role = pk_enums.ROLE_INSTALL_FILES
2888 GObject.idle_add(self._fail_not_implemented)
2889
2890- @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2891- in_signature="sss", out_signature="",
2892- sender_keyword="sender")
2893+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2894+ in_signature="sss", out_signature="",
2895+ sender_keyword="sender")
2896 def InstallSignature(self, sig_type, key_id, package_id, sender):
2897 """This method allows us to install new security keys.
2898
2899@@ -1755,9 +1757,13 @@
2900 :param key_id: A key ID, e.g. BB7576AC
2901 :param package_id:
2902 A PackageID for the package that the user is trying to install
2903+ (ignored)
2904 """
2905 self.role = pk_enums.ROLE_INSTALL_SIGNATURE
2906- GObject.idle_add(self._fail_not_implemented)
2907+ kwargs = {"sig_type": sig_type,
2908+ "key_id": key_id,
2909+ "package_id": package_id}
2910+ return self._run_query(kwargs, sender)
2911
2912 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2913 in_signature="sss", out_signature="",
2914@@ -1776,18 +1782,21 @@
2915 self.role = pk_enums.ROLE_REPO_SET_DATA
2916 GObject.idle_add(self._fail_not_implemented)
2917
2918- @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2919- in_signature="sb", out_signature="",
2920- sender_keyword="sender")
2921+ @dbus_deferred_method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2922+ in_signature="sb", out_signature="",
2923+ sender_keyword="sender")
2924 def RepoEnable(self, repo_id, enabled, sender):
2925 """This method enables the repository specified.
2926
2927 :param repo_id:
2928- A repository identifier, e.g. fedora-development-debuginfo
2929+ A repository identifier, e.g. fedora-development-debuginfo or an
2930+ apt source ("deb http://... unstable main")
2931 :param enabled: true if enabled, false if disabled.
2932 """
2933 self.role = pk_enums.ROLE_REPO_ENABLE
2934- GObject.idle_add(self._fail_not_implemented)
2935+ kwargs = {"repo_id": repo_id,
2936+ "enabled": enabled}
2937+ return self._run_query(kwargs, sender)
2938
2939 @dbus.service.method(PACKAGEKIT_TRANS_DBUS_INTERFACE,
2940 in_signature="s", out_signature="",
2941@@ -1889,7 +1898,7 @@
2942 # HELPERS
2943
2944 def _fail_not_implemented(self):
2945- self.ErrorCode(pk_enums.ERROR_NOT_SUPPORTED, "")
2946+ self.ErrorCode(pk_enums.ERROR_NOT_SUPPORTED, "Unimplemented method")
2947 self.exit = pk_enums.EXIT_FAILED
2948 return False
2949
2950@@ -1941,7 +1950,7 @@
2951 return trans
2952
2953
2954-class PackageKitWorker(aptdaemon.worker.AptWorker):
2955+class PackageKitWorker(worker.AptWorker):
2956
2957 _plugins = None
2958
2959@@ -1981,6 +1990,10 @@
2960 self.download_packages(trans, **trans.kwargs)
2961 elif trans.pktrans.role == pk_enums.ROLE_WHAT_PROVIDES:
2962 self.what_provides(trans, **trans.kwargs)
2963+ elif trans.pktrans.role == pk_enums.ROLE_REPO_ENABLE:
2964+ self.repo_enable(trans, **trans.kwargs)
2965+ elif trans.pktrans.role == pk_enums.ROLE_INSTALL_SIGNATURE:
2966+ self.install_signature(trans, **trans.kwargs)
2967 else:
2968 raise TransactionFailed(aptd_enums.ERROR_UNKNOWN,
2969 "Role %s isn't supported",
2970@@ -2063,7 +2076,7 @@
2971 pklog.info("Searching for package name: %s" % values)
2972 trans.progress = 101
2973
2974- for pkg_name in self._cache.keys():
2975+ for pkg_name in list(self._cache.keys()):
2976 if matches(values, pkg_name):
2977 self._emit_all_visible_pkg_versions(trans, filters,
2978 self._cache[pkg_name])
2979@@ -2082,7 +2095,7 @@
2980 db = xapian.Database(XAPIAN_DB)
2981 parser = xapian.QueryParser()
2982 parser.set_default_op(xapian.Query.OP_AND)
2983- query = parser.parse_query(u" ".join(values), search_flags)
2984+ query = parser.parse_query(" ".join(values), search_flags)
2985 enquire = xapian.Enquire(db)
2986 enquire.set_query(query)
2987 matches = enquire.get_mset(0, 1000)
2988@@ -2212,8 +2225,7 @@
2989 """
2990 Create a list of urls pointing to cves referred in the changelog
2991 """
2992- return map(lambda c: HREF_CVE % c,
2993- re.findall(MATCH_CVE, changelog, re.MULTILINE))
2994+ return [HREF_CVE % c for c in re.findall(MATCH_CVE, changelog, re.MULTILINE)]
2995
2996 pklog.info("Get update details of %s" % package_ids)
2997 trans.progress = 0
2998@@ -2239,7 +2251,7 @@
2999 obsoletes = ""
3000 vendor_url = ""
3001 restart = "none"
3002- update_text = u""
3003+ update_text = ""
3004 state = ""
3005 issued = ""
3006 updated = ""
3007@@ -2271,7 +2283,7 @@
3008 changelog_raw = pkg.get_changelog()
3009 # The internal download error string of python-apt ist not
3010 # provided as unicode object
3011- if not isinstance(changelog_raw, unicode):
3012+ if not isinstance(changelog_raw, str):
3013 changelog_raw = changelog_raw.decode("UTF-8")
3014 # Cache the fetched changelog
3015 if not os.path.exists(changelog_dir):
3016@@ -2286,24 +2298,24 @@
3017 finally:
3018 changelog_file.close()
3019 # Convert the changelog to markdown syntax
3020- changelog = u""
3021+ changelog = ""
3022 for line in changelog_raw.split("\n"):
3023 if line == "":
3024 changelog += " \n"
3025 else:
3026- changelog += u" %s \n" % line
3027+ changelog += " %s \n" % line
3028 if line.startswith(pkg.candidate.source_name):
3029 match = re.match(r"(?P<source>.+) \((?P<version>.*)\) "
3030 "(?P<dist>.+); urgency=(?P<urgency>.+)",
3031 line)
3032- update_text += u"%s\n%s\n\n" % (match.group("version"),
3033+ update_text += "%s\n%s\n\n" % (match.group("version"),
3034 "=" * \
3035 len(match.group("version")))
3036 elif line.startswith(" "):
3037- update_text += u" %s \n" % line
3038+ update_text += " %s \n" % line
3039 elif line.startswith(" --"):
3040 #FIXME: Add %z for the time zone - requires Python 2.6
3041- update_text += u" \n"
3042+ update_text += " \n"
3043 match = re.match("^ -- (?P<maintainer>.+) (?P<mail><.+>) "
3044 "(?P<date>.+) (?P<offset>[-\+][0-9]+)$",
3045 line)
3046@@ -2403,7 +2415,7 @@
3047 if not self._is_package_visible(pkg, filters):
3048 return
3049 else:
3050- summary = u""
3051+ summary = ""
3052 if base_dependency.relation:
3053 version = "%s%s" % (base_dependency.relation,
3054 base_dependency.version)
3055@@ -2557,10 +2569,7 @@
3056 trans.emit_files(id, files)
3057
3058 def what_provides(self, trans, filters, type, values):
3059- """Emit all dependencies of the given package ids.
3060-
3061- Doesn't support recursive dependency resolution.
3062- """
3063+ """Emit all packages which provide the given type and search value."""
3064 self._init_plugins()
3065
3066 supported_type = False
3067@@ -2581,6 +2590,34 @@
3068 raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
3069 "Query type '%s' is not supported" % type)
3070
3071+ def repo_enable(self, trans, repo_id, enabled):
3072+ """Enable or disable a repository."""
3073+
3074+ if not enabled:
3075+ raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
3076+ "Disabling repositories is not implemented")
3077+
3078+ fields = repo_id.split()
3079+ if len(fields) < 3 or fields[0] not in ('deb', 'deb-src'):
3080+ raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
3081+ "Unknown repository ID format: %s" % repo_id)
3082+
3083+ self.add_repository(trans, fields[0], fields[1], fields[2],
3084+ fields[3:], '', None)
3085+
3086+ def install_signature(self, trans, sig_type, key_id, package_id):
3087+ """Install an archive key."""
3088+ if sig_type != "gpg":
3089+ raise TransactionFailed(aptd_enums.ERROR_NOT_SUPPORTED,
3090+ "Type %s is not supported" % sig_type)
3091+ try:
3092+ keyserver = os.environ["APTDAEMON_KEYSERVER"]
3093+ except KeyError:
3094+ if platform.dist()[0] == "Ubuntu":
3095+ keyserver = "hkp://keyserver.ubuntu.com:80"
3096+ else:
3097+ keyserver = "hkp://keys.gnupg.net"
3098+ self.add_vendor_key_from_keyserver(trans, key_id, keyserver)
3099
3100 # Helpers
3101
3102@@ -2662,7 +2699,7 @@
3103 for name_raw in pkgs:
3104 #FIXME: Python-apt doesn't allow unicode as key. See #542965
3105 name = str(name_raw)
3106- if self._cache.has_key(name) and \
3107+ if name in self._cache and \
3108 self._is_package_visible(self._cache[name], filters):
3109 self._emit_package(trans, self._cache[name], info)
3110
3111@@ -2815,7 +2852,7 @@
3112 Return the packagekit group corresponding to the package's section
3113 """
3114 section = pkg.section.split("/")[-1]
3115- if SECTION_GROUP_MAP.has_key(section):
3116+ if section in SECTION_GROUP_MAP:
3117 return SECTION_GROUP_MAP[section]
3118 else:
3119 pklog.debug("Unkown package section %s of %s" % (pkg.section,
3120@@ -2855,9 +2892,9 @@
3121 def _apply_changes(self, trans, fetch_range=(15, 50),
3122 install_range=(50, 90)):
3123 """Apply changes and emit RequireRestart accordingly."""
3124- aptdaemon.worker.AptWorker._apply_changes(self, trans,
3125- fetch_range,
3126- install_range)
3127+ worker.AptWorker._apply_changes(self, trans,
3128+ fetch_range,
3129+ install_range)
3130 if (hasattr(trans, "pktrans") and
3131 (trans.role == aptd_enums.ROLE_UPGRADE_SYSTEM or
3132 trans.packages[aptd_enums.PKGS_UPGRADE] or
3133@@ -2923,8 +2960,7 @@
3134 e.g. xterm:i368=235; to xterm;235;i386;installed
3135 """
3136 #FIXME add arch support
3137- name, version, release = \
3138- aptdaemon.worker.AptWorker._split_package_id(pk_id)
3139+ name, version, release = worker.AptWorker._split_package_id(pk_id)
3140 try:
3141 name, arch = name.split(":", 1)
3142 except ValueError:
3143
3144=== added file 'aptdaemon/pkenums.py'
3145--- aptdaemon/pkenums.py 1970-01-01 00:00:00 +0000
3146+++ aptdaemon/pkenums.py 2012-06-13 16:29:18 +0000
3147@@ -0,0 +1,326 @@
3148+# This file was autogenerated from ../../../lib/packagekit-glib2/pk-enum.c by enum-converter.py
3149+
3150+class PackageKitEnum:
3151+ exit = ( "unknown", "success", "failed", "cancelled", "key-required", "eula-required", "media-change-required", "killed", "need-untrusted", "cancelled-priority", "skip-transaction", "repair-required", )
3152+ status = ( "unknown", "wait", "setup", "running", "query", "info", "refresh-cache", "remove", "download", "install", "update", "cleanup", "obsolete", "dep-resolve", "sig-check", "rollback", "test-commit", "commit", "request", "finished", "cancel", "download-repository", "download-packagelist", "download-filelist", "download-changelog", "download-group", "download-updateinfo", "repackaging", "loading-cache", "scan-applications", "generate-package-list", "waiting-for-lock", "waiting-for-auth", "scan-process-list", "check-executable-files", "check-libraries", "copy-files", )
3153+ role = ( "unknown", "cancel", "get-depends", "get-details", "get-files", "get-packages", "get-repo-list", "get-requires", "get-update-detail", "get-updates", "install-files", "install-packages", "install-signature", "refresh-cache", "remove-packages", "repo-enable", "repo-set-data", "resolve", "rollback", "search-details", "search-file", "search-group", "search-name", "update-packages", "update-system", "what-provides", "accept-eula", "download-packages", "get-distro-upgrades", "get-categories", "get-old-transactions", "simulate-install-files", "simulate-install-packages", "simulate-remove-packages", "simulate-update-packages", "upgrade-system", "repair-system", "simulate-repair-system", )
3154+ error = ( "unknown", "out-of-memory", "no-cache", "no-network", "not-supported", "internal-error", "gpg-failure", "filter-invalid", "package-id-invalid", "transaction-error", "transaction-cancelled", "package-not-installed", "package-not-found", "package-already-installed", "package-download-failed", "group-not-found", "group-list-invalid", "dep-resolution-failed", "create-thread-failed", "repo-not-found", "cannot-remove-system-package", "process-kill", "failed-initialization", "failed-finalise", "failed-config-parsing", "cannot-cancel", "cannot-get-lock", "no-packages-to-update", "cannot-write-repo-config", "local-install-failed", "bad-gpg-signature", "missing-gpg-signature", "cannot-install-source-package", "repo-configuration-error", "no-license-agreement", "file-conflicts", "package-conflicts", "repo-not-available", "invalid-package-file", "package-install-blocked", "package-corrupt", "all-packages-already-installed", "file-not-found", "no-more-mirrors-to-try", "no-distro-upgrade-data", "incompatible-architecture", "no-space-on-device", "media-change-required", "not-authorized", "update-not-found", "cannot-install-repo-unsigned", "cannot-update-repo-unsigned", "cannot-get-filelist", "cannot-get-requires", "cannot-disable-repository", "restricted-download", "package-failed-to-configure", "package-failed-to-build", "package-failed-to-install", "package-failed-to-remove", "failed-due-to-running-process", "package-database-changed", "provide-type-not-supported", "install-root-invalid", "cannot-fetch-sources", "cancelled-priority", "unfinished-transaction", )
3155+ restart = ( "unknown", "none", "system", "session", "application", "security-system", "security-session", )
3156+ message = ( "unknown", "broken-mirror", "connection-refused", "parameter-invalid", "priority-invalid", "backend-error", "daemon-error", "cache-being-rebuilt", "untrusted-package", "newer-package-exists", "could-not-find-package", "config-files-changed", "package-already-installed", "autoremove-ignored", "repo-metadata-download-failed", "repo-for-developers-only", "other-updates-held-back", )
3157+ filter = ( "unknown", "none", "installed", "~installed", "devel", "~devel", "gui", "~gui", "free", "~free", "visible", "~visible", "supported", "~supported", "basename", "~basename", "newest", "~newest", "arch", "~arch", "source", "~source", "collections", "~collections", "application", "~application", )
3158+ group = ( "unknown", "accessibility", "accessories", "education", "games", "graphics", "internet", "office", "other", "programming", "multimedia", "system", "desktop-gnome", "desktop-kde", "desktop-xfce", "desktop-other", "publishing", "servers", "fonts", "admin-tools", "legacy", "localization", "virtualization", "power-management", "security", "communication", "network", "maps", "repos", "science", "documentation", "electronics", "collections", "vendor", "newest", )
3159+ update_state = ( "unknown", "testing", "unstable", "stable", )
3160+ info = ( "unknown", "installed", "available", "low", "normal", "important", "security", "bugfix", "enhancement", "blocked", "downloading", "updating", "installing", "removing", "cleanup", "obsoleting", "collection-installed", "collection-available", "finished", "reinstalling", "downgrading", "preparing", "decompressing", "untrusted", "trusted", )
3161+ sig_type = ( "unknown", "gpg", )
3162+ upgrade = ( "unknown", "stable", "unstable", )
3163+ provides = ( "unknown", "any", "modalias", "codec", "mimetype", "driver", "font", "postscript-driver", "plasma-service", "shared-library", "python-module", "language-support", )
3164+ network = ( "unknown", "offline", "online", "wired", "wifi", "mobile", )
3165+ media_type = ( "unknown", "cd", "dvd", "disc", )
3166+ authorize_type = ( "unknown", "yes", "no", "interactive", )
3167+ upgrade_kind = ( "unknown", "minimal", "default", "complete", )
3168+
3169+# Constants
3170+
3171+AUTHORIZE_INTERACTIVE = "interactive"
3172+AUTHORIZE_NO = "no"
3173+AUTHORIZE_UNKNOWN = "unknown"
3174+AUTHORIZE_YES = "yes"
3175+DISTRO_UPGRADE_STABLE = "stable"
3176+DISTRO_UPGRADE_UNKNOWN = "unknown"
3177+DISTRO_UPGRADE_UNSTABLE = "unstable"
3178+ERROR_ALL_PACKAGES_ALREADY_INSTALLED = "all-packages-already-installed"
3179+ERROR_BAD_GPG_SIGNATURE = "bad-gpg-signature"
3180+ERROR_CANCELLED_PRIORITY = "cancelled-priority"
3181+ERROR_CANNOT_CANCEL = "cannot-cancel"
3182+ERROR_CANNOT_DISABLE_REPOSITORY = "cannot-disable-repository"
3183+ERROR_CANNOT_FETCH_SOURCES = "cannot-fetch-sources"
3184+ERROR_CANNOT_GET_FILELIST = "cannot-get-filelist"
3185+ERROR_CANNOT_GET_LOCK = "cannot-get-lock"
3186+ERROR_CANNOT_GET_REQUIRES = "cannot-get-requires"
3187+ERROR_CANNOT_INSTALL_REPO_UNSIGNED = "cannot-install-repo-unsigned"
3188+ERROR_CANNOT_INSTALL_SOURCE_PACKAGE = "cannot-install-source-package"
3189+ERROR_CANNOT_REMOVE_SYSTEM_PACKAGE = "cannot-remove-system-package"
3190+ERROR_CANNOT_UPDATE_REPO_UNSIGNED = "cannot-update-repo-unsigned"
3191+ERROR_CANNOT_WRITE_REPO_CONFIG = "cannot-write-repo-config"
3192+ERROR_CREATE_THREAD_FAILED = "create-thread-failed"
3193+ERROR_DEP_RESOLUTION_FAILED = "dep-resolution-failed"
3194+ERROR_FAILED_CONFIG_PARSING = "failed-config-parsing"
3195+ERROR_FAILED_FINALISE = "failed-finalise"
3196+ERROR_FAILED_INITIALIZATION = "failed-initialization"
3197+ERROR_FILE_CONFLICTS = "file-conflicts"
3198+ERROR_FILE_NOT_FOUND = "file-not-found"
3199+ERROR_FILTER_INVALID = "filter-invalid"
3200+ERROR_GPG_FAILURE = "gpg-failure"
3201+ERROR_GROUP_LIST_INVALID = "group-list-invalid"
3202+ERROR_GROUP_NOT_FOUND = "group-not-found"
3203+ERROR_INCOMPATIBLE_ARCHITECTURE = "incompatible-architecture"
3204+ERROR_INSTALL_ROOT_INVALID = "install-root-invalid"
3205+ERROR_INTERNAL_ERROR = "internal-error"
3206+ERROR_INVALID_PACKAGE_FILE = "invalid-package-file"
3207+ERROR_LOCAL_INSTALL_FAILED = "local-install-failed"
3208+ERROR_MEDIA_CHANGE_REQUIRED = "media-change-required"
3209+ERROR_MISSING_GPG_SIGNATURE = "missing-gpg-signature"
3210+ERROR_NOT_AUTHORIZED = "not-authorized"
3211+ERROR_NOT_SUPPORTED = "not-supported"
3212+ERROR_NO_CACHE = "no-cache"
3213+ERROR_NO_DISTRO_UPGRADE_DATA = "no-distro-upgrade-data"
3214+ERROR_NO_LICENSE_AGREEMENT = "no-license-agreement"
3215+ERROR_NO_MORE_MIRRORS_TO_TRY = "no-more-mirrors-to-try"
3216+ERROR_NO_NETWORK = "no-network"
3217+ERROR_NO_PACKAGES_TO_UPDATE = "no-packages-to-update"
3218+ERROR_NO_SPACE_ON_DEVICE = "no-space-on-device"
3219+ERROR_OOM = "out-of-memory"
3220+ERROR_PACKAGE_ALREADY_INSTALLED = "package-already-installed"
3221+ERROR_PACKAGE_CONFLICTS = "package-conflicts"
3222+ERROR_PACKAGE_CORRUPT = "package-corrupt"
3223+ERROR_PACKAGE_DATABASE_CHANGED = "package-database-changed"
3224+ERROR_PACKAGE_DOWNLOAD_FAILED = "package-download-failed"
3225+ERROR_PACKAGE_FAILED_TO_BUILD = "package-failed-to-build"
3226+ERROR_PACKAGE_FAILED_TO_CONFIGURE = "package-failed-to-configure"
3227+ERROR_PACKAGE_FAILED_TO_INSTALL = "package-failed-to-install"
3228+ERROR_PACKAGE_FAILED_TO_REMOVE = "package-failed-to-remove"
3229+ERROR_PACKAGE_ID_INVALID = "package-id-invalid"
3230+ERROR_PACKAGE_INSTALL_BLOCKED = "package-install-blocked"
3231+ERROR_PACKAGE_NOT_FOUND = "package-not-found"
3232+ERROR_PACKAGE_NOT_INSTALLED = "package-not-installed"
3233+ERROR_PROCESS_KILL = "process-kill"
3234+ERROR_PROVIDE_TYPE_NOT_SUPPORTED = "provide-type-not-supported"
3235+ERROR_REPO_CONFIGURATION_ERROR = "repo-configuration-error"
3236+ERROR_REPO_NOT_AVAILABLE = "repo-not-available"
3237+ERROR_REPO_NOT_FOUND = "repo-not-found"
3238+ERROR_RESTRICTED_DOWNLOAD = "restricted-download"
3239+ERROR_TRANSACTION_CANCELLED = "transaction-cancelled"
3240+ERROR_TRANSACTION_ERROR = "transaction-error"
3241+ERROR_UNFINISHED_TRANSACTION = "unfinished-transaction"
3242+ERROR_UNKNOWN = "unknown"
3243+ERROR_UPDATE_FAILED_DUE_TO_RUNNING_PROCESS = "failed-due-to-running-process"
3244+ERROR_UPDATE_NOT_FOUND = "update-not-found"
3245+EXIT_CANCELLED = "cancelled"
3246+EXIT_CANCELLED_PRIORITY = "cancelled-priority"
3247+EXIT_EULA_REQUIRED = "eula-required"
3248+EXIT_FAILED = "failed"
3249+EXIT_KEY_REQUIRED = "key-required"
3250+EXIT_KILLED = "killed"
3251+EXIT_MEDIA_CHANGE_REQUIRED = "media-change-required"
3252+EXIT_NEED_UNTRUSTED = "need-untrusted"
3253+EXIT_REPAIR_REQUIRED = "repair-required"
3254+EXIT_SKIP_TRANSACTION = "skip-transaction"
3255+EXIT_SUCCESS = "success"
3256+EXIT_UNKNOWN = "unknown"
3257+FILTER_APPLICATION = "application"
3258+FILTER_ARCH = "arch"
3259+FILTER_BASENAME = "basename"
3260+FILTER_COLLECTIONS = "collections"
3261+FILTER_DEVELOPMENT = "devel"
3262+FILTER_FREE = "free"
3263+FILTER_GUI = "gui"
3264+FILTER_INSTALLED = "installed"
3265+FILTER_NEWEST = "newest"
3266+FILTER_NONE = "none"
3267+FILTER_NOT_APPLICATION = "~application"
3268+FILTER_NOT_ARCH = "~arch"
3269+FILTER_NOT_BASENAME = "~basename"
3270+FILTER_NOT_COLLECTIONS = "~collections"
3271+FILTER_NOT_DEVELOPMENT = "~devel"
3272+FILTER_NOT_FREE = "~free"
3273+FILTER_NOT_GUI = "~gui"
3274+FILTER_NOT_INSTALLED = "~installed"
3275+FILTER_NOT_NEWEST = "~newest"
3276+FILTER_NOT_SOURCE = "~source"
3277+FILTER_NOT_SUPPORTED = "~supported"
3278+FILTER_NOT_VISIBLE = "~visible"
3279+FILTER_SOURCE = "source"
3280+FILTER_SUPPORTED = "supported"
3281+FILTER_UNKNOWN = "unknown"
3282+FILTER_VISIBLE = "visible"
3283+GROUP_ACCESSIBILITY = "accessibility"
3284+GROUP_ACCESSORIES = "accessories"
3285+GROUP_ADMIN_TOOLS = "admin-tools"
3286+GROUP_COLLECTIONS = "collections"
3287+GROUP_COMMUNICATION = "communication"
3288+GROUP_DESKTOP_GNOME = "desktop-gnome"
3289+GROUP_DESKTOP_KDE = "desktop-kde"
3290+GROUP_DESKTOP_OTHER = "desktop-other"
3291+GROUP_DESKTOP_XFCE = "desktop-xfce"
3292+GROUP_DOCUMENTATION = "documentation"
3293+GROUP_EDUCATION = "education"
3294+GROUP_ELECTRONICS = "electronics"
3295+GROUP_FONTS = "fonts"
3296+GROUP_GAMES = "games"
3297+GROUP_GRAPHICS = "graphics"
3298+GROUP_INTERNET = "internet"
3299+GROUP_LEGACY = "legacy"
3300+GROUP_LOCALIZATION = "localization"
3301+GROUP_MAPS = "maps"
3302+GROUP_MULTIMEDIA = "multimedia"
3303+GROUP_NETWORK = "network"
3304+GROUP_NEWEST = "newest"
3305+GROUP_OFFICE = "office"
3306+GROUP_OTHER = "other"
3307+GROUP_POWER_MANAGEMENT = "power-management"
3308+GROUP_PROGRAMMING = "programming"
3309+GROUP_PUBLISHING = "publishing"
3310+GROUP_REPOS = "repos"
3311+GROUP_SCIENCE = "science"
3312+GROUP_SECURITY = "security"
3313+GROUP_SERVERS = "servers"
3314+GROUP_SYSTEM = "system"
3315+GROUP_UNKNOWN = "unknown"
3316+GROUP_VENDOR = "vendor"
3317+GROUP_VIRTUALIZATION = "virtualization"
3318+INFO_AVAILABLE = "available"
3319+INFO_BLOCKED = "blocked"
3320+INFO_BUGFIX = "bugfix"
3321+INFO_CLEANUP = "cleanup"
3322+INFO_COLLECTION_AVAILABLE = "collection-available"
3323+INFO_COLLECTION_INSTALLED = "collection-installed"
3324+INFO_DECOMPRESSING = "decompressing"
3325+INFO_DOWNGRADING = "downgrading"
3326+INFO_DOWNLOADING = "downloading"
3327+INFO_ENHANCEMENT = "enhancement"
3328+INFO_FINISHED = "finished"
3329+INFO_IMPORTANT = "important"
3330+INFO_INSTALLED = "installed"
3331+INFO_INSTALLING = "installing"
3332+INFO_LOW = "low"
3333+INFO_NORMAL = "normal"
3334+INFO_OBSOLETING = "obsoleting"
3335+INFO_PREPARING = "preparing"
3336+INFO_REINSTALLING = "reinstalling"
3337+INFO_REMOVING = "removing"
3338+INFO_SECURITY = "security"
3339+INFO_TRUSTED = "trusted"
3340+INFO_UNKNOWN = "unknown"
3341+INFO_UNTRUSTED = "untrusted"
3342+INFO_UPDATING = "updating"
3343+MEDIA_TYPE_CD = "cd"
3344+MEDIA_TYPE_DISC = "disc"
3345+MEDIA_TYPE_DVD = "dvd"
3346+MEDIA_TYPE_UNKNOWN = "unknown"
3347+MESSAGE_AUTOREMOVE_IGNORED = "autoremove-ignored"
3348+MESSAGE_BACKEND_ERROR = "backend-error"
3349+MESSAGE_BROKEN_MIRROR = "broken-mirror"
3350+MESSAGE_CACHE_BEING_REBUILT = "cache-being-rebuilt"
3351+MESSAGE_CONFIG_FILES_CHANGED = "config-files-changed"
3352+MESSAGE_CONNECTION_REFUSED = "connection-refused"
3353+MESSAGE_COULD_NOT_FIND_PACKAGE = "could-not-find-package"
3354+MESSAGE_DAEMON_ERROR = "daemon-error"
3355+MESSAGE_NEWER_PACKAGE_EXISTS = "newer-package-exists"
3356+MESSAGE_OTHER_UPDATES_HELD_BACK = "other-updates-held-back"
3357+MESSAGE_PACKAGE_ALREADY_INSTALLED = "package-already-installed"
3358+MESSAGE_PARAMETER_INVALID = "parameter-invalid"
3359+MESSAGE_PRIORITY_INVALID = "priority-invalid"
3360+MESSAGE_REPO_FOR_DEVELOPERS_ONLY = "repo-for-developers-only"
3361+MESSAGE_REPO_METADATA_DOWNLOAD_FAILED = "repo-metadata-download-failed"
3362+MESSAGE_UNKNOWN = "unknown"
3363+MESSAGE_UNTRUSTED_PACKAGE = "untrusted-package"
3364+NETWORK_MOBILE = "mobile"
3365+NETWORK_OFFLINE = "offline"
3366+NETWORK_ONLINE = "online"
3367+NETWORK_UNKNOWN = "unknown"
3368+NETWORK_WIFI = "wifi"
3369+NETWORK_WIRED = "wired"
3370+PROVIDES_ANY = "any"
3371+PROVIDES_CODEC = "codec"
3372+PROVIDES_FONT = "font"
3373+PROVIDES_HARDWARE_DRIVER = "driver"
3374+PROVIDES_LANGUAGE_SUPPORT = "language-support"
3375+PROVIDES_MIMETYPE = "mimetype"
3376+PROVIDES_MODALIAS = "modalias"
3377+PROVIDES_PLASMA_SERVICE = "plasma-service"
3378+PROVIDES_POSTSCRIPT_DRIVER = "postscript-driver"
3379+PROVIDES_PYTHON = "python-module"
3380+PROVIDES_SHARED_LIB = "shared-library"
3381+PROVIDES_UNKNOWN = "unknown"
3382+RESTART_APPLICATION = "application"
3383+RESTART_NONE = "none"
3384+RESTART_SECURITY_SESSION = "security-session"
3385+RESTART_SECURITY_SYSTEM = "security-system"
3386+RESTART_SESSION = "session"
3387+RESTART_SYSTEM = "system"
3388+RESTART_UNKNOWN = "unknown"
3389+ROLE_ACCEPT_EULA = "accept-eula"
3390+ROLE_CANCEL = "cancel"
3391+ROLE_DOWNLOAD_PACKAGES = "download-packages"
3392+ROLE_GET_CATEGORIES = "get-categories"
3393+ROLE_GET_DEPENDS = "get-depends"
3394+ROLE_GET_DETAILS = "get-details"
3395+ROLE_GET_DISTRO_UPGRADES = "get-distro-upgrades"
3396+ROLE_GET_FILES = "get-files"
3397+ROLE_GET_OLD_TRANSACTIONS = "get-old-transactions"
3398+ROLE_GET_PACKAGES = "get-packages"
3399+ROLE_GET_REPO_LIST = "get-repo-list"
3400+ROLE_GET_REQUIRES = "get-requires"
3401+ROLE_GET_UPDATES = "get-updates"
3402+ROLE_GET_UPDATE_DETAIL = "get-update-detail"
3403+ROLE_INSTALL_FILES = "install-files"
3404+ROLE_INSTALL_PACKAGES = "install-packages"
3405+ROLE_INSTALL_SIGNATURE = "install-signature"
3406+ROLE_REFRESH_CACHE = "refresh-cache"
3407+ROLE_REMOVE_PACKAGES = "remove-packages"
3408+ROLE_REPAIR_SYSTEM = "repair-system"
3409+ROLE_REPO_ENABLE = "repo-enable"
3410+ROLE_REPO_SET_DATA = "repo-set-data"
3411+ROLE_RESOLVE = "resolve"
3412+ROLE_ROLLBACK = "rollback"
3413+ROLE_SEARCH_DETAILS = "search-details"
3414+ROLE_SEARCH_FILE = "search-file"
3415+ROLE_SEARCH_GROUP = "search-group"
3416+ROLE_SEARCH_NAME = "search-name"
3417+ROLE_SIMULATE_INSTALL_FILES = "simulate-install-files"
3418+ROLE_SIMULATE_INSTALL_PACKAGES = "simulate-install-packages"
3419+ROLE_SIMULATE_REMOVE_PACKAGES = "simulate-remove-packages"
3420+ROLE_SIMULATE_REPAIR_SYSTEM = "simulate-repair-system"
3421+ROLE_SIMULATE_UPDATE_PACKAGES = "simulate-update-packages"
3422+ROLE_UNKNOWN = "unknown"
3423+ROLE_UPDATE_PACKAGES = "update-packages"
3424+ROLE_UPDATE_SYSTEM = "update-system"
3425+ROLE_UPGRADE_SYSTEM = "upgrade-system"
3426+ROLE_WHAT_PROVIDES = "what-provides"
3427+SIGTYPE_GPG = "gpg"
3428+SIGTYPE_UNKNOWN = "unknown"
3429+STATUS_CANCEL = "cancel"
3430+STATUS_CHECK_EXECUTABLE_FILES = "check-executable-files"
3431+STATUS_CHECK_LIBRARIES = "check-libraries"
3432+STATUS_CLEANUP = "cleanup"
3433+STATUS_COMMIT = "commit"
3434+STATUS_COPY_FILES = "copy-files"
3435+STATUS_DEP_RESOLVE = "dep-resolve"
3436+STATUS_DOWNLOAD = "download"
3437+STATUS_DOWNLOAD_CHANGELOG = "download-changelog"
3438+STATUS_DOWNLOAD_FILELIST = "download-filelist"
3439+STATUS_DOWNLOAD_GROUP = "download-group"
3440+STATUS_DOWNLOAD_PACKAGELIST = "download-packagelist"
3441+STATUS_DOWNLOAD_REPOSITORY = "download-repository"
3442+STATUS_DOWNLOAD_UPDATEINFO = "download-updateinfo"
3443+STATUS_FINISHED = "finished"
3444+STATUS_GENERATE_PACKAGE_LIST = "generate-package-list"
3445+STATUS_INFO = "info"
3446+STATUS_INSTALL = "install"
3447+STATUS_LOADING_CACHE = "loading-cache"
3448+STATUS_OBSOLETE = "obsolete"
3449+STATUS_QUERY = "query"
3450+STATUS_REFRESH_CACHE = "refresh-cache"
3451+STATUS_REMOVE = "remove"
3452+STATUS_REPACKAGING = "repackaging"
3453+STATUS_REQUEST = "request"
3454+STATUS_ROLLBACK = "rollback"
3455+STATUS_RUNNING = "running"
3456+STATUS_SCAN_APPLICATIONS = "scan-applications"
3457+STATUS_SCAN_PROCESS_LIST = "scan-process-list"
3458+STATUS_SETUP = "setup"
3459+STATUS_SIG_CHECK = "sig-check"
3460+STATUS_TEST_COMMIT = "test-commit"
3461+STATUS_UNKNOWN = "unknown"
3462+STATUS_UPDATE = "update"
3463+STATUS_WAIT = "wait"
3464+STATUS_WAITING_FOR_AUTH = "waiting-for-auth"
3465+STATUS_WAITING_FOR_LOCK = "waiting-for-lock"
3466+UPDATE_STATE_STABLE = "stable"
3467+UPDATE_STATE_TESTING = "testing"
3468+UPDATE_STATE_UNKNOWN = "unknown"
3469+UPDATE_STATE_UNSTABLE = "unstable"
3470+UPGRADE_KIND_COMPLETE = "complete"
3471+UPGRADE_KIND_DEFAULT = "default"
3472+UPGRADE_KIND_MINIMAL = "minimal"
3473+UPGRADE_KIND_UNKNOWN = "unknown"
3474
3475=== modified file 'aptdaemon/policykit1.py'
3476--- aptdaemon/policykit1.py 2012-02-03 06:37:42 +0000
3477+++ aptdaemon/policykit1.py 2012-06-13 16:29:18 +0000
3478@@ -91,7 +91,8 @@
3479 return _check_authorization(subject, action_id, timeout, bus, flags)
3480
3481 def _check_authorization(subject, action_id, timeout, bus, flags=None):
3482- def policykit_done((authorized, challenged, auth_details)):
3483+ def policykit_done(xxx_todo_changeme):
3484+ (authorized, challenged, auth_details) = xxx_todo_changeme
3485 if authorized:
3486 deferred.callback(auth_details)
3487 elif challenged:
3488
3489=== modified file 'aptdaemon/progress.py'
3490--- aptdaemon/progress.py 2012-04-09 20:48:44 +0000
3491+++ aptdaemon/progress.py 2012-06-13 16:29:18 +0000
3492@@ -231,7 +231,7 @@
3493
3494 def stop(self):
3495 """Callback at the end of the operation"""
3496- self.transaction.progress_details = (0, 0, 0L, 0L, 0.0, 0L)
3497+ self.transaction.progress_details = (0, 0, 0, 0, 0.0, 0)
3498 self.transaction.progress = self.progress_end
3499 self.transaction.cancellable = False
3500
3501@@ -370,7 +370,16 @@
3502 msg
3503
3504
3505-class DaemonInstallProgress(object):
3506+class DaemonForkProgress(object):
3507+
3508+ """Forks and executes a given method in the child process while
3509+ monitoring the output and return state.
3510+
3511+ During the run() call the mainloop will be iterated.
3512+
3513+ Furthermore a status file descriptor is available to communicate
3514+ with the child process.
3515+ """
3516
3517 def __init__(self, transaction, begin=50, end=100):
3518 self.transaction = transaction
3519@@ -385,9 +394,15 @@
3520 self.output = ""
3521 self._line_buffer = ""
3522
3523+ def __enter__(self):
3524+ self.start_update()
3525+ return self
3526+
3527+ def __exit__(self, etype, evalue, etb):
3528+ self.finish_update()
3529+
3530 def start_update(self):
3531 log.debug("Start update")
3532- lock.status_lock.release()
3533 self.transaction.status = enums.STATUS_COMMITTING
3534 self.transaction.term_attached = True
3535 self.last_activity = time.time()
3536@@ -396,17 +411,21 @@
3537 def finish_update(self):
3538 """Callback at the end of the operation"""
3539 self.transaction.term_attached = False
3540- lock.wait_for_lock(self.transaction, lock.status_lock)
3541-
3542- def _child(self, pm):
3543- try:
3544- res = pm.do_install(self.status_child_fd)
3545- except:
3546- os._exit(apt_pkg.PackageManager.RESULT_FAILED)
3547- else:
3548- os._exit(res)
3549+
3550+ def _child(self, method, *args):
3551+ """Call the given method or function with the
3552+ corrsponding arguments in the child process.
3553+
3554+ This method should be replace in subclasses.
3555+ """
3556+ method(*args)
3557+ time.sleep(0.5)
3558+ os._exit(0)
3559
3560 def run(self, *args, **kwargs):
3561+ """Setup monitoring, fork and call the self._child() method in the
3562+ child process with the given arguments.
3563+ """
3564 log.debug("Run")
3565 terminal_fd = None
3566 if self.transaction.terminal:
3567@@ -477,68 +496,14 @@
3568 return False
3569
3570 def _on_status_update(self, source, condition):
3571- log.debug("UpdateInterface")
3572- status_msg = ""
3573- try:
3574- while not status_msg.endswith("\n"):
3575- self.last_activity = time.time()
3576- status_msg += os.read(source, 1)
3577- except:
3578- return False
3579- try:
3580- (status, pkg, percent, message_raw) = status_msg.split(":", 3)
3581- except ValueError:
3582- # silently ignore lines that can't be parsed
3583- return True
3584- message = message_raw.strip()
3585- #print "percent: %s %s" % (pkg, float(percent)/100.0)
3586- if status == "pmerror":
3587- self._error(pkg, message)
3588- elif status == "pmconffile":
3589- # we get a string like this:
3590- # 'current-conffile' 'new-conffile' useredited distedited
3591- match = re.match("\s*\'(.*)\'\s*\'(.*)\'.*", message_raw)
3592- if match:
3593- new, old = match.group(1), match.group(2)
3594- self._conffile(new, old)
3595- elif status == "pmstatus":
3596- if message.startswith("Installing"):
3597- status_enum = enums.PKG_INSTALLING
3598- elif message.startswith("Installed"):
3599- status_enum = enums.PKG_INSTALLED
3600- elif message.startswith("Configuring"):
3601- status_enum = enums.PKG_CONFIGURING
3602- elif message.startswith("Preparing to configure"):
3603- status_enum = enums.PKG_PREPARING_CONFIGURE
3604- elif message.startswith("Preparing for removal of"):
3605- status_enum = enums.PKG_PREPARING_REMOVE
3606- elif message.startswith("Removing"):
3607- status_enum = enums.PKG_REMOVING
3608- elif message.startswith("Removed"):
3609- status_enum = enums.PKG_REMOVED
3610- elif message.startswith("Preparing to completely remove"):
3611- status_enum = enums.PKG_PREPARING_PURGE
3612- elif message.startswith("Completely removing"):
3613- status_enum = enums.PKG_PURGING
3614- elif message.startswith("Completely removed"):
3615- status_enum = enums.PKG_PURGED
3616- elif message.startswith("Unpacking"):
3617- status_enum = enums.PKG_UNPACKING
3618- elif message.startswith("Preparing"):
3619- status_enum = enums.PKG_PREPARING_INSTALL
3620- elif message.startswith("Noting disappearance of"):
3621- status_enum = enums.PKG_DISAPPEARING
3622- elif message.startswith("Running"):
3623- status_enum = enums.PKG_RUNNING_TRIGGER
3624- else:
3625- status_enum = enums.PKG_UNKNOWN
3626- self._status_changed(pkg, float(percent), status_enum)
3627- # catch a time out by sending crtl+c
3628- if self.last_activity + INSTALL_TIMEOUT < time.time() and \
3629- self.child_pid:
3630- log.critical("Killing child since timeout of %s s", INSTALL_TIMEOUT)
3631- os.kill(self.child_pid, 15)
3632- return True
3633+ """Callback for changes on the status file descriptor.
3634+
3635+ The method has to return True to keep the monitoring alive. If
3636+ it returns False the monitoring will stop.
3637+
3638+ Replace this method in your subclass if you use the status fd.
3639+ """
3640+ return False
3641
3642 def _fork(self):
3643 """Fork and create a master/slave pty pair by which the forked process
3644@@ -598,11 +563,12 @@
3645 if condition == GObject.IO_IN:
3646 self.last_activity = time.time()
3647 try:
3648- char = os.read(source, 1)
3649+ char_byte = os.read(source, 1)
3650 except OSError:
3651 log.debug("Faild to read from master")
3652 return True
3653 # Write all the output from dpkg to a log
3654+ char = char_byte.decode("UTF-8", "ignore")
3655 if char == "\n":
3656 # Skip ANSI characters from the console output
3657 line = re.sub(REGEX_ANSI_ESCAPE_CODE, "", self._line_buffer)
3658@@ -614,7 +580,7 @@
3659 self._line_buffer += char
3660 if target:
3661 try:
3662- os.write(target, char)
3663+ os.write(target, char_byte)
3664 except OSError:
3665 log.debug("Failed to write to controlling terminal")
3666 return True
3667@@ -642,6 +608,93 @@
3668 os.close(source)
3669 return False
3670
3671+
3672+class DaemonInstallProgress(DaemonForkProgress):
3673+
3674+ """Progress to execute APT package operations in a child process."""
3675+
3676+ def start_update(self):
3677+ DaemonForkProgress.start_update(self)
3678+ lock.status_lock.release()
3679+
3680+ def finish_update(self):
3681+ """Callback at the end of the operation"""
3682+ DaemonForkProgress.finish_update(self)
3683+ lock.wait_for_lock(self.transaction, lock.status_lock)
3684+
3685+ def _child(self, pm):
3686+ try:
3687+ res = pm.do_install(self.status_child_fd)
3688+ except:
3689+ os._exit(apt_pkg.PackageManager.RESULT_FAILED)
3690+ else:
3691+ os._exit(res)
3692+
3693+ def _on_status_update(self, source, condition):
3694+ """Parse messages from APT on the status fd."""
3695+ log.debug("UpdateInterface")
3696+ status_msg = ""
3697+ try:
3698+ while not status_msg.endswith("\n"):
3699+ self.last_activity = time.time()
3700+ status_msg += os.read(source, 1).decode("UTF-8", "ignore")
3701+ except:
3702+ return False
3703+ try:
3704+ (status, pkg, percent, message_raw) = status_msg.split(":", 3)
3705+ except ValueError:
3706+ # silently ignore lines that can't be parsed
3707+ return True
3708+ message = message_raw.strip()
3709+ #print "percent: %s %s" % (pkg, float(percent)/100.0)
3710+ if status == "pmerror":
3711+ self._error(pkg, message)
3712+ elif status == "pmconffile":
3713+ # we get a string like this:
3714+ # 'current-conffile' 'new-conffile' useredited distedited
3715+ match = re.match("\s*\'(.*)\'\s*\'(.*)\'.*", message_raw)
3716+ if match:
3717+ new, old = match.group(1), match.group(2)
3718+ self._conffile(new, old)
3719+ elif status == "pmstatus":
3720+ if message.startswith("Installing"):
3721+ status_enum = enums.PKG_INSTALLING
3722+ elif message.startswith("Installed"):
3723+ status_enum = enums.PKG_INSTALLED
3724+ elif message.startswith("Configuring"):
3725+ status_enum = enums.PKG_CONFIGURING
3726+ elif message.startswith("Preparing to configure"):
3727+ status_enum = enums.PKG_PREPARING_CONFIGURE
3728+ elif message.startswith("Preparing for removal of"):
3729+ status_enum = enums.PKG_PREPARING_REMOVE
3730+ elif message.startswith("Removing"):
3731+ status_enum = enums.PKG_REMOVING
3732+ elif message.startswith("Removed"):
3733+ status_enum = enums.PKG_REMOVED
3734+ elif message.startswith("Preparing to completely remove"):
3735+ status_enum = enums.PKG_PREPARING_PURGE
3736+ elif message.startswith("Completely removing"):
3737+ status_enum = enums.PKG_PURGING
3738+ elif message.startswith("Completely removed"):
3739+ status_enum = enums.PKG_PURGED
3740+ elif message.startswith("Unpacking"):
3741+ status_enum = enums.PKG_UNPACKING
3742+ elif message.startswith("Preparing"):
3743+ status_enum = enums.PKG_PREPARING_INSTALL
3744+ elif message.startswith("Noting disappearance of"):
3745+ status_enum = enums.PKG_DISAPPEARING
3746+ elif message.startswith("Running"):
3747+ status_enum = enums.PKG_RUNNING_TRIGGER
3748+ else:
3749+ status_enum = enums.PKG_UNKNOWN
3750+ self._status_changed(pkg, float(percent), status_enum)
3751+ # catch a time out by sending crtl+c
3752+ if self.last_activity + INSTALL_TIMEOUT < time.time() and \
3753+ self.child_pid:
3754+ log.critical("Killing child since timeout of %s s", INSTALL_TIMEOUT)
3755+ os.kill(self.child_pid, 15)
3756+ return True
3757+
3758 def _status_changed(self, pkg, percent, status_enum):
3759 """Callback to update status information"""
3760 log.debug("APT status: %s, %s, %s", pkg, percent, status_enum)
3761@@ -669,9 +722,9 @@
3762 log.debug("Sending config file answer: %s",
3763 self.transaction.config_file_conflict_resolution)
3764 if self.transaction.config_file_conflict_resolution == "replace":
3765- os.write(self.master_fd, "y\n")
3766+ os.write(self.master_fd, b"y\n")
3767 elif self.transaction.config_file_conflict_resolution == "keep":
3768- os.write(self.master_fd, "n\n")
3769+ os.write(self.master_fd, b"n\n")
3770 self.transaction.config_file_conflict_resolution = None
3771 self.transaction.config_file_conflict = None
3772 self.transaction.status = enums.STATUS_COMMITTING
3773@@ -703,7 +756,7 @@
3774 status_raw = ""
3775 try:
3776 while not status_raw.endswith("\n"):
3777- status_raw += os.read(source, 1)
3778+ status_raw += os.read(source, 1).decode("UTF-8", "ignore")
3779 except:
3780 return False
3781 try:
3782
3783=== modified file 'aptdaemon/test.py'
3784--- aptdaemon/test.py 2012-02-03 06:37:42 +0000
3785+++ aptdaemon/test.py 2012-06-13 16:29:18 +0000
3786@@ -28,10 +28,21 @@
3787 import shutil
3788 import subprocess
3789 import sys
3790+import time
3791 import tempfile
3792 import unittest
3793
3794+if sys.version_info.major > 2:
3795+ from http.server import HTTPServer
3796+ from http.server import SimpleHTTPRequestHandler as HTTPRequestHandler
3797+else:
3798+ from BaseHTTPServer import HTTPServer
3799+ from SimpleHTTPServer import SimpleHTTPRequestHandler as HTTPRequestHandler
3800+
3801 import apt_pkg
3802+import apt.auth
3803+
3804+PY3K = sys.version_info.major > 2
3805
3806
3807 class Chroot(object):
3808@@ -55,16 +66,20 @@
3809 os.makedirs(os.path.join(self.path, "var/lib/apt/lists/partial"))
3810 os.makedirs(os.path.join(self.path, "etc/apt/apt.conf.d"))
3811 os.makedirs(os.path.join(self.path, "etc/apt/sources.list.d"))
3812+ os.makedirs(os.path.join(self.path, "etc/apt/preferences.d"))
3813 os.makedirs(os.path.join(self.path, "var/log"))
3814 os.makedirs(os.path.join(self.path, "media"))
3815
3816 # Make apt use the new chroot
3817 dpkg_wrapper = os.path.join(get_tests_dir(), "dpkg-wrapper.sh")
3818+ apt_key_wrapper = os.path.join(get_tests_dir(), "fakeroot-apt-key")
3819 config_path = os.path.join(self.path, "etc/apt/apt.conf.d/10chroot")
3820 with open(config_path, "w") as cnf:
3821 cnf.write("Dir::Bin::DPkg %s;" % dpkg_wrapper)
3822+ cnf.write("Dir::Bin::Apt-Key %s;" % apt_key_wrapper)
3823 apt_pkg.read_config_file(apt_pkg.config, config_path)
3824 apt_pkg.init_system()
3825+ apt_pkg.config["Dir"] = self.path
3826
3827 def remove(self):
3828 """Remove the files of the chroot."""
3829@@ -75,16 +90,8 @@
3830
3831 def add_trusted_key(self):
3832 """Add glatzor's key to the trusted ones."""
3833- gpg_cmd = "gpg --ignore-time-conflict --no-options " \
3834- "--no-default-keyring --quiet " \
3835- "--secret-keyring %s/etc/apt/secring.gpg " \
3836- "--trustdb-name %s/etc/apt/trustdb.gpg " \
3837- "--primary-keyring %s/etc/apt/trusted.gpg " % \
3838- (self.path, self.path, self.path)
3839- os.system("%s --import %s/repo/glatzor.gpg" % (gpg_cmd,
3840- get_tests_dir()))
3841- os.system("echo 'D0BF65B7DBE28DB62BEDBF1B683C53C7CF982D18:6:'| "
3842- "%s --import-ownertrust " % gpg_cmd)
3843+ apt.auth.add_key_from_file(os.path.join(get_tests_dir(),
3844+ "repo/glatzor.gpg"))
3845
3846 def install_debfile(self, path, force_depends=False):
3847 """Install a package file into the chroot."""
3848@@ -162,6 +169,14 @@
3849
3850 class AptDaemonTestCase(unittest.TestCase):
3851
3852+ @classmethod
3853+ def setupClass(cls):
3854+ # Start with a clean APT configuration to remove changes
3855+ # of previous tests
3856+ for key in set([key.split("::")[0] for key in apt_pkg.config.keys()]):
3857+ apt_pkg.config.clear(key)
3858+ apt_pkg.init_config()
3859+
3860 def start_fake_polkitd(self, options="all"):
3861 """Start a fake PolicyKit daemon.
3862
3863@@ -169,7 +184,8 @@
3864 Defaults to all
3865 """
3866 try:
3867- env = {"DBUS_SYSTEM_BUS_ADDRESS": self.dbus_address}
3868+ env = os.environ.copy()
3869+ env["DBUS_SYSTEM_BUS_ADDRESS"] = self.dbus_address
3870 except AttributeError:
3871 env=None
3872 dir = get_tests_dir()
3873@@ -185,7 +201,8 @@
3874 :param chroot: path to the chroot
3875 """
3876 try:
3877- env = {"DBUS_SYSTEM_BUS_ADDRESS": self.dbus_address}
3878+ env = os.environ.copy()
3879+ env["DBUS_SYSTEM_BUS_ADDRESS"] = self.dbus_address
3880 except AttributeError:
3881 env = None
3882 dir = get_tests_dir()
3883@@ -193,7 +210,7 @@
3884 path = "/usr/sbin/aptd"
3885 else:
3886 path = os.path.join(dir, "../aptd")
3887- proc = subprocess.Popen(["python", path, "--debug",
3888+ proc = subprocess.Popen(["python3", path, "--debug",
3889 "--disable-timeout", "--disable-plugins",
3890 "--chroot", chroot],
3891 env=env)
3892@@ -202,14 +219,42 @@
3893
3894 def start_dbus_daemon(self):
3895 """Start a private D-Bus daemon and return its process and address."""
3896- config_path = os.path.join(get_tests_dir(), "dbus.conf")
3897- proc = subprocess.Popen(["dbus-daemon", "--nofork",
3898- "--print-address", "--config-file",
3899- config_path],
3900- stdout=subprocess.PIPE)
3901+ proc, dbus_address = start_dbus_daemon()
3902 self.addCleanup(self._kill_process, proc)
3903- self.dbus_address = proc.stdout.readline().strip()
3904- return proc, self.dbus_address
3905+ self.dbus_address = dbus_address
3906+
3907+ def start_keyserver(self, filename=None):
3908+ """Start a fake keyserver on hkp://localhost:19191
3909+
3910+ Keyword arguments:
3911+ filename -- Optional path to a GnuPG pulic key file which should
3912+ be returned by lookups. By default the key of the test repo
3913+ is used.
3914+ """
3915+ dir = tempfile.mkdtemp(prefix="keyserver-test-")
3916+ self.addCleanup(shutil.rmtree, dir)
3917+ os.mkdir(os.path.join(dir, "pks"))
3918+ if filename is None:
3919+ filename = os.path.join(get_tests_dir(), "repo/glatzor.gpg")
3920+ shutil.copy(filename, os.path.join(dir, "pks", "lookup"))
3921+
3922+ pid = os.fork()
3923+ if pid == 0:
3924+ # quiesce server log
3925+ os.dup2(os.open('/dev/null', os.O_WRONLY), sys.stderr.fileno())
3926+ os.chdir(dir)
3927+ httpd = HTTPServer(('localhost', 19191), HTTPRequestHandler)
3928+ httpd.serve_forever()
3929+ os._exit(0)
3930+ else:
3931+ self.addCleanup(self._kill_pid, pid)
3932+
3933+ # wait a bit until server is ready
3934+ time.sleep(0.5)
3935+
3936+ def _kill_pid(self, pid):
3937+ os.kill(pid, 15)
3938+ os.wait()
3939
3940 def _kill_process(self, proc):
3941 proc.kill()
3942@@ -234,5 +279,19 @@
3943 else:
3944 raise Exception("Could not find tests direcotry")
3945
3946+def start_dbus_daemon():
3947+ """Start a private D-Bus daemon and return its process and address."""
3948+ config_path = os.path.join(get_tests_dir(), "dbus.conf")
3949+ proc = subprocess.Popen(["dbus-daemon", "--nofork",
3950+ "--print-address", "--config-file",
3951+ config_path],
3952+ stdout=subprocess.PIPE)
3953+ output = proc.stdout.readline().strip()
3954+ if PY3K:
3955+ dbus_address = output.decode()
3956+ else:
3957+ dbus_address = output
3958+ return proc, dbus_address
3959+
3960
3961 # vim: ts=4 et sts=4
3962
3963=== modified file 'aptdaemon/utils.py'
3964--- aptdaemon/utils.py 2012-04-02 19:04:16 +0000
3965+++ aptdaemon/utils.py 2012-06-13 16:29:18 +0000
3966@@ -44,8 +44,8 @@
3967 'funcname': func.__name__,
3968 },
3969 category=DeprecationWarning,
3970- filename=func.func_code.co_filename,
3971- lineno=func.func_code.co_firstlineno + 1
3972+ filename=func.__code__.co_filename,
3973+ lineno=func.__code__.co_firstlineno + 1
3974 )
3975 return func(*args, **kwargs)
3976 return new_func
3977@@ -62,7 +62,7 @@
3978 et = ElementTree.ElementTree(file=filename)
3979 self._dict = {}
3980 self.norm = norm
3981- for element in et.getiterator():
3982+ for element in list(et.iter()):
3983 iso_code = element.get(tag)
3984 if not iso_code and fallback_tag:
3985 iso_code = element.get(fallback_tag)
3986
3987=== modified file 'aptdaemon/worker.py'
3988--- aptdaemon/worker.py 2012-05-11 15:56:04 +0000
3989+++ aptdaemon/worker.py 2012-06-13 16:29:18 +0000
3990@@ -31,8 +31,13 @@
3991 import tempfile
3992 import time
3993 import traceback
3994+try:
3995+ from urllib.parse import urlsplit, urlunsplit
3996+except ImportError:
3997+ from urlparse import urlsplit, urlunsplit
3998
3999 import apt
4000+import apt.auth
4001 import apt.cache
4002 import apt.debfile
4003 import apt_pkg
4004@@ -41,7 +46,6 @@
4005 from aptsources.sourceslist import SourcesList
4006 from gi.repository import GObject
4007 import pkg_resources
4008-from softwareproperties.AptAuth import AptAuth
4009 import subprocess
4010
4011 from .enums import *
4012@@ -54,7 +58,8 @@
4013 DaemonAcquireRepoProgress, \
4014 DaemonDpkgInstallProgress, \
4015 DaemonDpkgReconfigureProgress, \
4016- DaemonDpkgRecoverProgress
4017+ DaemonDpkgRecoverProgress, \
4018+ DaemonForkProgress
4019
4020 log = logging.getLogger("AptDaemon.Worker")
4021
4022@@ -413,7 +418,7 @@
4023 """
4024 trans.progress = 101
4025 trans.status = STATUS_COMMITTING
4026- old_umask = os.umask(0022)
4027+ old_umask = os.umask(0o022)
4028 try:
4029 sourceslist = SourcesList()
4030 distro = aptsources.distro.get_distro()
4031@@ -470,8 +475,6 @@
4032 """Extract the credentials from an URI. Store the password in
4033 auth.conf and return the URI without any password information.
4034 """
4035- from urlparse import urlsplit, urlunsplit
4036-
4037 try:
4038 res = urlsplit(uri)
4039 except ValueError as error:
4040@@ -483,7 +486,7 @@
4041
4042 # write auth.conf
4043 auth_conf_path = apt_pkg.config.find_file("Dir::etc::netrc")
4044- old_umask = os.umask(0027)
4045+ old_umask = os.umask(0o027)
4046 try:
4047 with open(auth_conf_path, "a") as auth_conf:
4048 auth_conf.write("""machine %s
4049@@ -508,33 +511,39 @@
4050 keyserver - the keyserver (e.g. keyserver.ubuntu.com)
4051 """
4052 log.info("Adding vendor key from keyserver: %s %s", keyid, keyserver)
4053+ # Perform some sanity checks
4054+ try:
4055+ res = urlsplit(keyserver)
4056+ except ValueError:
4057+ raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
4058+ #TRANSLATORS: %s is the URL of GnuPG
4059+ # keyserver
4060+ _("The keyserver URL is invalid: %s"),
4061+ keyserver)
4062+ if res.scheme not in ["hkp", "ldap", "ldaps", "http", "https"]:
4063+ raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
4064+ #TRANSLATORS: %s is the URL of GnuPG
4065+ # keyserver
4066+ _("Invalid protocol of the server: %s"),
4067+ keyserver)
4068+ try:
4069+ int(keyid, 16)
4070+ except ValueError:
4071+ raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
4072+ #TRANSLATORS: %s is the id of a GnuPG key
4073+ # e.g. E08ADE95
4074+ _("Invalid key id: %s"), keyid)
4075 trans.status = STATUS_DOWNLOADING
4076 trans.progress = 101
4077 last_pulse = time.time()
4078- #FIXME: Use GObject.spawn_async and deferreds in the worker
4079- # Alternatively we could use python-pyme directly for a better
4080- # error handling. Or the --status-fd of gpg
4081- proc = subprocess.Popen(["/usr/bin/apt-key", "adv",
4082- "--keyserver", keyserver,
4083- "--recv", keyid], stderr=subprocess.STDOUT,
4084- stdout=subprocess.PIPE, close_fds=True)
4085- while proc.poll() is None:
4086- self._iterate_mainloop()
4087- time.sleep(0.05)
4088- if time.time() - last_pulse > 0.3:
4089- trans.progress = 101
4090- last_pulse = time.time()
4091- if proc.returncode != 0:
4092- stdout = unicode(proc.stdout.read(),
4093- # that can return "None", in this case, just
4094- # assume something
4095- sys.stdin.encoding or "UTF-8",
4096- errors="replace")
4097+ with DaemonForkProgress(trans) as progress:
4098+ progress.run(apt.auth.add_key_from_keyserver, keyid, keyserver)
4099+ if progress._child_exit != 0:
4100 #TRANSLATORS: The first %s is the key id and the second the server
4101 raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
4102 _("Failed to download and install the key "
4103 "%s from %s:\n%s"),
4104- keyid, keyserver, stdout)
4105+ keyid, keyserver, progress.output)
4106
4107 def add_vendor_key_from_file(self, trans, path):
4108 """Add the signing key from the given file to the trusted vendors.
4109@@ -545,15 +554,12 @@
4110 log.info("Adding vendor key from file: %s", path)
4111 trans.progress = 101
4112 trans.status = STATUS_COMMITTING
4113- try:
4114- #FIXME: use GObject.spawn_async or reactor.spawn
4115- #FIXME: use --dry-run before?
4116- auth = AptAuth()
4117- auth.add(os.path.expanduser(path))
4118- except Exception as error:
4119+ with DaemonForkProgress(trans) as progress:
4120+ progress.run(apt.auth.add_key_from_file, path)
4121+ if progress._child_exit != 0:
4122 raise TransactionFailed(ERROR_KEY_NOT_INSTALLED,
4123 _("Key file %s couldn't be installed: %s"),
4124- path, error)
4125+ path, progress.output)
4126
4127 def remove_vendor_key(self, trans, fingerprint):
4128 """Remove repository key.
4129@@ -566,14 +572,19 @@
4130 trans.progress = 101
4131 trans.status = STATUS_COMMITTING
4132 try:
4133- #FIXME: use GObject.spawn_async or reactor.spawn
4134- #FIXME: use --dry-run before?
4135- auth = AptAuth()
4136- auth.rm(fingerprint)
4137- except Exception as error:
4138+ int(fingerprint, 16)
4139+ except ValueError:
4140+ raise TransactionFailed(ERROR_KEY_NOT_REMOVED,
4141+ #TRANSLATORS: %s is the id of a GnuPG key
4142+ # e.g. E08ADE95
4143+ _("Invalid key id: %s"), fingerprint)
4144+ with DaemonForkProgress(trans) as progress:
4145+ progress.run(apt.auth.remove_key, fingerprint)
4146+ if progress._child_exit != 0:
4147 raise TransactionFailed(ERROR_KEY_NOT_REMOVED,
4148 _("Key with fingerprint %s couldn't be "
4149- "removed: %s"), fingerprint, error)
4150+ "removed: %s"), fingerprint,
4151+ progress.output)
4152
4153 def install_file(self, trans, path, force, simulate=False):
4154 """Install local package file.
4155@@ -603,7 +614,7 @@
4156 deb_progress = DaemonDpkgInstallProgress(trans, begin=64, end=95)
4157 res = deb.install(deb_progress)
4158 encoding = sys.getfilesystemencoding()
4159- trans.output += deb_progress.output.decode(encoding, "ignore")
4160+ trans.output += deb_progress.output
4161 if res:
4162 raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
4163 trans.output)
4164@@ -863,13 +874,10 @@
4165 """
4166 log.info("Fixing incomplete installs")
4167 trans.status = STATUS_CLEANING_UP
4168- progress = DaemonDpkgRecoverProgress(trans)
4169 with self._frozen_status():
4170- progress.start_update()
4171- progress.run()
4172- progress.finish_update()
4173- trans.output += progress.output.decode(sys.getfilesystemencoding(),
4174- "ignore")
4175+ with DaemonDpkgRecoverProgress(trans) as progress:
4176+ progress.run()
4177+ trans.output += progress.output
4178 if progress._child_exit != 0:
4179 raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
4180 trans.output)
4181@@ -883,13 +891,10 @@
4182 priority -- the lowest priority of question which should be asked
4183 """
4184 log.info("Reconfiguring packages")
4185- progress = DaemonDpkgReconfigureProgress(trans)
4186 with self._frozen_status():
4187- progress.start_update()
4188- progress.run(packages, priority)
4189- progress.finish_update()
4190- trans.output += progress.output.decode(sys.getfilesystemencoding(),
4191- "ignore")
4192+ with DaemonDpkgReconfigureProgress(trans) as progress:
4193+ progress.run(packages, priority)
4194+ trans.output += progress.output
4195 if progress._child_exit != 0:
4196 raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
4197 trans.output)
4198@@ -993,18 +998,15 @@
4199 except SystemError as excep:
4200 # Run dpkg --configure -a to recover from a failed transaction
4201 trans.status = STATUS_CLEANING_UP
4202- progress = DaemonDpkgRecoverProgress(trans, begin=90, end=95)
4203- progress.start_update()
4204- progress.run()
4205- progress.finish_update()
4206- output = inst_progress.output + progress.output
4207- trans.output += output.decode(sys.getfilesystemencoding(),
4208- "ignore")
4209+ with DaemonDpkgRecoverProgress(trans, begin=90, end=95) as pro:
4210+ pro.run()
4211+ output = inst_progress.output + pro.output
4212+ trans.output += output
4213 raise TransactionFailed(ERROR_PACKAGE_MANAGER_FAILED,
4214 "%s: %s" % (excep, trans.output))
4215 else:
4216 enc = sys.getfilesystemencoding()
4217- trans.output += inst_progress.output.decode(enc, "ignore")
4218+ trans.output += inst_progress.output
4219
4220 @contextlib.contextmanager
4221 def _frozen_status(self):
4222@@ -1103,7 +1105,7 @@
4223 size = int(deb["Installed-Size"].replace(",", "")) * 1024
4224 # Some packages ship really large install sizes e.g.
4225 # openvpn access server, see LP #758837
4226- if size > sys.maxint:
4227+ if size > sys.maxsize:
4228 raise OverflowError("Size is too large: %s Bytes" % size)
4229 except (KeyError, AttributeError, ValueError, OverflowError):
4230 if not trans.kwargs["force"]:
4231@@ -1181,7 +1183,6 @@
4232 :returns: An apt.debfile.Debfile instance.
4233 """
4234 #FIXME: Unblock lintian call
4235- path = path.encode("UTF-8")
4236 if not os.path.isfile(path):
4237 raise TransactionFailed(ERROR_UNREADABLE_PACKAGE_FILE, path)
4238 if not force and os.path.isfile("/usr/bin/lintian"):
4239@@ -1219,9 +1220,9 @@
4240 time.sleep(0.05)
4241 #FIXME: Add an error to catch return state 2 (failure)
4242 if proc.returncode == 1:
4243- stdout = unicode(proc.stdout.read(),
4244- sys.stdin.encoding or "UTF-8",
4245- errors="replace")
4246+ stdout = proc.stdout.read()
4247+ stdout.decode(sys.stdin.encoding or "UTF-8",
4248+ errors="replace")
4249 raise TransactionFailed(ERROR_INVALID_PACKAGE_FILE,
4250 "Lintian check results for %s:"
4251 "\n%s" % (path, stdout))
4252
4253=== modified file 'aptdcon'
4254--- aptdcon 2009-06-30 15:06:36 +0000
4255+++ aptdcon 2012-06-13 16:29:18 +0000
4256@@ -1,4 +1,4 @@
4257-#!/usr/bin/python
4258+#!/usr/bin/python3
4259 # -*- coding: utf-8 -*-
4260 """
4261 aptdcon - command line interface client to aptdaemon
4262
4263=== modified file 'debian/aptdaemon.install'
4264--- debian/aptdaemon.install 2012-04-09 20:48:44 +0000
4265+++ debian/aptdaemon.install 2012-06-13 16:29:18 +0000
4266@@ -1,7 +1,7 @@
4267 etc/apt/apt.conf.d/20dbus
4268 etc/dbus-1/system.d/org.debian.apt.conf
4269-usr/bin/aptd /usr/sbin
4270-usr/bin/aptdcon
4271+../../build/scripts-3.*/aptd /usr/sbin
4272+../../build/scripts-3.*/aptdcon /usr/bin
4273 usr/share/dbus-1/system-services/org.debian.apt.service
4274 usr/share/polkit-1/actions/org.debian.apt.policy
4275 usr/share/locale
4276
4277=== modified file 'debian/changelog'
4278--- debian/changelog 2012-05-23 12:53:16 +0000
4279+++ debian/changelog 2012-06-13 16:29:18 +0000
4280@@ -1,3 +1,42 @@
4281+aptdaemon (0.43+bzr838-0ubuntu1) UNRELEASED; urgency=low
4282+
4283+ * Upload of the latest Python3 porting efforts from trunk
4284+ * debian/patches:
4285+ - Add disable_simulate_test: Fails on build bot for unknown reasons
4286+ * debian/control:
4287+ - Switch aptdaemon package to Python3 by default
4288+ - Add new python3-aptdaemon.gtk3widgets package
4289+ - Replace python-aptdaemon.test by python3-aptdaemon.test
4290+ - Replace python-aptdaemon.pkcompat by python3-aptdaemon.pkcompat
4291+ - python3-aptdaemon.pkcompat provides the new virtual package
4292+ packagekit-system-interface to obsolete the OR dependencies
4293+ with packagekit of PackageKit clients
4294+ - Remove policykit1 dependecy from the modules and add it to the server
4295+ package
4296+ - Remove not used shlibs macros
4297+ - Remove dependency to python-packagekit, since we ship the enums
4298+ in python3-aptdaemon.pkcompat
4299+ - Add build dependencies to run the test suite
4300+ * debian/rules:
4301+ - Build with Python2 and 3
4302+ - Enable the test suite
4303+ * debian/*.(install|docs|examples):
4304+ - Adpat to above package changes
4305+
4306+ [ Steve Langasek ]
4307+ * debian/control:
4308+ - Remove python-software-properties dependency in favor of new
4309+ python-apt with apt.auth module
4310+ * aptdaemon/test.py: explicitly set the chroot directory in the apt config
4311+ as part of the test setup, without which apt-key's chroot handling won't
4312+ work.
4313+ * test/test_pk.py: increase the sleep on startup, to allow longer for
4314+ fake-polkitd to start up.
4315+ * aptdaemon/worker.py: restore compatibility with python2, which doesn't
4316+ have urllib.parse.
4317+
4318+ -- Sebastian Heinlein <glatzor@ubuntu.com> Fri, 11 May 2012 08:39:34 -0700
4319+
4320 aptdaemon (0.43+bzr810-0ubuntu3) quantal; urgency=low
4321
4322 * debian/python-aptdaemon.test.install: Fix installation path of
4323
4324=== modified file 'debian/control'
4325--- debian/control 2012-05-22 11:01:33 +0000
4326+++ debian/control 2012-06-13 16:29:18 +0000
4327@@ -4,35 +4,50 @@
4328 Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
4329 XSBC-Original-Maintainer: Julian Andres Klode <jak@debian.org>
4330 Build-Depends: debhelper (>= 7.3),
4331+ debconf-i18n,
4332+ dbus,
4333+ lintian,
4334 dh-translations,
4335- dbus,
4336- python,
4337+ python-all,
4338 python-setuptools,
4339 python-distutils-extra,
4340- python-apt (>= 0.7.96.1ubuntu9),
4341- python-debian,
4342- python-defer,
4343+ python-nose,
4344+ python3-all,
4345+ python3-setuptools,
4346+ python3-distutils-extra,
4347+ python3-nose,
4348+ gir1.2-glib-2.0,
4349+ gir1.2-packagekitglib-1.0,
4350+ python3-apt (>= 0.8.5~ubuntu1),
4351+ python3-defer (>= 1.0.6),
4352+ python3-dbus,
4353+ python3-gi,
4354+ python3-mock,
4355+ python3-pkg-resources,
4356+ python-apt (>= 0.8.5~ubuntu1),
4357+ python-defer (>= 1.0.6),
4358 python-dbus,
4359 python-gi,
4360- gir1.2-glib-2.0,
4361- python-software-properties
4362+ python-mock,
4363+ python-pkg-resources,
4364 Standards-Version: 3.9.1
4365 Homepage: https://launchpad.net/aptdaemon
4366 Vcs-Bzr: lp:~aptdaemon-developers/aptdaemon/ubuntu-quantal
4367 Vcs-Browser: https://code.launchpad.net/~aptdaemon-developers/aptdaemon/ubuntu-quantal
4368 XS-Original-Vcs-Bzr: nosmart+http://bzr.debian.org/bzr/apt/aptdaemon/debian-sid
4369 XS-Original-Vcs-Browser: http://bzr.debian.org/loggerhead/apt/aptdaemon/debian-sid
4370-XS-Python-Version: >= 2.7
4371+X-Python-Version: >= 2.7
4372+X-Python3-Version: >= 3.2
4373
4374 Package: aptdaemon
4375 Architecture: all
4376 Depends: ${misc:Depends},
4377- ${python:Depends},
4378- python-aptdaemon (= ${binary:Version}),
4379- python-gi,
4380- gir1.2-glib-2.0
4381+ ${python3:Depends},
4382+ gir1.2-glib-2.0,
4383+ python3-aptdaemon (= ${binary:Version}),
4384+ python3-gi,
4385+ policykit-1,
4386 Recommends: lintian
4387-XB-Python-Version: ${python:Versions}
4388 Breaks: software-center (<< 1.1.21)
4389 Description: transaction based package management service
4390 Aptdaemon allows normal users to perform package management tasks, e.g.
4391@@ -54,39 +69,54 @@
4392 the daemon. Moreover it contains the aptdcon script, which is a command
4393 line client for aptdaemon. The API is not stable yet.
4394
4395+Package: python3-aptdaemon
4396+Architecture: all
4397+Section: python
4398+Depends: ${misc:Depends},
4399+ ${python3:Depends},
4400+ gir1.2-glib-2.0,
4401+ python3-apt (>= 0.8.5~ubuntu1),
4402+ python3-defer (>= 1.0.6),
4403+ python3-dbus,
4404+ python3-gi,
4405+ python3-pkg-resources,
4406+Recommends: aptdaemon
4407+Description: Python 3 module for the server and client of aptdaemon
4408+ Aptdaemon is a transaction based package management service. It allows
4409+ normal users to perform package management tasks, e.g. refreshing the
4410+ cache, upgrading the system, installing or removing software packages.
4411+ .
4412+ This package provides the Python 3 modules required to run aptdaemon
4413+ and to implement a client. The API is not stable yet.
4414+
4415+
4416 Package: python-aptdaemon
4417 Architecture: all
4418 Section: python
4419-Depends: ${shlibs:Depends},
4420- ${misc:Depends},
4421+Depends: ${misc:Depends},
4422 ${python:Depends},
4423- python-apt (>= 0.7.96.1ubuntu9),
4424+ python-apt (>= 0.8.5~ubuntu1),
4425 python-debian,
4426 python-defer,
4427 python-dbus,
4428 python-gi,
4429 gir1.2-glib-2.0,
4430 python-pkg-resources,
4431- python-software-properties,
4432- policykit-1
4433 Recommends: aptdaemon
4434-XB-Python-Version: ${python:Versions}
4435-Description: Python module for the server and client of aptdaemon
4436+Description: Python 2 module for the server and client of aptdaemon
4437 Aptdaemon is a transaction based package management service. It allows
4438 normal users to perform package management tasks, e.g. refreshing the
4439 cache, upgrading the system, installing or removing software packages.
4440 .
4441- This package provides the Python modules required to run aptdaemon
4442+ This package provides the Python 2 modules required to run aptdaemon
4443 and to implement a client. The API is not stable yet.
4444
4445-Package: python-aptdaemon.test
4446+Package: python3-aptdaemon.test
4447 Architecture: all
4448 Section: python
4449-Depends: ${shlibs:Depends},
4450- ${misc:Depends},
4451- ${python:Depends},
4452- python-aptdaemon (= ${binary:Version}),
4453-XB-Python-Version: ${python:Versions}
4454+Depends: ${misc:Depends},
4455+ ${python3:Depends},
4456+ python3-aptdaemon (= ${binary:Version}),
4457 Description: Test environment for aptdaemon clients
4458 Aptdaemon is a transaction based package management daemon. It allows
4459 normal users to perform package management tasks, e.g. refreshing the
4460@@ -98,8 +128,7 @@
4461
4462 Package: aptdaemon-data
4463 Architecture: all
4464-Depends: ${shlibs:Depends},
4465- ${misc:Depends}
4466+Depends: ${misc:Depends}
4467 Replaces: python-aptdaemon-gtk (<= 0.41+bzr580-0ubuntu1)
4468 Description: data files for clients
4469 Aptdaemon is a transaction based package management daemon. It allows
4470@@ -112,12 +141,10 @@
4471 Package: python-aptdaemon-gtk
4472 Architecture: all
4473 Section: python
4474-Depends: ${shlibs:Depends},
4475- ${misc:Depends},
4476+Depends: ${misc:Depends},
4477 ${python:Depends},
4478 python-aptdaemon.gtkwidgets (= ${binary:Version}),
4479 python-aptdaemon.gtk3widgets (= ${binary:Version})
4480-XB-Python-Version: ${python:Versions}
4481 Description: Transitional dummy package
4482 Aptdaemon is a transaction based package management daemon. It allows
4483 normal users to perform package management tasks, e.g. refreshing the
4484@@ -129,16 +156,16 @@
4485 .
4486 You can remove it safely.
4487
4488-Package: python-aptdaemon.pkcompat
4489+Package: python3-aptdaemon.pkcompat
4490 Architecture: all
4491 Section: python
4492-Depends: ${shlibs:Depends},
4493- ${misc:Depends},
4494- ${python:Depends},
4495- python-aptdaemon (= ${binary:Version}),
4496- python-packagekit,
4497-Conflicts: packagekit
4498-XB-Python-Version: ${python:Versions}
4499+Depends: ${misc:Depends},
4500+ ${python3:Depends},
4501+ python3-aptdaemon (= ${binary:Version}),
4502+Provides: packagekit-system-interface
4503+Conflicts: packagekit,
4504+ python-aptdaemon.pkcompat,
4505+Replaces: python-aptdaemon.pkcompat
4506 Description: PackageKit compatibilty for AptDaemon
4507 Aptdaemon is a transaction based package management daemon. It allows
4508 normal users to perform package management tasks, e.g. refreshing the
4509@@ -149,8 +176,7 @@
4510 Package: python-aptdaemon.gtkwidgets
4511 Architecture: all
4512 Section: python
4513-Depends: ${shlibs:Depends},
4514- ${misc:Depends},
4515+Depends: ${misc:Depends},
4516 ${python:Depends},
4517 python-aptdaemon (= ${binary:Version}),
4518 python-gtk2,
4519@@ -158,7 +184,6 @@
4520 aptdaemon-data
4521 Conflicts: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
4522 Replaces: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
4523-XB-Python-Version: ${python:Versions}
4524 Description: Python GTK+ 2 widgets to run an aptdaemon client
4525 Aptdaemon is a transaction based package management daemon. It allows
4526 normal users to perform package management tasks, e.g. refreshing the
4527@@ -168,12 +193,32 @@
4528 graphical client. The widgets can be used to initiate, to monitor and
4529 to control a transaction. The API is not stable yet.
4530
4531+Package: python3-aptdaemon.gtk3widgets
4532+Architecture: all
4533+Section: python
4534+Depends: ${misc:Depends},
4535+ ${python3:Depends},
4536+ python3-aptdaemon (= ${binary:Version}),
4537+ python3-gi,
4538+ gir1.2-gtk-3.0,
4539+ gir1.2-vte-2.90,
4540+ aptdaemon-data
4541+Conflicts: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
4542+Replaces: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
4543+Description: Python 3 GTK+ 3 widgets to run an aptdaemon client
4544+ Aptdaemon is a transaction based package management daemon. It allows
4545+ normal users to perform package management tasks, e.g. refreshing the
4546+ cache, upgrading the system, installing or removing software packages.
4547+ .
4548+ This package provides the Python 3 GTK+ 3 widgets to implement a fully
4549+ working graphical client. The widgets can be used to initiate, to
4550+ monitor and to control a transaction. The API is not stable yet.
4551+
4552 Package: python-aptdaemon.gtk3widgets
4553 Architecture: all
4554 Section: python
4555-Depends: ${shlibs:Depends},
4556- ${misc:Depends},
4557- ${python:Depends},
4558+Depends: ${misc:Depends},
4559+ ${python3:Depends},
4560 python-aptdaemon (= ${binary:Version}),
4561 python-gi,
4562 gir1.2-gtk-3.0,
4563@@ -181,12 +226,11 @@
4564 aptdaemon-data
4565 Conflicts: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
4566 Replaces: python-aptdaemon-gtk (<< 0.41+bzr582-0ubuntu1)
4567-XB-Python-Version: ${python:Versions}
4568-Description: Python GTK+ 3 widgets to run an aptdaemon client
4569+Description: Python 2 GTK+ 3 widgets to run an aptdaemon client
4570 Aptdaemon is a transaction based package management daemon. It allows
4571 normal users to perform package management tasks, e.g. refreshing the
4572 cache, upgrading the system, installing or removing software packages.
4573 .
4574- This package provides the Python GTK+ 3 widgets to implement a fully
4575+ This package provides the Python 2 GTK+ 3 widgets to implement a fully
4576 working graphical client. The widgets can be used to initiate, to
4577 monitor and to control a transaction. The API is not stable yet.
4578
4579=== added file 'debian/patches/disable_simulate_test.patch'
4580--- debian/patches/disable_simulate_test.patch 1970-01-01 00:00:00 +0000
4581+++ debian/patches/disable_simulate_test.patch 2012-06-13 16:29:18 +0000
4582@@ -0,0 +1,12 @@
4583+=== modified file 'tests/test_simulate.py'
4584+--- old/tests/test_simulate.py 2012-03-19 07:58:34 +0000
4585++++ new/tests/test_simulate.py 2012-06-04 11:06:46 +0000
4586+@@ -25,6 +25,7 @@
4587+ def setUp(self):
4588+ """Setup a chroot, run the aptdaemon and a fake PolicyKit daemon."""
4589+ # Setup chroot
4590++ self.skipTest("Temporarily disabled")
4591+ self.chroot = aptdaemon.test.Chroot()
4592+ self.chroot.setup()
4593+ self.addCleanup(self.chroot.remove)
4594+
4595
4596=== modified file 'debian/patches/series'
4597--- debian/patches/series 2011-12-15 10:15:46 +0000
4598+++ debian/patches/series 2012-06-13 16:29:18 +0000
4599@@ -0,0 +1,2 @@
4600+disable_simulate_test.patch
4601+test-suite-fixes
4602
4603=== added file 'debian/patches/test-suite-fixes'
4604--- debian/patches/test-suite-fixes 1970-01-01 00:00:00 +0000
4605+++ debian/patches/test-suite-fixes 2012-06-13 16:29:18 +0000
4606@@ -0,0 +1,53 @@
4607+Description: fixes for the test suite
4608+ fixes against upstream bzr to make the test suite work on quantal, with
4609+ python2+python3:
4610+ aptdaemon/test.py: explicitly set the chroot directory in the apt config
4611+ as part of the test setup, without which apt-key's chroot handling won't
4612+ work.
4613+ test/test_pk.py: increase the sleep on startup, to allow longer for
4614+ fake-polkitd to connect to dbus.
4615+ aptdaemon/worker.py: restore compatibility with python2, which doesn't
4616+ have urllib.parse.
4617+Author: Steve Langasek <steve.langasek@ubuntu.com>
4618+
4619+Index: trunk/aptdaemon/test.py
4620+===================================================================
4621+--- trunk.orig/aptdaemon/test.py
4622++++ trunk/aptdaemon/test.py
4623+@@ -79,6 +79,7 @@
4624+ cnf.write("Dir::Bin::Apt-Key %s;" % apt_key_wrapper)
4625+ apt_pkg.read_config_file(apt_pkg.config, config_path)
4626+ apt_pkg.init_system()
4627++ apt_pkg.config["Dir"] = self.path
4628+
4629+ def remove(self):
4630+ """Remove the files of the chroot."""
4631+Index: trunk/aptdaemon/worker.py
4632+===================================================================
4633+--- trunk.orig/aptdaemon/worker.py
4634++++ trunk/aptdaemon/worker.py
4635+@@ -31,7 +31,10 @@
4636+ import tempfile
4637+ import time
4638+ import traceback
4639+-from urllib.parse import urlsplit, urlunsplit
4640++try:
4641++ from urllib.parse import urlsplit, urlunsplit
4642++except ImportError:
4643++ from urlparse import urlsplit, urlunsplit
4644+
4645+ import apt
4646+ import apt.auth
4647+Index: trunk/tests/test_pk.py
4648+===================================================================
4649+--- trunk.orig/tests/test_pk.py
4650++++ trunk/tests/test_pk.py
4651+@@ -66,7 +66,7 @@
4652+ self.start_session_aptd(self.chroot.path)
4653+ # Start the fake PolikcyKit daemon
4654+ self.start_fake_polkitd()
4655+- time.sleep(0.5)
4656++ time.sleep(2.5)
4657+
4658+ def tearDown(self):
4659+ shutil.rmtree(self.workdir)
4660
4661=== modified file 'debian/python-aptdaemon.pkcompat.install'
4662--- debian/python-aptdaemon.pkcompat.install 2011-11-21 10:08:24 +0000
4663+++ debian/python-aptdaemon.pkcompat.install 2012-06-13 16:29:18 +0000
4664@@ -1,3 +1,4 @@
4665-usr/lib/python2.*/*-packages/aptdaemon/pkcompat.py
4666+usr/lib/python3*/*-packages/aptdaemon/pkcompat.py
4667+usr/lib/python3*/*-packages/aptdaemon/pkenums.py
4668 usr/share/dbus-1/system-services/org.freedesktop.PackageKit.service
4669 etc/dbus-1/system.d/org.freedesktop.PackageKit-aptd.conf
4670
4671=== modified file 'debian/python-aptdaemon.test.install'
4672--- debian/python-aptdaemon.test.install 2012-05-23 12:53:16 +0000
4673+++ debian/python-aptdaemon.test.install 2012-06-13 16:29:18 +0000
4674@@ -1,4 +1,4 @@
4675-usr/lib/python2.*/*-packages/aptdaemon/test.py
4676+usr/lib/python3*/*-packages/aptdaemon/test.py
4677 tests/repo/glatzor.gpg /usr/share/aptdaemon/tests/repo/
4678 tests/repo/gstreamer0.10-silly_0.1-0_all.deb /usr/share/aptdaemon/tests/repo/
4679 tests/repo/Packages /usr/share/aptdaemon/tests/repo/
4680
4681=== added file 'debian/python3-aptdaemon.gtk3widgets.examples'
4682--- debian/python3-aptdaemon.gtk3widgets.examples 1970-01-01 00:00:00 +0000
4683+++ debian/python3-aptdaemon.gtk3widgets.examples 2012-06-13 16:29:18 +0000
4684@@ -0,0 +1,1 @@
4685+gtk3-demo.py
4686
4687=== added file 'debian/python3-aptdaemon.gtk3widgets.install'
4688--- debian/python3-aptdaemon.gtk3widgets.install 1970-01-01 00:00:00 +0000
4689+++ debian/python3-aptdaemon.gtk3widgets.install 2012-06-13 16:29:18 +0000
4690@@ -0,0 +1,1 @@
4691+usr/lib/python3*/*-packages/aptdaemon/gtk3widgets.py
4692
4693=== added file 'debian/python3-aptdaemon.install'
4694--- debian/python3-aptdaemon.install 1970-01-01 00:00:00 +0000
4695+++ debian/python3-aptdaemon.install 2012-06-13 16:29:18 +0000
4696@@ -0,0 +1,16 @@
4697+usr/lib/python3*/*-packages/aptdaemon/__init__.py
4698+usr/lib/python3*/*-packages/aptdaemon/client.py
4699+usr/lib/python3*/*-packages/aptdaemon/config.py
4700+usr/lib/python3*/*-packages/aptdaemon/console.py
4701+usr/lib/python3*/*-packages/aptdaemon/core.py
4702+usr/lib/python3*/*-packages/aptdaemon/crash.py
4703+usr/lib/python3*/*-packages/aptdaemon/debconf.py
4704+usr/lib/python3*/*-packages/aptdaemon/enums.py
4705+usr/lib/python3*/*-packages/aptdaemon/errors.py
4706+usr/lib/python3*/*-packages/aptdaemon/loop.py
4707+usr/lib/python3*/*-packages/aptdaemon/lock.py
4708+usr/lib/python3*/*-packages/aptdaemon/networking.py
4709+usr/lib/python3*/*-packages/aptdaemon/policykit1.py
4710+usr/lib/python3*/*-packages/aptdaemon/progress.py
4711+usr/lib/python3*/*-packages/aptdaemon/utils.py
4712+usr/lib/python3*/*-packages/aptdaemon/worker.py
4713
4714=== added file 'debian/python3-aptdaemon.pkcompat.docs'
4715--- debian/python3-aptdaemon.pkcompat.docs 1970-01-01 00:00:00 +0000
4716+++ debian/python3-aptdaemon.pkcompat.docs 2012-06-13 16:29:18 +0000
4717@@ -0,0 +1,1 @@
4718+README.PackageKit
4719
4720=== added file 'debian/python3-aptdaemon.pkcompat.install'
4721--- debian/python3-aptdaemon.pkcompat.install 1970-01-01 00:00:00 +0000
4722+++ debian/python3-aptdaemon.pkcompat.install 2012-06-13 16:29:18 +0000
4723@@ -0,0 +1,4 @@
4724+usr/lib/python3*/*-packages/aptdaemon/pkcompat.py
4725+usr/lib/python3*/*-packages/aptdaemon/pkenums.py
4726+usr/share/dbus-1/system-services/org.freedesktop.PackageKit.service
4727+etc/dbus-1/system.d/org.freedesktop.PackageKit-aptd.conf
4728
4729=== added file 'debian/python3-aptdaemon.test.examples'
4730--- debian/python3-aptdaemon.test.examples 1970-01-01 00:00:00 +0000
4731+++ debian/python3-aptdaemon.test.examples 2012-06-13 16:29:18 +0000
4732@@ -0,0 +1,1 @@
4733+tests/test_client.py
4734
4735=== added file 'debian/python3-aptdaemon.test.install'
4736--- debian/python3-aptdaemon.test.install 1970-01-01 00:00:00 +0000
4737+++ debian/python3-aptdaemon.test.install 2012-06-13 16:29:18 +0000
4738@@ -0,0 +1,18 @@
4739+usr/lib/python3*/*-packages/aptdaemon/test.py
4740+tests/repo/glatzor.gpg /usr/share/aptdaemon/tests/repo/
4741+tests/repo/gstreamer0.10-silly_0.1-0_all.deb /usr/share/aptdaemon/tests/repo/
4742+tests/repo/Packages /usr/share/aptdaemon/tests/repo/
4743+tests/repo/Release /usr/share/aptdaemon/tests/repo/
4744+tests/repo/Release.gpg /usr/share/aptdaemon/tests/repo/
4745+tests/repo/silly-base_0.1-0_all.deb /usr/share/aptdaemon/tests/repo/
4746+tests/repo/silly-base_0.1-0update1_all.deb /usr/share/aptdaemon/tests/repo/
4747+tests/repo/silly-broken_0.1-0_all.deb /usr/share/aptdaemon/tests/repo/
4748+tests/repo/silly-config_0.1-0_all.deb /usr/share/aptdaemon/tests/repo/
4749+tests/repo/silly-depend-base_0.1-0_all.deb /usr/share/aptdaemon/tests/repo/
4750+tests/repo/silly-essential_0.1-0_all.deb /usr/share/aptdaemon/tests/repo/
4751+tests/repo/silly-fail_0.1-0_all.deb /usr/share/aptdaemon/tests/repo/
4752+tests/repo/silly-important_0.1-0_all.deb /usr/share/aptdaemon/tests/repo/
4753+tests/repo/silly-postinst-input_0.1-0_all.deb /usr/share/aptdaemon/tests/repo/
4754+tests/dpkg-wrapper.sh /usr/share/aptdaemon/tests/
4755+tests/fake-polkitd.py /usr/share/aptdaemon/tests/
4756+tests/dbus.conf /usr/share/aptdaemon/tests/
4757
4758=== modified file 'debian/rules'
4759--- debian/rules 2011-11-21 10:08:24 +0000
4760+++ debian/rules 2012-06-13 16:29:18 +0000
4761@@ -1,12 +1,32 @@
4762 #!/usr/bin/make -f
4763
4764+#DH_VERBOSE=1
4765+
4766+PYTHON2=$(shell pyversions -vr)
4767+PYTHON3=$(shell py3versions -vr)
4768+
4769 %:
4770- dh --with=python2,translations $@
4771+ dh $@ --with=python2,python3,translations
4772+
4773+build-python%:
4774+ python$* setup.py build
4775+
4776+override_dh_auto_build: $(PYTHON3:%=build-python%)
4777+ dh_auto_build
4778+
4779+install-python%:
4780+ python$* setup.py install --root=$(CURDIR)/debian/tmp --install-layout=deb
4781+
4782+override_dh_auto_install: $(PYTHON3:%=install-python%)
4783+ dh_auto_install
4784
4785 override_dh_auto_clean:
4786 dh_auto_clean
4787 rm -rf build *.egg-info po/aptdaemon.pot
4788
4789-# mvo: disabled temporarely, see changelog for 0.41+bzr586-0ubuntu1
4790-#override_dh_auto_test:
4791-# unit2 discover
4792+ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
4793+test-python%:
4794+ python$* setup.py test -vv
4795+
4796+override_dh_auto_test: $(PYTHON3:%=test-python%) $(PYTHON2:%=test-python%)
4797+endif
4798
4799=== added file 'doc/source/aptdaemon.gtk3widgets.rst'
4800--- doc/source/aptdaemon.gtk3widgets.rst 1970-01-01 00:00:00 +0000
4801+++ doc/source/aptdaemon.gtk3widgets.rst 2012-06-13 16:29:18 +0000
4802@@ -0,0 +1,5 @@
4803+:mod:`aptdaemon.gtk3widgets` --- The gtk3widgets module
4804+=====================================================
4805+
4806+.. automodule:: aptdaemon.gtk3widgets
4807+ :members:
4808
4809=== removed file 'doc/source/aptdaemon.gtkwidgets.rst'
4810--- doc/source/aptdaemon.gtkwidgets.rst 2011-11-21 10:08:24 +0000
4811+++ doc/source/aptdaemon.gtkwidgets.rst 1970-01-01 00:00:00 +0000
4812@@ -1,5 +0,0 @@
4813-:mod:`aptdaemon.gtkwidgets` --- The gtkwidgets module
4814-=====================================================
4815-
4816-.. automodule:: aptdaemon.gtkwidgets
4817- :members:
4818
4819=== modified file 'doc/source/index.rst'
4820--- doc/source/index.rst 2011-11-21 10:08:24 +0000
4821+++ doc/source/index.rst 2012-06-13 16:29:18 +0000
4822@@ -8,7 +8,7 @@
4823
4824 aptdaemon.client
4825 aptdaemon.enums
4826- aptdaemon.gtkwidgets
4827+ aptdaemon.gtk3widgets
4828
4829 dbus
4830 plugins
4831
4832=== modified file 'gtk-demo.py'
4833--- gtk-demo.py 2011-12-01 14:40:52 +0000
4834+++ gtk-demo.py 2012-06-13 16:29:18 +0000
4835@@ -1,4 +1,4 @@
4836-#!/usr/bin/env python
4837+#!/usr/bin/python
4838 # -*- coding: utf-8 -*-
4839 """
4840 Provides a graphical demo application for aptdaemon
4841
4842=== modified file 'gtk3-demo.py'
4843--- gtk3-demo.py 2011-12-01 14:40:52 +0000
4844+++ gtk3-demo.py 2012-06-13 16:29:18 +0000
4845@@ -1,4 +1,4 @@
4846-#!/usr/bin/env python
4847+#!/usr/bin/python3
4848 # -*- coding: utf-8 -*-
4849 """
4850 Provides a graphical demo application for aptdaemon
4851@@ -66,14 +66,11 @@
4852 self._run_transaction(trans)
4853
4854 def _on_error(self, error):
4855- try:
4856- raise error
4857- except aptdaemon.errors.NotAuthorizedError:
4858+ if isinstance(error, aptdaemon.errors.NotAuthorizedError):
4859 # Silently ignore auth failures
4860 return
4861- except aptdaemon.errors.TransactionFailed as error:
4862- pass
4863- except Exception as error:
4864+ elif not isinstance(error, aptdaemon.errors.TransactionFailed):
4865+ # Catch internal errors of the client
4866 error = aptdaemon.errors.TransactionFailed(ERROR_UNKNOWN,
4867 str(error))
4868 dia = AptErrorDialog(error)
4869
4870=== modified file 'po/af.po'
4871--- po/af.po 2011-11-21 10:08:24 +0000
4872+++ po/af.po 2012-06-13 16:29:18 +0000
4873@@ -7,499 +7,585 @@
4874 msgstr ""
4875 "Project-Id-Version: aptdaemon\n"
4876 "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
4877-"POT-Creation-Date: 2010-09-27 21:46+0000\n"
4878-"PO-Revision-Date: 2010-07-26 09:31+0000\n"
4879+"POT-Creation-Date: 2012-04-10 15:24+0000\n"
4880+"PO-Revision-Date: 2011-01-16 11:40+0000\n"
4881 "Last-Translator: Michael Vogt <michael.vogt@ubuntu.com>\n"
4882 "Language-Team: Afrikaans <af@li.org>\n"
4883 "MIME-Version: 1.0\n"
4884 "Content-Type: text/plain; charset=UTF-8\n"
4885 "Content-Transfer-Encoding: 8bit\n"
4886 "Plural-Forms: nplurals=2; plural=n != 1;\n"
4887-"X-Launchpad-Export-Date: 2010-09-28 16:44+0000\n"
4888-"X-Generator: Launchpad (build Unknown)\n"
4889-
4890-#. This privilege allows to call AddRepository, UpdateCache(Partially)
4891-#. and InstallPackages in a row and only authenticating once.
4892-#.
4893-#. The client has to authenticate for this privilege before calling
4894-#. the aptdaemon methods.
4895+"X-Launchpad-Export-Date: 2012-05-26 09:08+0000\n"
4896+"X-Generator: Launchpad (build 15288)\n"
4897+
4898+#: ../data/org.debian.apt.policy.in.h:1
4899+msgid "List keys of trusted vendors"
4900+msgstr ""
4901+
4902+#: ../data/org.debian.apt.policy.in.h:2
4903+msgid "To view the list of trusted keys, you need to authenticate."
4904+msgstr ""
4905+
4906+#: ../data/org.debian.apt.policy.in.h:3 ../aptdaemon/console.py:607
4907+msgid "Remove downloaded package files"
4908+msgstr ""
4909+
4910+#: ../data/org.debian.apt.policy.in.h:4
4911+msgid "To clean downloaded package files, you need to authenticate."
4912+msgstr ""
4913+
4914+#: ../data/org.debian.apt.policy.in.h:5
4915+msgid "Change software configuration"
4916+msgstr ""
4917+
4918 #: ../data/org.debian.apt.policy.in.h:6
4919-msgid "Add a new repository and install packages from it"
4920-msgstr ""
4921-
4922-#. This privilege allows to call AddRepository, UpdateCache(Partially)
4923-#. and InstallPackages in a row and only authenticating once.
4924-#.
4925-#. The client has to authenticate for this privilege before calling
4926-#. the aptdaemon methods.
4927-#.
4928-#. The only difference to install-packages-from-new-repo is the wording
4929-#. of the message. It is required by Ubuntu's Software-Center.
4930-#: ../data/org.debian.apt.policy.in.h:15
4931-msgid ""
4932-"Add a new repository of purchased software and install packages from it"
4933-msgstr ""
4934-
4935-#: ../data/org.debian.apt.policy.in.h:16
4936-msgid "Cancel the task of another user"
4937-msgstr "Kanselleer die taak van 'n ander gebruiker"
4938-
4939-#: ../data/org.debian.apt.policy.in.h:17
4940+msgid "To change software settings, you need to authenticate."
4941+msgstr ""
4942+
4943+#: ../data/org.debian.apt.policy.in.h:7
4944 msgid "Change software repository"
4945 msgstr ""
4946
4947-#: ../data/org.debian.apt.policy.in.h:18
4948-msgid "Install or remove packages"
4949+#: ../data/org.debian.apt.policy.in.h:8
4950+msgid "To change software repository settings, you need to authenticate."
4951 msgstr ""
4952
4953-#: ../data/org.debian.apt.policy.in.h:19
4954+#: ../data/org.debian.apt.policy.in.h:9
4955 msgid "Install package file"
4956 msgstr "Installeer pakketlêer"
4957
4958+#: ../data/org.debian.apt.policy.in.h:10
4959+msgid "To install this package, you need to authenticate."
4960+msgstr ""
4961+
4962+#: ../data/org.debian.apt.policy.in.h:11
4963+msgid "Update package information"
4964+msgstr "Opdateer pakketinformasie"
4965+
4966+#: ../data/org.debian.apt.policy.in.h:12
4967+msgid "To update the software catalog, you need to authenticate."
4968+msgstr ""
4969+
4970+#: ../data/org.debian.apt.policy.in.h:13
4971+msgid "Install or remove packages"
4972+msgstr ""
4973+
4974+#: ../data/org.debian.apt.policy.in.h:14
4975+msgid "To install or remove software, you need to authenticate."
4976+msgstr ""
4977+
4978+#. This privilege allows to call AddRepository, UpdateCache(Partially)
4979+#. and InstallPackages in a row and only authenticating once.
4980+#.
4981+#. The client has to authenticate for this privilege before calling
4982+#. the aptdaemon methods.
4983 #: ../data/org.debian.apt.policy.in.h:20
4984-msgid "List keys of trusted vendors"
4985+msgid "Add a new repository and install packages from it"
4986 msgstr ""
4987
4988 #: ../data/org.debian.apt.policy.in.h:21
4989-msgid "Set a proxy for software downloads"
4990-msgstr ""
4991-
4992-#: ../data/org.debian.apt.policy.in.h:22
4993-msgid "To cancel someone else's software changes, you need to authenticate."
4994-msgstr ""
4995-
4996-#: ../data/org.debian.apt.policy.in.h:23
4997-msgid "To change software repository settings, you need to authenticate."
4998-msgstr ""
4999-
5000-#: ../data/org.debian.apt.policy.in.h:24
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches