Merge lp:click/devel into lp:click

Proposed by Michael Vogt
Status: Merged
Approved by: Michael Vogt
Approved revision: 557
Merged at revision: 452
Proposed branch: lp:click/devel
Merge into: lp:click
Diff against target: 747 lines (+318/-153)
10 files modified
click/build.py (+4/-1)
click/chroot.py (+174/-128)
click/commands/install.py (+5/-1)
click/install.py (+17/-6)
click/tests/test_build.py (+2/-0)
click/tests/test_chroot.py (+14/-5)
click/tests/test_install.py (+5/-11)
debian/changelog (+30/-0)
debian/click.postinst (+3/-1)
lib/click/user.vala (+64/-0)
To merge this branch: bzr merge lp:click/devel
Reviewer Review Type Date Requested Status
Michael Vogt Approve
Review via email: mp+249631@code.launchpad.net

Commit message

Click 0.4.37 (skipping 0.4.36 to workaround version conflicts in PPAs): bugfixes, geoip based chroot mirror selection

Description of the change

  [ Michael Vogt ]
  * lp:~mvo/click/no-error-no-missing-systemctl:
    - fix a spurious error message on systems without systemctl
  * lp:~mvo/click/do-not-crash-in-build-on-broken-symlinks:
    - do not crash when building a click package that contains broken
      symlinks
  * lp:~mvo/click/dpkg-less-verbose:
    - do not show dpkg output on install unless --verbose is used
  * lp:~mvo/click/lp1394256-run-user-hooks:
    - ensures that click user hooks are run for all logged in users when
      click is used with "--all-users".
  * lp:~mvo/click/qt5-qmake-cross-armhf:
    - add qt5-qmake-arm-linux-gnueabihf to chroot (LP: #1393698)
  * lp:~mvo/click/chroot-15.04-multiarch:
    - add ubuntu-sdk-libs-tools and oxide-codecs-extra to the chroot
  * lp:~mvo/click/lp1394256-run-user-hooks-on-remove-too:
    - Run the click remove user hooks for all logged in users.
  * click/chroot.py:
    - use string.format() for chroot TARGET selection
  * skip 0.4.36 version and go straight to 0.4.37 (LP: #1418086)

  [ Zoltan Balogh ]
  * lp:~bzoltan/click/vivid-transition_mirrors:
    - use geoip to guess the most suitable country mirror when creating
      the click chroot

To post a comment you must log in.
Revision history for this message
Michael Vogt (mvo) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'click/build.py'
2--- click/build.py 2014-05-05 13:10:19 +0000
3+++ click/build.py 2015-02-13 12:37:00 +0000
4@@ -274,7 +274,10 @@
5 with open(md5sums_path, "w") as md5sums:
6 for path in sorted(self.list_files(root_path)):
7 md5 = hashlib.md5()
8- with open(os.path.join(root_path, path), "rb") as f:
9+ p = os.path.join(root_path, path)
10+ if not os.path.exists(p):
11+ continue
12+ with open(p, "rb") as f:
13 while True:
14 buf = f.read(16384)
15 if not buf:
16
17=== modified file 'click/chroot.py'
18--- click/chroot.py 2014-11-13 10:20:37 +0000
19+++ click/chroot.py 2015-02-13 12:37:00 +0000
20@@ -26,6 +26,8 @@
21 "ClickChrootDoesNotExistException",
22 ]
23
24+import urllib
25+import urllib.request
26 import os
27 import pwd
28 import re
29@@ -34,6 +36,7 @@
30 import subprocess
31 import sys
32 from textwrap import dedent
33+from xml.etree import ElementTree
34
35
36 framework_base = {
37@@ -67,114 +70,121 @@
38 # Please keep the lists of package names sorted.
39 extra_packages = {
40 "ubuntu-sdk-13.10": [
41- "libqt5opengl5-dev:TARGET",
42- "libqt5svg5-dev:TARGET",
43- "libqt5v8-5-dev:TARGET",
44- "libqt5webkit5-dev:TARGET",
45- "libqt5xmlpatterns5-dev:TARGET",
46- "qmlscene:TARGET",
47- "qt3d5-dev:TARGET",
48- "qt5-default:TARGET",
49- "qt5-qmake:TARGET",
50- "qtbase5-dev:TARGET",
51- "qtdeclarative5-dev:TARGET",
52- "qtmultimedia5-dev:TARGET",
53- "qtquick1-5-dev:TARGET",
54- "qtscript5-dev:TARGET",
55- "qtsensors5-dev:TARGET",
56- "qttools5-dev:TARGET",
57+ "libqt5opengl5-dev:{TARGET}",
58+ "libqt5svg5-dev:{TARGET}",
59+ "libqt5v8-5-dev:{TARGET}",
60+ "libqt5webkit5-dev:{TARGET}",
61+ "libqt5xmlpatterns5-dev:{TARGET}",
62+ "qmlscene:{TARGET}",
63+ "qt3d5-dev:{TARGET}",
64+ "qt5-default:{TARGET}",
65+ "qt5-qmake:{TARGET}",
66+ "qtbase5-dev:{TARGET}",
67+ "qtdeclarative5-dev:{TARGET}",
68+ "qtmultimedia5-dev:{TARGET}",
69+ "qtquick1-5-dev:{TARGET}",
70+ "qtscript5-dev:{TARGET}",
71+ "qtsensors5-dev:{TARGET}",
72+ "qttools5-dev:{TARGET}",
73 "ubuntu-ui-toolkit-doc",
74 ],
75 "ubuntu-sdk-14.04": [
76 "cmake",
77- "google-mock:TARGET",
78+ "google-mock:{TARGET}",
79 "intltool",
80- "libboost1.54-dev:TARGET",
81- "libjsoncpp-dev:TARGET",
82- "libprocess-cpp-dev:TARGET",
83- "libproperties-cpp-dev:TARGET",
84- "libqt5svg5-dev:TARGET",
85- "libqt5webkit5-dev:TARGET",
86- "libqt5xmlpatterns5-dev:TARGET",
87- "libunity-scopes-dev:TARGET",
88+ "libboost1.54-dev:{TARGET}",
89+ "libjsoncpp-dev:{TARGET}",
90+ "libprocess-cpp-dev:{TARGET}",
91+ "libproperties-cpp-dev:{TARGET}",
92+ "libqt5svg5-dev:{TARGET}",
93+ "libqt5webkit5-dev:{TARGET}",
94+ "libqt5xmlpatterns5-dev:{TARGET}",
95+ "libunity-scopes-dev:{TARGET}",
96 # bug #1316930, needed for autopilot
97 "python3",
98- "qmlscene:TARGET",
99- "qt3d5-dev:TARGET",
100- "qt5-default:TARGET",
101- "qtbase5-dev:TARGET",
102- "qtdeclarative5-dev:TARGET",
103+ "qmlscene:{TARGET}",
104+ "qt3d5-dev:{TARGET}",
105+ "qt5-default:{TARGET}",
106+ "qtbase5-dev:{TARGET}",
107+ "qtdeclarative5-dev:{TARGET}",
108 "qtdeclarative5-dev-tools",
109- "qtlocation5-dev:TARGET",
110- "qtmultimedia5-dev:TARGET",
111- "qtscript5-dev:TARGET",
112- "qtsensors5-dev:TARGET",
113- "qttools5-dev:TARGET",
114- "qttools5-dev-tools:TARGET",
115+ "qtlocation5-dev:{TARGET}",
116+ "qtmultimedia5-dev:{TARGET}",
117+ "qtscript5-dev:{TARGET}",
118+ "qtsensors5-dev:{TARGET}",
119+ "qttools5-dev:{TARGET}",
120+ "qttools5-dev-tools:{TARGET}",
121 "ubuntu-ui-toolkit-doc",
122 ],
123 "ubuntu-sdk-14.10": [
124 "cmake",
125 "cmake-extras",
126- "google-mock:TARGET",
127+ "google-mock:{TARGET}",
128 "intltool",
129- "libboost1.55-dev:TARGET",
130- "libcontent-hub-dev:TARGET",
131- "libjsoncpp-dev:TARGET",
132- "libnet-cpp-dev:TARGET",
133- "libprocess-cpp-dev:TARGET",
134- "libproperties-cpp-dev:TARGET",
135- "libqt5keychain0:TARGET",
136- "libqt5sensors5-dev:TARGET",
137- "libqt5svg5-dev:TARGET",
138- "libqt5webkit5-dev:TARGET",
139- "libqt5xmlpatterns5-dev:TARGET",
140- "libunity-scopes-dev:TARGET",
141+ "libboost1.55-dev:{TARGET}",
142+ "libcontent-hub-dev:{TARGET}",
143+ "libjsoncpp-dev:{TARGET}",
144+ "libnet-cpp-dev:{TARGET}",
145+ "libprocess-cpp-dev:{TARGET}",
146+ "libproperties-cpp-dev:{TARGET}",
147+ "libqt5keychain0:{TARGET}",
148+ "libqt5sensors5-dev:{TARGET}",
149+ "libqt5svg5-dev:{TARGET}",
150+ "libqt5webkit5-dev:{TARGET}",
151+ "libqt5xmlpatterns5-dev:{TARGET}",
152+ "libunity-scopes-dev:{TARGET}",
153 # bug #1316930, needed for autopilot
154 "python3",
155- "qml-module-qt-labs-settings:TARGET",
156- "qml-module-qtmultimedia:TARGET",
157- "qml-module-qtquick-layouts:TARGET",
158- "qml-module-qtsensors:TARGET",
159- "qml-module-qtwebkit:TARGET",
160- "qmlscene:TARGET",
161- "qt3d5-dev:TARGET",
162- "qt5-default:TARGET",
163- "qtdeclarative5-accounts-plugin:TARGET",
164+ "qml-module-qt-labs-settings:{TARGET}",
165+ "qml-module-qtmultimedia:{TARGET}",
166+ "qml-module-qtquick-layouts:{TARGET}",
167+ "qml-module-qtsensors:{TARGET}",
168+ "qml-module-qtwebkit:{TARGET}",
169+ "qmlscene:{TARGET}",
170+ "qt3d5-dev:{TARGET}",
171+ "qt5-default:{TARGET}",
172+ "qtdeclarative5-accounts-plugin:{TARGET}",
173 "qtdeclarative5-dev-tools",
174- "qtdeclarative5-folderlistmodel-plugin:TARGET",
175- "qtdeclarative5-localstorage-plugin:TARGET",
176- "qtdeclarative5-online-accounts-client0.1:TARGET",
177- "qtdeclarative5-particles-plugin:TARGET",
178- "qtdeclarative5-poppler1.0:TARGET",
179- "qtdeclarative5-qtlocation-plugin:TARGET",
180- "qtdeclarative5-qtorganizer-plugin:TARGET",
181- "qtdeclarative5-qtpositioning-plugin:TARGET",
182- "qtdeclarative5-u1db1.0:TARGET",
183- "qtdeclarative5-ubuntu-content0.1:TARGET",
184- "qtdeclarative5-ubuntu-download-manager0.1:TARGET",
185- "qtdeclarative5-ubuntu-mediascanner0.1:TARGET",
186- "qtdeclarative5-ubuntu-syncmonitor0.1:TARGET",
187- "qtdeclarative5-ubuntu-telephony-phonenumber0.1:TARGET",
188- "qtdeclarative5-ubuntu-ui-toolkit-plugin:TARGET",
189- "qtdeclarative5-usermetrics0.1:TARGET",
190- "qtdeclarative5-xmllistmodel-plugin:TARGET",
191- "qtlocation5-dev:TARGET",
192- "qtmultimedia5-dev:TARGET",
193- "qtscript5-dev:TARGET",
194- "qttools5-dev:TARGET",
195- "qttools5-dev-tools:TARGET",
196- "ubuntu-html5-theme:TARGET",
197+ "qtdeclarative5-folderlistmodel-plugin:{TARGET}",
198+ "qtdeclarative5-localstorage-plugin:{TARGET}",
199+ "qtdeclarative5-online-accounts-client0.1:{TARGET}",
200+ "qtdeclarative5-particles-plugin:{TARGET}",
201+ "qtdeclarative5-poppler1.0:{TARGET}",
202+ "qtdeclarative5-qtlocation-plugin:{TARGET}",
203+ "qtdeclarative5-qtorganizer-plugin:{TARGET}",
204+ "qtdeclarative5-qtpositioning-plugin:{TARGET}",
205+ "qtdeclarative5-u1db1.0:{TARGET}",
206+ "qtdeclarative5-ubuntu-content0.1:{TARGET}",
207+ "qtdeclarative5-ubuntu-download-manager0.1:{TARGET}",
208+ "qtdeclarative5-ubuntu-mediascanner0.1:{TARGET}",
209+ "qtdeclarative5-ubuntu-syncmonitor0.1:{TARGET}",
210+ "qtdeclarative5-ubuntu-telephony-phonenumber0.1:{TARGET}",
211+ "qtdeclarative5-ubuntu-ui-toolkit-plugin:{TARGET}",
212+ "qtdeclarative5-usermetrics0.1:{TARGET}",
213+ "qtdeclarative5-xmllistmodel-plugin:{TARGET}",
214+ "qtlocation5-dev:{TARGET}",
215+ "qtmultimedia5-dev:{TARGET}",
216+ "qtscript5-dev:{TARGET}",
217+ "qttools5-dev:{TARGET}",
218+ "qttools5-dev-tools:{TARGET}",
219+ "ubuntu-html5-theme:{TARGET}",
220 "ubuntu-ui-toolkit-doc",
221 ],
222 "ubuntu-sdk-15.04": [
223 # the sdk libs
224- "ubuntu-sdk-libs:TARGET",
225- "ubuntu-sdk-libs-dev:TARGET",
226+ "ubuntu-sdk-libs:{TARGET}",
227+ "ubuntu-sdk-libs-dev:{TARGET}",
228+ # the native build tools
229+ "ubuntu-sdk-libs-tools",
230+ # FIXME: see
231+ # http://pad.lv/~mvo/oxide/crossbuild-friendly/+merge/234093
232+ # we help the apt resolver here until the
233+ # oxideqt-codecs/oxidec-codecs-extras is sorted
234+ "oxideqt-codecs-extra",
235 ],
236 "ubuntu-core-15.04-dev1": [
237- "ubuntu-core-libs:TARGET",
238- "ubuntu-core-libs-dev:TARGET",
239+ "ubuntu-core-libs:{TARGET}",
240+ "ubuntu-core-libs-dev:{TARGET}",
241 ],
242 }
243
244@@ -185,6 +195,56 @@
245 non_meta_re = re.compile(r'^[a-zA-Z0-9+,./:=@_-]+$')
246
247
248+GEOIP_SERVER = "http://geoip.ubuntu.com/lookup"
249+
250+
251+def get_geoip_country_code_prefix():
252+ click_no_local_mirror = os.environ.get('CLICK_NO_LOCAL_MIRROR', 'auto')
253+ if click_no_local_mirror == '1':
254+ return ""
255+ try:
256+ with urllib.request.urlopen(GEOIP_SERVER) as f:
257+ xml_data = f.read()
258+ et = ElementTree.fromstring(xml_data)
259+ return et.find("CountryCode").text.lower()+"."
260+ except (ElementTree.ParseError, urllib.error.URLError):
261+ pass
262+ return ""
263+
264+def generate_sources(series, native_arch, target_arch,
265+ archive_mirror, ports_mirror, components):
266+ """Generate a list of strings for apts sources.list.
267+ Arguments:
268+ series -- the distro series (e.g. vivid)
269+ native_arch -- the native architecture (e.g. amd64)
270+ target_arch -- the target architecture (e.g. armhf)
271+ archive_mirror -- main mirror, e.g. http://archive.ubuntu.com/ubuntu
272+ ports_mirror -- ports mirror, e.g. http://ports.ubuntu.com/ubuntu-ports
273+ components -- the components as string, e.g. "main restricted universe"
274+ """
275+ pockets = ['%s' % series]
276+ for pocket in ['updates', 'security']:
277+ pockets.append('%s-%s' % (series, pocket))
278+ sources = []
279+ # write binary lines
280+ arches = [target_arch]
281+ if native_arch != target_arch:
282+ arches.append(native_arch)
283+ for arch in arches:
284+ if arch not in primary_arches:
285+ mirror = ports_mirror
286+ else:
287+ mirror = archive_mirror
288+ for pocket in pockets:
289+ sources.append("deb [arch=%s] %s %s %s" %
290+ (arch, mirror, pocket, components))
291+ # write source lines
292+ for pocket in pockets:
293+ sources.append("deb-src %s %s %s" %
294+ (archive_mirror, pocket, components))
295+ return sources
296+
297+
298 def shell_escape(command):
299 escaped = []
300 for arg in command:
301@@ -247,11 +307,7 @@
302 if chroots_dir is None:
303 chroots_dir = "/var/lib/schroot/chroots"
304 self.chroots_dir = chroots_dir
305- # this doesn't work because we are running this under sudo
306- if 'DEBOOTSTRAP_MIRROR' in os.environ:
307- self.archive = os.environ['DEBOOTSTRAP_MIRROR']
308- else:
309- self.archive = "http://archive.ubuntu.com/ubuntu"
310+
311 if "SUDO_USER" in os.environ:
312 self.user = os.environ["SUDO_USER"]
313 elif "PKEXEC_UID" in os.environ:
314@@ -330,31 +386,6 @@
315 users="\n".join(users),
316 mount=mount))
317
318- def _generate_sources(self, series, native_arch, target_arch, components):
319- ports_mirror = "http://ports.ubuntu.com/ubuntu-ports"
320- pockets = ['%s' % series]
321- for pocket in ['updates', 'security']:
322- pockets.append('%s-%s' % (series, pocket))
323- sources = []
324- # write binary lines
325- arches = [target_arch]
326- if native_arch != target_arch:
327- arches.append(native_arch)
328- for arch in arches:
329- if arch not in primary_arches:
330- mirror = ports_mirror
331- else:
332- mirror = self.archive
333- for pocket in pockets:
334- sources.append("deb [arch=%s] %s %s %s" %
335- (arch, mirror, pocket, components))
336- # write source lines
337- for pocket in pockets:
338- sources.append("deb-src %s %s %s" %
339- (self.archive, pocket, components))
340-
341- return sources
342-
343 def _generate_daemon_policy(self, mount):
344 daemon_policy = "%s/usr/sbin/policy-rc.d" % mount
345 with open(daemon_policy, "w") as policy:
346@@ -409,7 +440,7 @@
347 build_pkgs=' '.join(build_pkgs)))
348 return finish_script
349
350- def _debootstrap(self, components, mount):
351+ def _debootstrap(self, components, mount, archive):
352 subprocess.check_call([
353 "debootstrap",
354 "--arch", self.native_arch,
355@@ -417,7 +448,7 @@
356 "--components=%s" % ','.join(components),
357 self.series,
358 mount,
359- self.archive
360+ archive
361 ])
362
363 @property
364@@ -467,22 +498,37 @@
365 proxy = os.environ["http_proxy"]
366 if not proxy:
367 proxy = subprocess.check_output(
368- 'unset x; eval "$(apt-config shell x Acquire::HTTP::Proxy)"; echo "$x"',
369+ 'unset x; eval "$(apt-config shell x Acquire::HTTP::Proxy)"; \
370+ echo "$x"',
371 shell=True, universal_newlines=True).strip()
372 build_pkgs = [
373- "build-essential", "fakeroot",
374- "apt-utils", self._make_cross_package("g++"),
375- self._make_cross_package("pkg-config"), "cmake",
376- "dpkg-cross", "libc-dev:%s" % self.target_arch
377- ]
378+ # sort alphabetically
379+ "apt-utils",
380+ "build-essential",
381+ "cmake",
382+ "dpkg-cross",
383+ "fakeroot",
384+ "libc-dev:%s" % self.target_arch,
385+ # build pkg names dynamically
386+ self._make_cross_package("g++"),
387+ self._make_cross_package("pkg-config"),
388+ ]
389 for package in extra_packages.get(self.framework_base, []):
390- package = package.replace(":TARGET", ":%s" % self.target_arch)
391+ package = package.format(TARGET=self.target_arch)
392 build_pkgs.append(package)
393 os.makedirs(mount)
394- self._debootstrap(components, mount)
395- sources = self._generate_sources(self.series, self.native_arch,
396- self.target_arch,
397- ' '.join(components))
398+
399+ country_code = get_geoip_country_code_prefix()
400+ archive = "http://%sarchive.ubuntu.com/ubuntu" % country_code
401+ ports_mirror = "http://%sports.ubuntu.com/ubuntu-ports" % country_code
402+ # this doesn't work because we are running this under sudo
403+ if 'DEBOOTSTRAP_MIRROR' in os.environ:
404+ archive = os.environ['DEBOOTSTRAP_MIRROR']
405+ self._debootstrap(components, mount, archive)
406+ sources = generate_sources(self.series, self.native_arch,
407+ self.target_arch,
408+ archive, ports_mirror,
409+ ' '.join(components))
410 with open("%s/etc/apt/sources.list" % mount, "w") as sources_list:
411 for line in sources:
412 print(line, file=sources_list)
413
414=== modified file 'click/commands/install.py'
415--- click/commands/install.py 2014-09-10 12:28:49 +0000
416+++ click/commands/install.py 2015-02-13 12:37:00 +0000
417@@ -46,6 +46,9 @@
418 parser.add_option(
419 "--allow-unauthenticated", default=False, action="store_true",
420 help="allow installing packages with no signatures")
421+ parser.add_option(
422+ "--verbose", default=False, action="store_true",
423+ help="be more verbose on install")
424 options, args = parser.parse_args(argv)
425 if len(args) < 1:
426 parser.error("need package file name")
427@@ -59,7 +62,8 @@
428 allow_unauthenticated=options.allow_unauthenticated)
429 try:
430 installer.install(
431- package_path, user=options.user, all_users=options.all_users)
432+ package_path, user=options.user, all_users=options.all_users,
433+ quiet=not options.verbose)
434 except ClickInstallerError as e:
435 print("Cannot install %s: %s" % (package_path, e), file=sys.stderr)
436 return 1
437
438=== modified file 'click/install.py'
439--- click/install.py 2014-09-10 11:50:18 +0000
440+++ click/install.py 2015-02-13 12:37:00 +0000
441@@ -347,7 +347,7 @@
442 os.mkdir(os.path.join(admin_dir, "updates"))
443 os.mkdir(os.path.join(admin_dir, "triggers"))
444
445- def _unpack(self, path, user=None, all_users=False):
446+ def _unpack(self, path, user=None, all_users=False, quiet=True):
447 package_name, package_version = self.audit(path, check_arch=True)
448
449 # Is this package already unpacked in an underlay (non-topmost)
450@@ -401,9 +401,20 @@
451 kwargs = {}
452 if sys.version >= "3.2":
453 kwargs["pass_fds"] = (fd.fileno(),)
454- subprocess.check_call(
455- command, preexec_fn=partial(self._install_preexec, inst_dir),
456- env=env, **kwargs)
457+ if quiet:
458+ fn = subprocess.check_output
459+ kwargs["stderr"] = subprocess.STDOUT
460+ else:
461+ fn = subprocess.check_call
462+ try:
463+ fn(command,
464+ preexec_fn=partial(self._install_preexec, inst_dir),
465+ env=env, universal_newlines=True,
466+ **kwargs)
467+ except subprocess.CalledProcessError as e:
468+ logging.error("%s failed with exit_code %s:\n%s" % (
469+ command, e.returncode, e.output))
470+ raise
471 for dirpath, dirnames, filenames in os.walk(inst_dir):
472 for entry in dirnames + filenames:
473 entry_path = os.path.join(dirpath, entry)
474@@ -441,9 +452,9 @@
475
476 return package_name, package_version, old_version
477
478- def install(self, path, user=None, all_users=False):
479+ def install(self, path, user=None, all_users=False, quiet=True):
480 package_name, package_version, old_version = self._unpack(
481- path, user=user, all_users=all_users)
482+ path, user=user, all_users=all_users, quiet=quiet)
483
484 if user is not None or all_users:
485 if all_users:
486
487=== modified file 'click/tests/test_build.py'
488--- click/tests/test_build.py 2014-09-04 13:41:30 +0000
489+++ click/tests/test_build.py 2015-02-13 12:37:00 +0000
490@@ -134,6 +134,8 @@
491 touch(os.path.join(scratch, ".git", "config"))
492 with mkfile(os.path.join(scratch, "toplevel")) as f:
493 f.write("test /toplevel\n")
494+ os.symlink(
495+ "file-does-not-exist", os.path.join(scratch, "broken-symlink"))
496 with mkfile(os.path.join(scratch, "manifest.json")) as f:
497 json.dump({
498 "name": "com.example.test",
499
500=== modified file 'click/tests/test_chroot.py'
501--- click/tests/test_chroot.py 2014-07-02 09:07:13 +0000
502+++ click/tests/test_chroot.py 2015-02-13 12:37:00 +0000
503@@ -28,6 +28,7 @@
504
505 from click.chroot import (
506 ClickChroot,
507+ generate_sources,
508 strip_dev_series_from_framework,
509 )
510 from click.tests.helpers import TestCase, mock
511@@ -48,7 +49,7 @@
512 self._maint_kwargs = kwargs
513 return 0
514
515- def _debootstrap(self, components, mount):
516+ def _debootstrap(self, components, mount, archive_server):
517 os.makedirs(os.path.join(mount, "etc", "apt"))
518 os.makedirs(os.path.join(mount, "usr", "sbin"))
519 os.makedirs(os.path.join(mount, "sbin"))
520@@ -110,8 +111,10 @@
521 def test_gen_sources_archive_only(self):
522 chroot = ClickChroot("amd64", "ubuntu-sdk-13.10", series="trusty")
523 chroot.native_arch = "i386"
524- sources = chroot._generate_sources(
525+ sources = generate_sources(
526 chroot.series, chroot.native_arch, chroot.target_arch,
527+ "http://archive.ubuntu.com/ubuntu",
528+ "http://ports.ubuntu.com/ubuntu-ports",
529 "main")
530 self.assertEqual([
531 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu trusty main',
532@@ -128,8 +131,10 @@
533 def test_gen_sources_mixed_archive_ports(self):
534 chroot = ClickChroot("armhf", "ubuntu-sdk-13.10", series="trusty")
535 chroot.native_arch = "i386"
536- sources = chroot._generate_sources(
537+ sources = generate_sources(
538 chroot.series, chroot.native_arch, chroot.target_arch,
539+ "http://archive.ubuntu.com/ubuntu",
540+ "http://ports.ubuntu.com/ubuntu-ports",
541 "main")
542 self.assertEqual([
543 'deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports trusty main',
544@@ -146,8 +151,10 @@
545 def test_gen_sources_ports_only(self):
546 chroot = ClickChroot("armhf", "ubuntu-sdk-13.10", series="trusty")
547 chroot.native_arch = "armel"
548- sources = chroot._generate_sources(
549+ sources = generate_sources(
550 chroot.series, chroot.native_arch, chroot.target_arch,
551+ "http://archive.ubuntu.com/ubuntu",
552+ "http://ports.ubuntu.com/ubuntu-ports",
553 "main")
554 self.assertEqual([
555 'deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports trusty main',
556@@ -164,8 +171,10 @@
557 def test_gen_sources_native(self):
558 chroot = ClickChroot("i386", "ubuntu-sdk-14.04", series="trusty")
559 chroot.native_arch = "i386"
560- sources = chroot._generate_sources(
561+ sources = generate_sources(
562 chroot.series, chroot.native_arch, chroot.target_arch,
563+ "http://archive.ubuntu.com/ubuntu",
564+ "http://ports.ubuntu.com/ubuntu-ports",
565 "main")
566 self.assertEqual([
567 'deb [arch=i386] http://archive.ubuntu.com/ubuntu trusty main',
568
569=== modified file 'click/tests/test_install.py'
570--- click/tests/test_install.py 2014-08-19 06:32:16 +0000
571+++ click/tests/test_install.py 2015-02-13 12:37:00 +0000
572@@ -456,18 +456,12 @@
573 with self.run_in_subprocess(
574 "click_get_frameworks_dir") as (enter, preloads):
575 enter()
576- original_call = subprocess.call
577+ original_call = subprocess.check_output
578
579 def call_side_effect(*args, **kwargs):
580- if "TEST_VERBOSE" in os.environ:
581- return original_call(
582- ["touch", os.path.join(self.temp_dir, "sentinel")],
583- **kwargs)
584- else:
585- with open("/dev/null", "w") as devnull:
586- return original_call(
587- ["touch", os.path.join(self.temp_dir, "sentinel")],
588- stdout=devnull, stderr=devnull, **kwargs)
589+ return original_call(
590+ ["touch", os.path.join(self.temp_dir, "sentinel")],
591+ **kwargs)
592
593 path = self.make_fake_package(
594 control_fields={
595@@ -490,7 +484,7 @@
596 db.add(root)
597 installer = ClickInstaller(db)
598 self._setup_frameworks(preloads, frameworks=["ubuntu-sdk-13.10"])
599- with mock.patch("subprocess.call") as mock_call:
600+ with mock.patch("subprocess.check_output") as mock_call:
601 mock_call.side_effect = call_side_effect
602 self.assertRaises(
603 subprocess.CalledProcessError, installer.install, path)
604
605=== modified file 'debian/changelog'
606--- debian/changelog 2014-11-14 12:29:14 +0000
607+++ debian/changelog 2015-02-13 12:37:00 +0000
608@@ -1,3 +1,33 @@
609+click (0.4.37) UNRELEASED; urgency=low
610+
611+ [ Michael Vogt ]
612+ * lp:~mvo/click/no-error-no-missing-systemctl:
613+ - fix a spurious error message on systems without systemctl
614+ * lp:~mvo/click/do-not-crash-in-build-on-broken-symlinks:
615+ - do not crash when building a click package that contains broken
616+ symlinks
617+ * lp:~mvo/click/dpkg-less-verbose:
618+ - do not show dpkg output on install unless --verbose is used
619+ * lp:~mvo/click/lp1394256-run-user-hooks:
620+ - ensures that click user hooks are run for all logged in users when
621+ click is used with "--all-users".
622+ * lp:~mvo/click/qt5-qmake-cross-armhf:
623+ - add qt5-qmake-arm-linux-gnueabihf to chroot (LP: #1393698)
624+ * lp:~mvo/click/chroot-15.04-multiarch:
625+ - add ubuntu-sdk-libs-tools and oxide-codecs-extra to the chroot
626+ * lp:~mvo/click/lp1394256-run-user-hooks-on-remove-too:
627+ - Run the click remove user hooks for all logged in users.
628+ * click/chroot.py:
629+ - use string.format() for chroot TARGET selection
630+ * skip 0.4.36 version and go straight to 0.4.37 (LP: #1418086)
631+
632+ [ Zoltan Balogh ]
633+ * lp:~bzoltan/click/vivid-transition_mirrors:
634+ - use geoip to guess the most suitable country mirror when creating
635+ the click chroot
636+
637+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 14 Nov 2014 12:29:14 +0000
638+
639 click (0.4.35) vivid; urgency=low
640
641 [ Michael Vogt ]
642
643=== modified file 'debian/click.postinst'
644--- debian/click.postinst 2014-10-14 09:47:48 +0000
645+++ debian/click.postinst 2015-02-13 12:37:00 +0000
646@@ -13,7 +13,9 @@
647
648 # dh-systemd has no support yet for user systemd units
649 # so we need to do this manually here
650- systemctl --global enable click-user-hooks.service || true
651+ if which systemctl >/dev/null 2>&1; then
652+ systemctl --global enable click-user-hooks.service || true
653+ fi
654 fi
655
656 #DEBHELPER#
657
658=== modified file 'lib/click/user.vala'
659--- lib/click/user.vala 2014-09-29 13:23:12 +0000
660+++ lib/click/user.vala 2015-02-13 12:37:00 +0000
661@@ -33,8 +33,21 @@
662 * symlinks per user.
663 */
664
665+
666 namespace Click {
667
668+ struct LogindUser {
669+ uint32 uid;
670+ string name;
671+ string ObjectPath;
672+ }
673+
674+ /* the logind dbus interface */
675+ [DBus (name = "org.freedesktop.login1.Manager")]
676+ interface LogindManager : Object {
677+ public abstract LogindUser[] ListUsers () throws IOError;
678+ }
679+
680 /* Pseudo-usernames selected to be invalid as a real username, and alluding
681 * to group syntaxes used in other systems.
682 */
683@@ -596,6 +609,53 @@
684 if (! is_pseudo_user)
685 package_install_hooks (db, package,
686 old_version, version, name);
687+
688+ // run user hooks for all logged in users
689+ if (name == ALL_USERS)
690+ run_user_install_hooks_for_all_logged_in_users (package, old_version, version);
691+ }
692+
693+ private string[]
694+ get_logged_in_users()
695+ {
696+ string[] logged_in_users = {};
697+ try {
698+ LogindManager logind = Bus.get_proxy_sync (
699+ BusType.SYSTEM,
700+ "org.freedesktop.login1",
701+ "/org/freedesktop/login1");
702+ var users = logind.ListUsers();
703+ foreach (LogindUser user in users)
704+ {
705+ // FIXME: ideally we would read from /etc/adduser.conf
706+ if(user.uid >= 1000 && user.uid <= 30000)
707+ {
708+ logged_in_users += user.name;
709+ }
710+ }
711+ } catch (Error e) {
712+ warning ("Can not connect to logind");
713+ }
714+ return logged_in_users;
715+ }
716+
717+ private void
718+ run_user_install_hooks_for_all_logged_in_users (string package,
719+ string? old_version,
720+ string version) throws IOError
721+ {
722+ foreach (string username in get_logged_in_users())
723+ package_install_hooks (db, package,
724+ old_version, version, username);
725+ }
726+
727+ private void
728+ run_user_remove_hooks_for_all_logged_in_users (string package,
729+ string old_version) throws IOError
730+ {
731+ foreach (string username in get_logged_in_users())
732+ package_remove_hooks (db, package,
733+ old_version, username);
734 }
735
736 private bool
737@@ -688,6 +748,10 @@
738
739 if (! is_pseudo_user)
740 package_remove_hooks (db, package, old_version, name);
741+
742+ // run user hooks for all logged in users
743+ if (name == ALL_USERS)
744+ run_user_remove_hooks_for_all_logged_in_users (package, old_version);
745 }
746
747 /**

Subscribers

People subscribed via source and target branches

to all changes: