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