| Status: | Merged |
|---|---|
| Approved by: | Michael Vogt on 2015-02-24 |
| Approved revision: | 562 |
| Merged at revision: | 454 |
| Proposed branch: | lp:click/devel |
| Merge into: | lp:click |
| Diff against target: |
798 lines (+285/-160) 14 files modified
click/build.py (+48/-71) click/commands/build.py (+5/-0) click/commands/buildsource.py (+6/-0) click/framework.py (+19/-13) click/tests/helpers.py (+21/-0) click/tests/test_build.py (+37/-35) click/tests/test_database.py (+12/-0) click/tests/test_user.py (+22/-8) debian/changelog (+17/-0) debian/rules (+1/-1) doc/manpage.rst (+12/-2) lib/click/database.vala (+29/-3) lib/click/user.vala (+48/-27) pk-plugin/pk-plugin-click.c (+8/-0) |
| To merge this branch: | bzr merge lp:click/devel |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| click hackers | 2015-02-23 | Pending | |
|
Review via email:
|
|||
Commit Message
Click 0.4.38: stop apps when uninstalling them, fix crash on empty db, add --ignore option to click build, fix framework validation for snappy frameworks
Description of the Change
click (0.4.38) UNRELEASED; urgency=low
* lp:~mvo/click/lp1232130-kill-on-remove-2:
- When uninstalling a app, stop it if its running (LP: #1232130)
* lp:~mvo/click/dont-crash-for-empty-db:
- Do not crash when no database configuration is used and
Click.
* lp:~mvo/click/lp1219912-build-exclude:
- add a new --ignore option to click {build,buildsource}
(LP: #1219912)
* lp:~mvo/click/fix-multiple-framework-validation:
- fix framework validation for snappy
-- Michael Vogt <email address hidden> Mon, 23 Feb 2015 08:20:04 +0100
- 563. By Michael Vogt on 2015-02-24
- 564. By Michael Vogt on 2015-02-24
-
bump version number
- 565. By Michael Vogt on 2015-02-24
-
bump version number
- 566. By Michael Vogt on 2015-02-24
-
run debian/
packagekit- check with "sh" as something in jenkins
made it mode 0644 - 567. By Michael Vogt on 2015-02-26
Preview Diff
| 1 | === modified file 'click/build.py' |
| 2 | --- click/build.py 2015-01-19 10:26:26 +0000 |
| 3 | +++ click/build.py 2015-02-26 17:06:20 +0000 |
| 4 | @@ -83,6 +83,42 @@ |
| 5 | class ClickBuilderBase: |
| 6 | def __init__(self): |
| 7 | self.file_map = {} |
| 8 | + # From @Dpkg::Source::Package::tar_ignore_default_pattern. |
| 9 | + # (more in ClickSourceBuilder) |
| 10 | + self._ignore_patterns = [ |
| 11 | + "*.click", |
| 12 | + ".*.sw?", |
| 13 | + "*~", |
| 14 | + ",,*", |
| 15 | + ".[#~]*", |
| 16 | + ".arch-ids", |
| 17 | + ".arch-inventory", |
| 18 | + ".bzr", |
| 19 | + ".bzr-builddeb", |
| 20 | + ".bzr.backup", |
| 21 | + ".bzr.tags", |
| 22 | + ".bzrignore", |
| 23 | + ".cvsignore", |
| 24 | + ".git", |
| 25 | + ".gitattributes", |
| 26 | + ".gitignore", |
| 27 | + ".gitmodules", |
| 28 | + ".hg", |
| 29 | + ".hgignore", |
| 30 | + ".hgsigs", |
| 31 | + ".hgtags", |
| 32 | + ".shelf", |
| 33 | + ".svn", |
| 34 | + "CVS", |
| 35 | + "DEADJOE", |
| 36 | + "RCS", |
| 37 | + "_MTN", |
| 38 | + "_darcs", |
| 39 | + "{arch}", |
| 40 | + ] |
| 41 | + |
| 42 | + def add_ignore_pattern(self, pattern): |
| 43 | + self._ignore_patterns.append(pattern) |
| 44 | |
| 45 | def add_file(self, source_path, dest_path): |
| 46 | self.file_map[source_path] = dest_path |
| 47 | @@ -132,39 +168,6 @@ |
| 48 | |
| 49 | |
| 50 | class ClickBuilder(ClickBuilderBase): |
| 51 | - # TODO: This should be configurable, or at least extensible. |
| 52 | - _ignore_patterns = [ |
| 53 | - "*.click", |
| 54 | - ".*.sw?", |
| 55 | - "*~", |
| 56 | - ",,*", |
| 57 | - ".[#~]*", |
| 58 | - ".arch-ids", |
| 59 | - ".arch-inventory", |
| 60 | - ".be", |
| 61 | - ".bzr", |
| 62 | - ".bzr-builddeb", |
| 63 | - ".bzr.backup", |
| 64 | - ".bzr.tags", |
| 65 | - ".bzrignore", |
| 66 | - ".cvsignore", |
| 67 | - ".git", |
| 68 | - ".gitattributes", |
| 69 | - ".gitignore", |
| 70 | - ".gitmodules", |
| 71 | - ".hg", |
| 72 | - ".hgignore", |
| 73 | - ".hgsigs", |
| 74 | - ".hgtags", |
| 75 | - ".shelf", |
| 76 | - ".svn", |
| 77 | - "CVS", |
| 78 | - "DEADJOE", |
| 79 | - "RCS", |
| 80 | - "_MTN", |
| 81 | - "_darcs", |
| 82 | - "{arch}", |
| 83 | - ] |
| 84 | |
| 85 | def list_files(self, root_path): |
| 86 | for dirpath, _, filenames in os.walk(root_path): |
| 87 | @@ -298,44 +301,18 @@ |
| 88 | |
| 89 | |
| 90 | class ClickSourceBuilder(ClickBuilderBase): |
| 91 | - # From @Dpkg::Source::Package::tar_ignore_default_pattern. |
| 92 | - # TODO: This should be configurable, or at least extensible. |
| 93 | - _ignore_patterns = [ |
| 94 | - "*.a", |
| 95 | - "*.click", |
| 96 | - "*.la", |
| 97 | - "*.o", |
| 98 | - "*.so", |
| 99 | - ".*.sw?", |
| 100 | - "*~", |
| 101 | - ",,*", |
| 102 | - ".[#~]*", |
| 103 | - ".arch-ids", |
| 104 | - ".arch-inventory", |
| 105 | - ".be", |
| 106 | - ".bzr", |
| 107 | - ".bzr-builddeb", |
| 108 | - ".bzr.backup", |
| 109 | - ".bzr.tags", |
| 110 | - ".bzrignore", |
| 111 | - ".cvsignore", |
| 112 | - ".deps", |
| 113 | - ".git", |
| 114 | - ".gitattributes", |
| 115 | - ".gitignore", |
| 116 | - ".gitmodules", |
| 117 | - ".hg", |
| 118 | - ".hgignore", |
| 119 | - ".hgsigs", |
| 120 | - ".hgtags", |
| 121 | - ".shelf", |
| 122 | - ".svn", |
| 123 | - "CVS", |
| 124 | - "DEADJOE", |
| 125 | - "RCS", |
| 126 | - "_MTN", |
| 127 | - "_darcs", |
| 128 | - "{arch}", |
| 129 | + |
| 130 | + def __init__(self): |
| 131 | + super(ClickSourceBuilder, self).__init__() |
| 132 | + # From @Dpkg::Source::Package::tar_ignore_default_pattern. |
| 133 | + # (more in ClickBuilderBase) |
| 134 | + self._ignore_patterns += [ |
| 135 | + "*.a", |
| 136 | + ".be", |
| 137 | + ".deps", |
| 138 | + "*.la", |
| 139 | + "*.o", |
| 140 | + "*.so", |
| 141 | ] |
| 142 | |
| 143 | def build(self, dest_dir, manifest_path=None): |
| 144 | |
| 145 | === modified file 'click/commands/build.py' |
| 146 | --- click/commands/build.py 2014-09-05 14:03:19 +0000 |
| 147 | +++ click/commands/build.py 2015-02-26 17:06:20 +0000 |
| 148 | @@ -34,6 +34,9 @@ |
| 149 | parser.add_option( |
| 150 | "--no-validate", action="store_false", default=True, dest="validate", |
| 151 | help="Don't run click-reviewers-tools check on resulting .click") |
| 152 | + parser.add_option( |
| 153 | + "-I", "--ignore", metavar="file-pattern", action='append', default=[], |
| 154 | + help="Ignore the given pattern when building the package") |
| 155 | options, args = parser.parse_args(argv) |
| 156 | if len(args) < 1: |
| 157 | parser.error("need directory") |
| 158 | @@ -48,6 +51,8 @@ |
| 159 | (directory, options.manifest)) |
| 160 | builder = ClickBuilder() |
| 161 | builder.add_file(directory, "./") |
| 162 | + for ignore in options.ignore: |
| 163 | + builder.add_ignore_pattern(ignore) |
| 164 | try: |
| 165 | path = builder.build(".", manifest_path=options.manifest) |
| 166 | except ClickBuildError as e: |
| 167 | |
| 168 | === modified file 'click/commands/buildsource.py' |
| 169 | --- click/commands/buildsource.py 2014-06-17 08:25:27 +0000 |
| 170 | +++ click/commands/buildsource.py 2015-02-26 17:06:20 +0000 |
| 171 | @@ -29,6 +29,10 @@ |
| 172 | parser.add_option( |
| 173 | "-m", "--manifest", metavar="PATH", |
| 174 | help="read package manifest from PATH") |
| 175 | + parser.add_option( |
| 176 | + "-I", "--ignore", metavar="file-pattern", action='append', |
| 177 | + default=[], |
| 178 | + help="Ignore the given pattern when building the package") |
| 179 | options, args = parser.parse_args(argv) |
| 180 | if len(args) < 1: |
| 181 | parser.error("need directory") |
| 182 | @@ -45,6 +49,8 @@ |
| 183 | (directory, options.manifest)) |
| 184 | builder = ClickSourceBuilder() |
| 185 | builder.add_file(directory, "./") |
| 186 | + for ignore in options.ignore: |
| 187 | + builder.add_ignore_pattern(ignore) |
| 188 | try: |
| 189 | path = builder.build(".", manifest_path=options.manifest) |
| 190 | except ClickBuildError as e: |
| 191 | |
| 192 | === modified file 'click/framework.py' |
| 193 | --- click/framework.py 2014-06-23 21:14:06 +0000 |
| 194 | +++ click/framework.py 2015-02-26 17:06:20 +0000 |
| 195 | @@ -31,12 +31,6 @@ |
| 196 | pass |
| 197 | |
| 198 | |
| 199 | -# FIXME: use native lib if available |
| 200 | -#from gi.repository import Click |
| 201 | -#click_framework_get_base_version = Click.framework_get_base_version |
| 202 | -#click_framework_has_framework = Click.has_framework |
| 203 | - |
| 204 | - |
| 205 | # python version of the vala parse_deb822_file() |
| 206 | def parse_deb822_file(filename): |
| 207 | data = {} |
| 208 | @@ -76,6 +70,12 @@ |
| 209 | return deb822.get("base-version", None) |
| 210 | |
| 211 | |
| 212 | +# python version of the vala click_framework_get_base_version() |
| 213 | +def click_framework_get_base_name(framework_name): |
| 214 | + deb822 = parse_deb822_file(get_framework_path(framework_name)) |
| 215 | + return deb822.get("base-name", None) |
| 216 | + |
| 217 | + |
| 218 | # python version of the vala click_framework_has_framework |
| 219 | def click_framework_has_framework(framework_name): |
| 220 | return os.path.exists(get_framework_path(framework_name)) |
| 221 | @@ -94,7 +94,7 @@ |
| 222 | raise ClickFrameworkInvalid( |
| 223 | 'Could not parse framework "%s"' % framework_string) |
| 224 | |
| 225 | - framework_base_versions = set() |
| 226 | + base_name_versions = {} |
| 227 | missing_frameworks = [] |
| 228 | for or_dep in parsed_framework: |
| 229 | if len(or_dep) > 1: |
| 230 | @@ -110,9 +110,20 @@ |
| 231 | if not click_framework_has_framework(framework_name): |
| 232 | missing_frameworks.append(framework_name) |
| 233 | continue |
| 234 | + # ensure we do not use different base versions for the same base-name |
| 235 | + framework_base_name = click_framework_get_base_name( |
| 236 | + framework_name) |
| 237 | framework_base_version = click_framework_get_base_version( |
| 238 | framework_name) |
| 239 | - framework_base_versions.add(framework_base_version) |
| 240 | + prev = base_name_versions.get(framework_base_name, None) |
| 241 | + if prev and prev != framework_base_version: |
| 242 | + raise ClickFrameworkInvalid( |
| 243 | + 'Multiple frameworks with different base versions are not ' |
| 244 | + 'allowed. Found: {} ({} != {})'.format( |
| 245 | + framework_base_name, |
| 246 | + framework_base_version, |
| 247 | + base_name_versions[framework_base_name])) |
| 248 | + base_name_versions[framework_base_name] = framework_base_version |
| 249 | |
| 250 | if not ignore_missing_frameworks: |
| 251 | if len(missing_frameworks) > 1: |
| 252 | @@ -132,8 +143,3 @@ |
| 253 | elif missing_frameworks: |
| 254 | logging.warning('Ignoring missing framework "%s"' % ( |
| 255 | missing_frameworks[0])) |
| 256 | - |
| 257 | - if len(framework_base_versions) > 1: |
| 258 | - raise ClickFrameworkInvalid( |
| 259 | - 'Multiple frameworks with different base versions are not ' |
| 260 | - 'allowed. Found: {0}'.format(framework_base_versions)) |
| 261 | |
| 262 | === modified file 'click/tests/helpers.py' |
| 263 | --- click/tests/helpers.py 2014-09-29 13:23:52 +0000 |
| 264 | +++ click/tests/helpers.py 2015-02-26 17:06:20 +0000 |
| 265 | @@ -30,6 +30,7 @@ |
| 266 | |
| 267 | import contextlib |
| 268 | from functools import wraps |
| 269 | +import json |
| 270 | import os |
| 271 | import re |
| 272 | import shutil |
| 273 | @@ -59,6 +60,26 @@ |
| 274 | return wrapper |
| 275 | |
| 276 | |
| 277 | +def make_installed_click(db, db_dir, package="test-1", version="1.0", |
| 278 | + json_data={}, make_current=True, user="@all"): |
| 279 | + """Create a fake installed click package for the given db/db_dir""" |
| 280 | + json_data["name"] = package |
| 281 | + json_data["version"] = version |
| 282 | + with mkfile_utf8(os.path.join( |
| 283 | + db_dir, package, version, ".click", "info", |
| 284 | + "%s.manifest" % package)) as f: |
| 285 | + json.dump(json_data, f, ensure_ascii=False) |
| 286 | + if make_current: |
| 287 | + os.symlink( |
| 288 | + version, os.path.join(db_dir, package, "current")) |
| 289 | + if user == "@all": |
| 290 | + registry = Click.User.for_all_users(db) |
| 291 | + else: |
| 292 | + registry = Click.User.for_user(db, user) |
| 293 | + registry.set_version(package, version) |
| 294 | + return os.path.join(db_dir, package, version) |
| 295 | + |
| 296 | + |
| 297 | class TestCase(gimock.GIMockTestCase): |
| 298 | def setUp(self): |
| 299 | super(TestCase, self).setUp() |
| 300 | |
| 301 | === modified file 'click/tests/test_build.py' |
| 302 | --- click/tests/test_build.py 2015-01-19 10:26:26 +0000 |
| 303 | +++ click/tests/test_build.py 2015-02-26 17:06:20 +0000 |
| 304 | @@ -207,21 +207,37 @@ |
| 305 | self.assertEqual( |
| 306 | "foo", os.readlink(os.path.join(extract_path, "bin", "bar"))) |
| 307 | |
| 308 | + def _make_scratch_dir(self, manifest_override={}): |
| 309 | + self.use_temp_dir() |
| 310 | + scratch = os.path.join(self.temp_dir, "scratch") |
| 311 | + manifest = { |
| 312 | + "name": "com.example.test", |
| 313 | + "version": "1.0", |
| 314 | + "maintainer": "Foo Bar <foo@example.org>", |
| 315 | + "title": "test title", |
| 316 | + "architecture": "all", |
| 317 | + "framework": "ubuntu-sdk-13.10", |
| 318 | + } |
| 319 | + manifest.update(manifest_override) |
| 320 | + with mkfile(os.path.join(scratch, "manifest.json")) as f: |
| 321 | + json.dump(manifest, f) |
| 322 | + self.builder.add_file(scratch, "/") |
| 323 | + return scratch |
| 324 | + |
| 325 | @disable_logging |
| 326 | def test_build_excludes_dot_click(self): |
| 327 | - self.use_temp_dir() |
| 328 | - scratch = os.path.join(self.temp_dir, "scratch") |
| 329 | + scratch = self._make_scratch_dir() |
| 330 | touch(os.path.join(scratch, ".click", "evil-file")) |
| 331 | - with mkfile(os.path.join(scratch, "manifest.json")) as f: |
| 332 | - json.dump({ |
| 333 | - "name": "com.example.test", |
| 334 | - "version": "1.0", |
| 335 | - "maintainer": "Foo Bar <foo@example.org>", |
| 336 | - "title": "test title", |
| 337 | - "architecture": "all", |
| 338 | - "framework": "ubuntu-sdk-13.10", |
| 339 | - }, f) |
| 340 | + path = self.builder.build(self.temp_dir) |
| 341 | + extract_path = os.path.join(self.temp_dir, "extract") |
| 342 | + subprocess.check_call(["dpkg-deb", "-x", path, extract_path]) |
| 343 | + self.assertEqual([], os.listdir(extract_path)) |
| 344 | + |
| 345 | + def test_build_ignore_pattern(self): |
| 346 | + scratch = self._make_scratch_dir() |
| 347 | + touch(os.path.join(scratch, "build", "foo.o")) |
| 348 | self.builder.add_file(scratch, "/") |
| 349 | + self.builder.add_ignore_pattern("build") |
| 350 | path = self.builder.build(self.temp_dir) |
| 351 | extract_path = os.path.join(self.temp_dir, "extract") |
| 352 | subprocess.check_call(["dpkg-deb", "-x", path, extract_path]) |
| 353 | @@ -229,18 +245,9 @@ |
| 354 | |
| 355 | @disable_logging |
| 356 | def test_build_multiple_architectures(self): |
| 357 | - self.use_temp_dir() |
| 358 | - scratch = os.path.join(self.temp_dir, "scratch") |
| 359 | - with mkfile(os.path.join(scratch, "manifest.json")) as f: |
| 360 | - json.dump({ |
| 361 | - "name": "com.example.test", |
| 362 | - "version": "1.0", |
| 363 | - "maintainer": "Foo Bar <foo@example.org>", |
| 364 | - "title": "test title", |
| 365 | + scratch = self._make_scratch_dir(manifest_override={ |
| 366 | "architecture": ["armhf", "i386"], |
| 367 | - "framework": "ubuntu-sdk-13.10", |
| 368 | - }, f) |
| 369 | - self.builder.add_file(scratch, "/") |
| 370 | + }) |
| 371 | path = os.path.join(self.temp_dir, "com.example.test_1.0_multi.click") |
| 372 | self.assertEqual(path, self.builder.build(self.temp_dir)) |
| 373 | self.assertTrue(os.path.exists(path)) |
| 374 | @@ -255,22 +262,12 @@ |
| 375 | del target_json["installed-size"] |
| 376 | self.assertEqual(source_json, target_json) |
| 377 | |
| 378 | - # FIXME: DRY violation with test_build_multiple_architectures etc |
| 379 | @disable_logging |
| 380 | def test_build_multiple_frameworks(self): |
| 381 | - self.use_temp_dir() |
| 382 | - scratch = os.path.join(self.temp_dir, "scratch") |
| 383 | - with mkfile(os.path.join(scratch, "manifest.json")) as f: |
| 384 | - json.dump({ |
| 385 | - "name": "com.example.test", |
| 386 | - "version": "1.0", |
| 387 | - "maintainer": "Foo Bar <foo@example.org>", |
| 388 | - "title": "test title", |
| 389 | - "architecture": "all", |
| 390 | + scratch = self._make_scratch_dir(manifest_override={ |
| 391 | "framework": |
| 392 | "ubuntu-sdk-14.04-basic, ubuntu-sdk-14.04-webapps", |
| 393 | - }, f) |
| 394 | - self.builder.add_file(scratch, "/") |
| 395 | + }) |
| 396 | path = self.builder.build(self.temp_dir) |
| 397 | control_path = os.path.join(self.temp_dir, "control") |
| 398 | subprocess.check_call(["dpkg-deb", "-e", path, control_path]) |
| 399 | @@ -289,13 +286,15 @@ |
| 400 | self.builder = ClickBuilder() |
| 401 | for framework_name in ("ubuntu-sdk-13.10", |
| 402 | "ubuntu-sdk-14.04-papi", |
| 403 | - "ubuntu-sdk-14.04-html"): |
| 404 | + "ubuntu-sdk-14.04-html", |
| 405 | + "docker-sdk-1.3"): |
| 406 | self._create_mock_framework_file(framework_name) |
| 407 | |
| 408 | def test_validate_framework_good(self): |
| 409 | valid_framework_values = ( |
| 410 | "ubuntu-sdk-13.10", |
| 411 | "ubuntu-sdk-14.04-papi, ubuntu-sdk-14.04-html", |
| 412 | + "ubuntu-sdk-13.10, docker-sdk-1.3", |
| 413 | ) |
| 414 | for framework in valid_framework_values: |
| 415 | self.builder._validate_framework(framework) |
| 416 | @@ -322,6 +321,8 @@ |
| 417 | scratch = os.path.join(self.temp_dir, "scratch") |
| 418 | touch(os.path.join(scratch, "bin", "foo")) |
| 419 | touch(os.path.join(scratch, ".git", "config")) |
| 420 | + touch(os.path.join(scratch, "foo.so")) |
| 421 | + touch(os.path.join(scratch, "build", "meep.goah")) |
| 422 | with mkfile(os.path.join(scratch, "manifest.json")) as f: |
| 423 | json.dump({ |
| 424 | "name": "com.example.test", |
| 425 | @@ -334,6 +335,7 @@ |
| 426 | # build() overrides this back to 0o644 |
| 427 | os.fchmod(f.fileno(), 0o600) |
| 428 | self.builder.add_file(scratch, "./") |
| 429 | + self.builder.add_ignore_pattern("build") |
| 430 | path = os.path.join(self.temp_dir, "com.example.test_1.0.tar.gz") |
| 431 | self.assertEqual(path, self.builder.build(self.temp_dir)) |
| 432 | self.assertTrue(os.path.exists(path)) |
| 433 | |
| 434 | === modified file 'click/tests/test_database.py' |
| 435 | --- click/tests/test_database.py 2014-09-10 11:54:14 +0000 |
| 436 | +++ click/tests/test_database.py 2015-02-26 17:06:20 +0000 |
| 437 | @@ -562,6 +562,18 @@ |
| 438 | db = Click.DB() |
| 439 | self.assertEqual(0, db.props.size) |
| 440 | |
| 441 | + def test_no_db_conf_errors(self): |
| 442 | + db = Click.DB() |
| 443 | + self.assertRaisesDatabaseError( |
| 444 | + Click.DatabaseError.INVALID, db.get, 0) |
| 445 | + self.assertEqual(db.props.overlay, "") |
| 446 | + self.assertRaisesDatabaseError( |
| 447 | + Click.DatabaseError.INVALID, db.maybe_remove, "something", "1.0") |
| 448 | + self.assertRaisesDatabaseError( |
| 449 | + Click.DatabaseError.INVALID, db.gc) |
| 450 | + self.assertRaisesDatabaseError( |
| 451 | + Click.DatabaseError.INVALID, db.ensure_ownership) |
| 452 | + |
| 453 | def test_read_nonexistent(self): |
| 454 | db = Click.DB() |
| 455 | db.read(db_dir=os.path.join(self.temp_dir, "nonexistent")) |
| 456 | |
| 457 | === modified file 'click/tests/test_user.py' |
| 458 | --- click/tests/test_user.py 2014-09-29 11:12:52 +0000 |
| 459 | +++ click/tests/test_user.py 2015-02-26 17:06:20 +0000 |
| 460 | @@ -34,6 +34,7 @@ |
| 461 | from click.tests.gimock_types import Passwd |
| 462 | from click.tests.helpers import ( |
| 463 | TestCase, |
| 464 | + make_installed_click, |
| 465 | mkfile, |
| 466 | make_file_with_content, |
| 467 | touch, |
| 468 | @@ -557,21 +558,34 @@ |
| 469 | self.assertEqual(b_overlay, registry.get_path("b")) |
| 470 | self.assertTrue(registry.is_removable("b")) |
| 471 | |
| 472 | - def test_app_stops_on_remove(self): |
| 473 | + |
| 474 | +class StopAppTestCase(TestCase): |
| 475 | + |
| 476 | + def setUp(self): |
| 477 | + super(StopAppTestCase, self).setUp() |
| 478 | + self.use_temp_dir() |
| 479 | + self.db = Click.DB() |
| 480 | + self.db.add(self.temp_dir) |
| 481 | + |
| 482 | + # setup fake app_stop |
| 483 | fake_app_stop = os.path.join(self.temp_dir, "bin", "ubuntu-app-stop") |
| 484 | - fake_app_stop_output = os.path.join(self.temp_dir, "fake-app-stop.out") |
| 485 | + self.fake_app_stop_output = os.path.join( |
| 486 | + self.temp_dir, "fake-app-stop.out") |
| 487 | fake_app_stop_content = dedent("""\ |
| 488 | #!/bin/sh |
| 489 | echo "$@" >> %s |
| 490 | - """ % fake_app_stop_output) |
| 491 | + """ % self.fake_app_stop_output) |
| 492 | make_file_with_content(fake_app_stop, fake_app_stop_content, 0o755) |
| 493 | # its ok to modify env here, click.helpers.TestCase will take care |
| 494 | # of it |
| 495 | os.environ["PATH"] = "%s:%s" % ( |
| 496 | os.path.dirname(fake_app_stop), os.environ["PATH"]) |
| 497 | - # get a app with manifest etc all |
| 498 | - _, registry = self._setUpMultiDB() |
| 499 | - registry.remove("a") |
| 500 | + |
| 501 | + def test_app_stops_on_remove(self): |
| 502 | + make_installed_click(self.db, self.temp_dir, "meep", "2.0", |
| 503 | + {"hooks": {"a-app": {}}}) |
| 504 | + registry = Click.User.for_user(self.db, "user") |
| 505 | + registry.remove("meep") |
| 506 | # ensure that stop was called with the right app |
| 507 | - with open(fake_app_stop_output) as f: |
| 508 | - self.assertEqual("a_a-app_1.1", f.read().strip()) |
| 509 | + with open(self.fake_app_stop_output) as f: |
| 510 | + self.assertEqual("meep_a-app_2.0", f.read().strip()) |
| 511 | |
| 512 | === modified file 'debian/changelog' |
| 513 | --- debian/changelog 2015-02-13 14:46:35 +0000 |
| 514 | +++ debian/changelog 2015-02-26 17:06:20 +0000 |
| 515 | @@ -1,3 +1,20 @@ |
| 516 | +click (0.4.38.4) UNRELEASED; urgency=low |
| 517 | + |
| 518 | + * lp:~mvo/click/lp1232130-kill-on-remove-2: |
| 519 | + - When uninstalling a app, stop it if its running (LP: #1232130) |
| 520 | + * lp:~mvo/click/dont-crash-for-empty-db: |
| 521 | + - Do not crash when no database configuration is used and |
| 522 | + Click.DB.{get,props.overlay,gc,ensure_ownership} are called. |
| 523 | + * lp:~mvo/click/lp1219912-build-exclude: |
| 524 | + - add a new --ignore option to click {build,buildsource} |
| 525 | + (LP: #1219912) |
| 526 | + * lp:~mvo/click/fix-multiple-framework-validation: |
| 527 | + - fix framework validation for snappy |
| 528 | + * run debian/packagekit-check with "sh" as something in jenkins |
| 529 | + made it mode 0644 |
| 530 | + |
| 531 | + -- Michael Vogt <michael.vogt@ubuntu.com> Mon, 23 Feb 2015 08:20:04 +0100 |
| 532 | + |
| 533 | click (0.4.37) vivid; urgency=low |
| 534 | |
| 535 | [ Michael Vogt ] |
| 536 | |
| 537 | === modified file 'debian/rules' |
| 538 | --- debian/rules 2014-10-10 07:10:23 +0000 |
| 539 | +++ debian/rules 2015-02-26 17:06:20 +0000 |
| 540 | @@ -1,6 +1,6 @@ |
| 541 | #! /usr/bin/make -f |
| 542 | |
| 543 | -PACKAGEKIT := $(shell debian/packagekit-check) |
| 544 | +PACKAGEKIT := $(shell sh debian/packagekit-check) |
| 545 | ifeq ($(PACKAGEKIT),yes) |
| 546 | EXTRA_DH_OPTIONS := |
| 547 | else |
| 548 | |
| 549 | === modified file 'doc/manpage.rst' |
| 550 | --- doc/manpage.rst 2014-10-13 12:48:35 +0000 |
| 551 | +++ doc/manpage.rst 2015-02-26 17:06:20 +0000 |
| 552 | @@ -73,6 +73,11 @@ |
| 553 | |
| 554 | -m PATH, --manifest=PATH Read package manifest from PATH |
| 555 | (default: ``manifest.json``). |
| 556 | +-I file-pattern, --ignore=file-pattern Ignore the given shell-pattern |
| 557 | + when building the package. |
| 558 | + The option may be repeated multiple |
| 559 | + times to list multiple patterns to |
| 560 | + exclude. |
| 561 | --no-validate Don't run checks from click-reviewers-tools on |
| 562 | the resulting .click file. |
| 563 | |
| 564 | @@ -90,8 +95,13 @@ |
| 565 | |
| 566 | Options: |
| 567 | |
| 568 | --m PATH, --manifest=PATH Read package manifest from PATH |
| 569 | - (default: ``manifest.json``). |
| 570 | +-m PATH, --manifest=PATH Read package manifest from PATH |
| 571 | + (default: ``manifest.json``). |
| 572 | +-I file-pattern, --ignore=file-pattern Ignore the given shell-pattern |
| 573 | + when building the package. |
| 574 | + The option may be repeated multiple |
| 575 | + times to list multiple patterns to |
| 576 | + exclude. |
| 577 | |
| 578 | click chroot |
| 579 | ------------ |
| 580 | |
| 581 | === modified file 'lib/click/database.vala' |
| 582 | --- lib/click/database.vala 2014-09-12 11:46:05 +0000 |
| 583 | +++ lib/click/database.vala 2015-02-26 17:06:20 +0000 |
| 584 | @@ -34,7 +34,11 @@ |
| 585 | /** |
| 586 | * Package manifest cannot be parsed. |
| 587 | */ |
| 588 | - BAD_MANIFEST |
| 589 | + BAD_MANIFEST, |
| 590 | + /** |
| 591 | + * No database available for the given request |
| 592 | + */ |
| 593 | + INVALID |
| 594 | } |
| 595 | |
| 596 | private string? app_pid_command = null; |
| 597 | @@ -602,8 +606,11 @@ |
| 598 | public int size { get { return db.size; } } |
| 599 | |
| 600 | public new SingleDB |
| 601 | - @get (int index) |
| 602 | + @get (int index) throws DatabaseError |
| 603 | { |
| 604 | + if (index >= db.size) |
| 605 | + throw new DatabaseError.INVALID |
| 606 | + ("invalid index %i for db of size %i", index, db.size); |
| 607 | return db.get (index); |
| 608 | } |
| 609 | |
| 610 | @@ -618,7 +625,15 @@ |
| 611 | * |
| 612 | * The directory where changes should be written. |
| 613 | */ |
| 614 | - public string overlay { get { return db.last ().root; } } |
| 615 | + public string overlay |
| 616 | + { |
| 617 | + get { |
| 618 | + if (db.size == 0) |
| 619 | + return ""; |
| 620 | + else |
| 621 | + return db.last ().root; |
| 622 | + } |
| 623 | + } |
| 624 | |
| 625 | /** |
| 626 | * get_path: |
| 627 | @@ -812,21 +827,32 @@ |
| 628 | return generator.to_data (null); |
| 629 | } |
| 630 | |
| 631 | + private void |
| 632 | + ensure_db () throws Error |
| 633 | + { |
| 634 | + if (db.size == 0) |
| 635 | + throw new DatabaseError.INVALID |
| 636 | + ("no database loaded"); |
| 637 | + } |
| 638 | + |
| 639 | public void |
| 640 | maybe_remove (string package, string version) throws Error |
| 641 | { |
| 642 | + ensure_db(); |
| 643 | db.last ().maybe_remove (package, version); |
| 644 | } |
| 645 | |
| 646 | public void |
| 647 | gc () throws Error |
| 648 | { |
| 649 | + ensure_db(); |
| 650 | db.last ().gc (); |
| 651 | } |
| 652 | |
| 653 | public void |
| 654 | ensure_ownership () throws Error |
| 655 | { |
| 656 | + ensure_db(); |
| 657 | db.last ().ensure_ownership (); |
| 658 | } |
| 659 | } |
| 660 | |
| 661 | === modified file 'lib/click/user.vala' |
| 662 | --- lib/click/user.vala 2014-12-05 15:09:48 +0000 |
| 663 | +++ lib/click/user.vala 2015-02-26 17:06:20 +0000 |
| 664 | @@ -658,8 +658,49 @@ |
| 665 | old_version, username); |
| 666 | } |
| 667 | |
| 668 | - private bool |
| 669 | - stop_running_app (string package, string version) |
| 670 | + private string |
| 671 | + get_dbus_session_bus_env_for_current_user() |
| 672 | + { |
| 673 | + string euid = "%i".printf((int)(Posix.geteuid ())); |
| 674 | + var dbus_session_file = Path.build_filename( |
| 675 | + "/run", "user", euid, "dbus-session"); |
| 676 | + string session_env; |
| 677 | + try { |
| 678 | + FileUtils.get_contents(dbus_session_file, out session_env); |
| 679 | + session_env = session_env.strip(); |
| 680 | + } catch (Error e) { |
| 681 | + warning("Can not get the dbus session to stop app (%s)", e.message); |
| 682 | + } |
| 683 | + return session_env; |
| 684 | + } |
| 685 | + |
| 686 | + private bool |
| 687 | + stop_single_app (string app_id) |
| 688 | + { |
| 689 | + // get the users dbus session when we run as root first as this |
| 690 | + // is where ubuntu-app-stop listens |
| 691 | + string[] envp = Environ.get(); |
| 692 | + envp += get_dbus_session_bus_env_for_current_user(); |
| 693 | + |
| 694 | + string[] command = { |
| 695 | + "ubuntu-app-stop", app_id |
| 696 | + }; |
| 697 | + bool res = false; |
| 698 | + try { |
| 699 | + int exit_status; |
| 700 | + Process.spawn_sync |
| 701 | + (null, command, envp, |
| 702 | + SpawnFlags.SEARCH_PATH, |
| 703 | + null, null, null, out exit_status); |
| 704 | + res = Process.check_exit_status (exit_status); |
| 705 | + } catch (Error e) { |
| 706 | + res = false; |
| 707 | + } |
| 708 | + return res; |
| 709 | + } |
| 710 | + |
| 711 | + private bool |
| 712 | + stop_running_apps_for_package (string package, string version) |
| 713 | { |
| 714 | var res = true; |
| 715 | if (! find_on_path ("ubuntu-app-stop")) |
| 716 | @@ -679,24 +720,7 @@ |
| 717 | } |
| 718 | var hooks = manifest.get_object_member ("hooks"); |
| 719 | foreach (unowned string app_name in hooks.get_members ()) |
| 720 | - { |
| 721 | - // FIXME: move this into a "stop_single_app" helper |
| 722 | - string[] command = { |
| 723 | - "ubuntu-app-stop", |
| 724 | - @"$(package)_$(app_name)_$(version)" |
| 725 | - }; |
| 726 | - try { |
| 727 | - int exit_status; |
| 728 | - Process.spawn_sync |
| 729 | - (null, command, null, |
| 730 | - SpawnFlags.SEARCH_PATH | |
| 731 | - SpawnFlags.STDOUT_TO_DEV_NULL, |
| 732 | - null, null, null, out exit_status); |
| 733 | - res &= Process.check_exit_status (exit_status); |
| 734 | - } catch (Error e) { |
| 735 | - res &= false; |
| 736 | - } |
| 737 | - } |
| 738 | + res &= stop_single_app (@"$(package)_$(app_name)_$(version)"); |
| 739 | return res; |
| 740 | } |
| 741 | |
| 742 | @@ -718,6 +742,8 @@ |
| 743 | old_version = Path.get_basename (target); |
| 744 | drop_privileges (); |
| 745 | try { |
| 746 | + // stop before removing the path to the manifest |
| 747 | + stop_running_apps_for_package (package, old_version); |
| 748 | unlink_force (path); |
| 749 | } finally { |
| 750 | regain_privileges (); |
| 751 | @@ -733,19 +759,14 @@ |
| 752 | ensure_db (); |
| 753 | drop_privileges (); |
| 754 | try { |
| 755 | + // stop before removing the path to the manifest |
| 756 | + stop_running_apps_for_package (package, old_version); |
| 757 | symlink_force (HIDDEN_VERSION, path); |
| 758 | } finally { |
| 759 | regain_privileges (); |
| 760 | } |
| 761 | } |
| 762 | |
| 763 | - drop_privileges (); |
| 764 | - try { |
| 765 | - stop_running_app (package, old_version); |
| 766 | - } finally { |
| 767 | - regain_privileges (); |
| 768 | - } |
| 769 | - |
| 770 | if (! is_pseudo_user) |
| 771 | package_remove_hooks (db, package, old_version, name); |
| 772 | |
| 773 | |
| 774 | === modified file 'pk-plugin/pk-plugin-click.c' |
| 775 | --- pk-plugin/pk-plugin-click.c 2014-09-02 08:44:39 +0000 |
| 776 | +++ pk-plugin/pk-plugin-click.c 2015-02-26 17:06:20 +0000 |
| 777 | @@ -637,6 +637,11 @@ |
| 778 | GError *error = NULL; |
| 779 | gchar *summary = NULL; |
| 780 | |
| 781 | + // PK does not set a PATH, but we need one for removal |
| 782 | + const gchar *old_path = g_getenv("PATH"); |
| 783 | + if(old_path == NULL) |
| 784 | + g_setenv("PATH", DEFAULT_PATH, 0); |
| 785 | + |
| 786 | username = click_get_username_for_uid |
| 787 | (pk_transaction_get_uid (transaction)); |
| 788 | if (!username) { |
| 789 | @@ -701,6 +706,9 @@ |
| 790 | ret = TRUE; |
| 791 | |
| 792 | out: |
| 793 | + if(old_path == NULL) |
| 794 | + g_unsetenv("PATH"); |
| 795 | + |
| 796 | g_free (summary); |
| 797 | if (error) |
| 798 | g_error_free (error); |
