Merge lp:~mvo/click/lp1245826-multiple-hookfiles into lp:click/devel

Proposed by Michael Vogt
Status: Needs review
Proposed branch: lp:~mvo/click/lp1245826-multiple-hookfiles
Merge into: lp:click/devel
Diff against target: 299 lines (+103/-32)
3 files modified
click/tests/gimock.py (+2/-1)
click/tests/test_hooks.py (+46/-2)
lib/click/hooks.vala (+55/-29)
To merge this branch: bzr merge lp:~mvo/click/lp1245826-multiple-hookfiles
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
click hackers Pending
Review via email: mp+235474@code.launchpad.net

Commit message

Add support for multiple click hook files.

Description of the change

Add support for multiple click hook files.

This is based on the work of lp:~mardy/click/lp1245826. Feedback on the approach appreciated, the actual code needs a refactor to get rid of the duplication of the relative_path reading code.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:524
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~mvo/click/lp1245826-multiple-hookfiles/+merge/235474/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/click-devel-ci/69/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-amd64-ci/71/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-armhf-ci/69/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-i386-ci/69/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/click-devel-ci/69/rebuild

review: Needs Fixing (continuous-integration)
525. By Michael Vogt

refactor duplicated code into get_relative_paths_for_hookname()

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:525
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~mvo/click/lp1245826-multiple-hookfiles/+merge/235474/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/click-devel-ci/70/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-amd64-ci/72/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-armhf-ci/70/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-i386-ci/70/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/click-devel-ci/70/rebuild

review: Needs Fixing (continuous-integration)
526. By Michael Vogt

fix pep8 failure

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:526
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~mvo/click/lp1245826-multiple-hookfiles/+merge/235474/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/click-devel-ci/85/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-amd64-ci/87
    SUCCESS: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-armhf-ci/85
        deb: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-armhf-ci/85/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/click-devel-utopic-i386-ci/85

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/click-devel-ci/85/rebuild

review: Needs Fixing (continuous-integration)

Unmerged revisions

526. By Michael Vogt

fix pep8 failure

525. By Michael Vogt

refactor duplicated code into get_relative_paths_for_hookname()

524. By Michael Vogt

add support for relative_path in get_app_hooks

523. By Michael Vogt

fix remove and add test

522. By Michael Vogt

Add support for multiple hook files

This allows writing hook files like:
"""
 Pattern: %s/${id}_${basename}
"""

and manifest with:
"""
hooks": {
  "app": {
     "service": ["target-1","target-2"]
  }
}
"""

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'click/tests/gimock.py'
--- click/tests/gimock.py 2014-06-23 21:14:06 +0000
+++ click/tests/gimock.py 2014-09-30 05:57:11 +0000
@@ -443,7 +443,8 @@
443 env["LD_PRELOAD"] = lib_path443 env["LD_PRELOAD"] = lib_path
444 subp = subprocess.Popen(args, close_fds=False, env=env,444 subp = subprocess.Popen(args, close_fds=False, env=env,
445 stdout=subprocess.PIPE,445 stdout=subprocess.PIPE,
446 stderr=subprocess.PIPE)446 stderr=subprocess.PIPE,
447 universal_newlines=True)
447 os.close(wfd)448 os.close(wfd)
448 reader = os.fdopen(rfd, "rb")449 reader = os.fdopen(rfd, "rb")
449 stdout, stderr = subp.communicate()450 stdout, stderr = subp.communicate()
450451
=== modified file 'click/tests/test_hooks.py'
--- click/tests/test_hooks.py 2014-07-11 17:20:51 +0000
+++ click/tests/test_hooks.py 2014-09-30 05:57:11 +0000
@@ -424,6 +424,31 @@
424 os.path.join(self.temp_dir, "test-2", "2.0", "target-2"),424 os.path.join(self.temp_dir, "test-2", "2.0", "target-2"),
425 os.readlink(path_2))425 os.readlink(path_2))
426426
427 def test_install_hook_with_multiple_files(self):
428 with self.run_in_subprocess(
429 "click_get_hooks_dir") as (enter, preloads):
430 enter()
431 self._setup_hooks_dir(
432 preloads, hooks_dir=os.path.join(self.temp_dir, "hooks"))
433 self._make_hook_file(
434 "Pattern: %s/${id}_${basename}.new" % self.temp_dir,
435 hookname="new")
436 self._make_installed_click("test-1", "1.0", json_data={
437 "hooks": {"test1-app": {"new": ["target-1","target-2"]}}})
438 hook = Click.Hook.open(self.db, "new")
439 hook.install(user_name=None)
440 for hook_file in ("target-1", "target-2"):
441 path = os.path.join(
442 self.temp_dir, "test-1_test1-app_1.0_%s.new" % hook_file)
443 expected_path = os.path.join(
444 self.temp_dir, "test-1", "1.0", hook_file)
445 self.assertEqual(expected_path, os.readlink(path))
446 hook.remove(user_name=None)
447 for hook_file in ("target-1", "target-2"):
448 path = os.path.join(
449 self.temp_dir, "test-1_test1-app_1.0_%s.new" % hook_file)
450 self.assertEqual(os.path.lexists(path), False)
451
427 def test_remove(self):452 def test_remove(self):
428 with self.run_in_subprocess(453 with self.run_in_subprocess(
429 "click_get_hooks_dir") as (enter, preloads):454 "click_get_hooks_dir") as (enter, preloads):
@@ -1114,6 +1139,10 @@
1114 print("Pattern: %s/yelp/other-${id}.txt" % self.temp_dir,1139 print("Pattern: %s/yelp/other-${id}.txt" % self.temp_dir,
1115 file=f)1140 file=f)
1116 print("Hook-Name: yelp", file=f)1141 print("Hook-Name: yelp", file=f)
1142 with mkfile(os.path.join(hooks_dir, "service.hook")) as f:
1143 print("Pattern: %s/service/${id}_${basename}.txt" % self.temp_dir,
1144 file=f)
1145 print("Hook-Name: service", file=f)
1117 os.mkdir(os.path.join(self.temp_dir, "unity"))1146 os.mkdir(os.path.join(self.temp_dir, "unity"))
1118 unity_path = os.path.join(1147 unity_path = os.path.join(
1119 self.temp_dir, "unity", "test_app_1.0.scope")1148 self.temp_dir, "unity", "test_app_1.0.scope")
@@ -1125,18 +1154,33 @@
1125 yelp_other_path = os.path.join(1154 yelp_other_path = os.path.join(
1126 self.temp_dir, "yelp", "other-test_app_1.0.txt")1155 self.temp_dir, "yelp", "other-test_app_1.0.txt")
1127 os.symlink("dummy", yelp_other_path)1156 os.symlink("dummy", yelp_other_path)
1157 os.mkdir(os.path.join(self.temp_dir, "service"))
1158 service1_path = os.path.join(
1159 self.temp_dir, "service", "test_app_1.0_service1.txt")
1160 os.symlink("dummy", service1_path)
1161 service2_path = os.path.join(
1162 self.temp_dir, "service", "test_app_1.0_service2.txt")
1163 os.symlink("dummy", service2_path)
1128 package_dir = os.path.join(self.temp_dir, "test")1164 package_dir = os.path.join(self.temp_dir, "test")
1129 with mkfile(os.path.join(1165 with mkfile(os.path.join(
1130 package_dir, "1.0", ".click", "info",1166 package_dir, "1.0", ".click", "info",
1131 "test.manifest")) as f:1167 "test.manifest")) as f:
1132 json.dump(1168 json.dump(
1133 {"hooks": {1169 {"hooks":
1134 "app": {"yelp": "foo.txt", "unity": "foo.scope"}}1170 {
1171 "app": {
1172 "yelp": "foo.txt",
1173 "unity": "foo.scope",
1174 "service": ["service1", "service2"],
1175 },
1176 }
1135 }, f)1177 }, f)
1136 Click.package_remove_hooks(self.db, "test", "1.0", user_name=None)1178 Click.package_remove_hooks(self.db, "test", "1.0", user_name=None)
1137 self.assertFalse(os.path.lexists(unity_path))1179 self.assertFalse(os.path.lexists(unity_path))
1138 self.assertFalse(os.path.lexists(yelp_docs_path))1180 self.assertFalse(os.path.lexists(yelp_docs_path))
1139 self.assertFalse(os.path.lexists(yelp_other_path))1181 self.assertFalse(os.path.lexists(yelp_other_path))
1182 self.assertFalse(os.path.lexists(service1_path))
1183 self.assertFalse(os.path.lexists(service2_path))
11401184
11411185
1142class TestPackageHooksValidateFramework(TestClickHookBase):1186class TestPackageHooksValidateFramework(TestClickHookBase):
11431187
=== modified file 'lib/click/hooks.vala'
--- lib/click/hooks.vala 2014-09-10 11:57:55 +0000
+++ lib/click/hooks.vala 2014-09-30 05:57:11 +0000
@@ -227,23 +227,24 @@
227 Gee.Comparable<AppHook> {227 Gee.Comparable<AppHook> {
228 public string app_name { get; construct; }228 public string app_name { get; construct; }
229 public string hook_name { get; construct; }229 public string hook_name { get; construct; }
230 public string relative_path { get; construct; }
230231
231 public232 public
232 AppHook (string app_name, string hook_name)233 AppHook (string app_name, string hook_name, string? relative_path = null)
233 {234 {
234 Object (app_name: app_name, hook_name: hook_name);235 Object (app_name: app_name, hook_name: hook_name, relative_path: relative_path);
235 }236 }
236237
237 public uint238 public uint
238 hash ()239 hash ()
239 {240 {
240 return app_name.hash () ^ hook_name.hash ();241 return app_name.hash () ^ hook_name.hash () ^ relative_path.hash();
241 }242 }
242243
243 public bool244 public bool
244 equal_to (AppHook obj)245 equal_to (AppHook obj)
245 {246 {
246 return app_name == obj.app_name && hook_name == obj.hook_name;247 return app_name == obj.app_name && hook_name == obj.hook_name && relative_path == obj.relative_path;
247 }248 }
248249
249 public int250 public int
@@ -252,7 +253,10 @@
252 var ret = strcmp (app_name, obj.app_name);253 var ret = strcmp (app_name, obj.app_name);
253 if (ret != 0)254 if (ret != 0)
254 return ret;255 return ret;
255 return strcmp (hook_name, obj.hook_name);256 ret = strcmp (hook_name, obj.hook_name);
257 if (ret != 0)
258 return ret;
259 return strcmp (relative_path, obj.relative_path);
256 }260 }
257}261}
258262
@@ -588,10 +592,11 @@
588 * @version: A version string.592 * @version: A version string.
589 * @app_name: An application name.593 * @app_name: An application name.
590 * @user_name: (allow-none): A user name, or null.594 * @user_name: (allow-none): A user name, or null.
595 * @base_name: (allow-none): A base name, or null.
591 */596 */
592 public string597 public string
593 get_pattern (string package, string version, string app_name,598 get_pattern (string package, string version, string app_name,
594 string? user_name = null) throws HooksError599 string? user_name = null, string? base_name = "") throws HooksError
595 {600 {
596 var builder = new VariantBuilder (new VariantType ("a{sms}"));601 var builder = new VariantBuilder (new VariantType ("a{sms}"));
597 var app_id = get_app_id (package, version, app_name);602 var app_id = get_app_id (package, version, app_name);
@@ -600,9 +605,9 @@
600 builder.add ("{sms}", "id", app_id);605 builder.add ("{sms}", "id", app_id);
601 builder.add ("{sms}", "user", user_name);606 builder.add ("{sms}", "user", user_name);
602 builder.add ("{sms}", "home", user_home);607 builder.add ("{sms}", "home", user_home);
608 builder.add ("{sms}", "basename", base_name);
603 if (is_single_version) {609 if (is_single_version) {
604 var short_app_id = get_short_app_id (package,610 var short_app_id = get_short_app_id (package, app_name);
605 app_name);
606 builder.add ("{sms}", "short-id", short_app_id);611 builder.add ("{sms}", "short-id", short_app_id);
607 }612 }
608 var ret = pattern_format (pattern, builder.end ());613 var ret = pattern_format (pattern, builder.end ());
@@ -799,7 +804,8 @@
799 else804 else
800 path = db.get_path (package, version);805 path = db.get_path (package, version);
801 var target = Path.build_filename (path, relative_path);806 var target = Path.build_filename (path, relative_path);
802 var link = get_pattern (package, version, app_name, user_name);807 var link = get_pattern (package, version, app_name, user_name,
808 Path.get_basename (relative_path));
803 if (is_symlink (link) && FileUtils.read_link (link) == target)809 if (is_symlink (link) && FileUtils.read_link (link) == target)
804 return;810 return;
805 ensuredir (Path.get_dirname (link));811 ensuredir (Path.get_dirname (link));
@@ -862,10 +868,10 @@
862 */868 */
863 public void869 public void
864 remove_package (string package, string version, string app_name,870 remove_package (string package, string version, string app_name,
865 string? user_name = null) throws Error871 string? user_name = null, string? base_name = null) throws Error
866 {872 {
867 unlink_force (get_pattern873 unlink_force (get_pattern
868 (package, version, app_name, user_name));874 (package, version, app_name, user_name, base_name));
869 run_commands (user_name);875 run_commands (user_name);
870 }876 }
871877
@@ -953,17 +959,14 @@
953 var manifest_hooks = read_manifest_hooks959 var manifest_hooks = read_manifest_hooks
954 (db, unpacked.package, unpacked.version);960 (db, unpacked.package, unpacked.version);
955 foreach (var app_name in manifest_hooks.get_members ()) {961 foreach (var app_name in manifest_hooks.get_members ()) {
956 var hooks = manifest_hooks.get_object_member962 foreach (var relative_path in get_relative_paths_for_hookname(manifest_hooks, app_name, hook_name))
957 (app_name);963 {
958 if (hooks.has_member (hook_name)) {964 ret.prepend (new RelevantApp
959 var relative_path = hooks.get_string_member965 (unpacked.package,
960 (hook_name);966 unpacked.version, app_name,
961 ret.prepend (new RelevantApp967 unpacked.user_name,
962 (unpacked.package,968 relative_path));
963 unpacked.version, app_name,969 }
964 unpacked.user_name,
965 relative_path));
966 }
967 }970 }
968 }971 }
969 ret.reverse ();972 ret.reverse ();
@@ -998,7 +1001,7 @@
998 {1001 {
999 foreach (var app in get_relevant_apps (user_name))1002 foreach (var app in get_relevant_apps (user_name))
1000 remove_package (app.package, app.version, app.app_name,1003 remove_package (app.package, app.version, app.app_name,
1001 app.user_name);1004 app.user_name, app.relative_path);
1002 }1005 }
10031006
1004 /**1007 /**
@@ -1058,6 +1061,28 @@
1058 }1061 }
1059}1062}
10601063
1064private List<string>
1065get_relative_paths_for_hookname(Json.Object manifest, string app_name, string hook_name) throws Error
1066{
1067 var ret = new List<string> ();
1068 var hooks = manifest.get_object_member (app_name);
1069 if (!hooks.has_member (hook_name))
1070 return ret;
1071
1072 var node = hooks.get_member(hook_name);
1073 var value_type = node.get_value_type();
1074 // support both single string and list for hook targets in manifest
1075 if (value_type.name() == "gchararray")
1076 ret.append (node.get_string());
1077 else {
1078 var array = node.get_array ();
1079 foreach(var elm in array.get_elements ()) {
1080 ret.append (elm.get_string ());
1081 }
1082 }
1083 return ret;
1084}
1085
1061private Gee.TreeSet<AppHook>1086private Gee.TreeSet<AppHook>
1062get_app_hooks (Json.Object manifest)1087get_app_hooks (Json.Object manifest)
1063{1088{
@@ -1065,7 +1090,8 @@
1065 foreach (var app_name in manifest.get_members ()) {1090 foreach (var app_name in manifest.get_members ()) {
1066 var hooks = manifest.get_object_member (app_name);1091 var hooks = manifest.get_object_member (app_name);
1067 foreach (var hook_name in hooks.get_members ())1092 foreach (var hook_name in hooks.get_members ())
1068 items.add (new AppHook (app_name, hook_name));1093 foreach (var relative_path in get_relative_paths_for_hookname(manifest, app_name, hook_name))
1094 items.add (new AppHook (app_name, hook_name, relative_path));
1069 }1095 }
1070 return items;1096 return items;
1071}1097}
@@ -1105,7 +1131,7 @@
1105 if (! hook.is_single_version)1131 if (! hook.is_single_version)
1106 continue;1132 continue;
1107 hook.remove_package (package, old_version,1133 hook.remove_package (package, old_version,
1108 app_hook.app_name, user_name);1134 app_hook.app_name, user_name, app_hook.relative_path);
1109 }1135 }
1110 }1136 }
11111137
@@ -1116,14 +1142,14 @@
1116 var hook_names = app_hooks.get_members ();1142 var hook_names = app_hooks.get_members ();
1117 hook_names.sort (strcmp);1143 hook_names.sort (strcmp);
1118 foreach (var hook_name in hook_names) {1144 foreach (var hook_name in hook_names) {
1119 var relative_path = app_hooks.get_string_member1145 foreach (var relative_path in get_relative_paths_for_hookname (new_manifest, app_name, hook_name)) {
1120 (hook_name);1146 foreach (var hook in Hook.open_all (db, hook_name)) {
1121 foreach (var hook in Hook.open_all (db, hook_name)) {
1122 if (hook.is_user_level != (user_name != null))1147 if (hook.is_user_level != (user_name != null))
1123 continue;1148 continue;
1124 hook.install_package (package, new_version,1149 hook.install_package (package, new_version,
1125 app_name, relative_path,1150 app_name, relative_path,
1126 user_name);1151 user_name);
1152 }
1127 }1153 }
1128 }1154 }
1129 }1155 }
@@ -1152,7 +1178,7 @@
1152 if (hook.is_user_level != (user_name != null))1178 if (hook.is_user_level != (user_name != null))
1153 continue;1179 continue;
1154 hook.remove_package (package, old_version,1180 hook.remove_package (package, old_version,
1155 app_hook.app_name, user_name);1181 app_hook.app_name, user_name, app_hook.relative_path);
1156 }1182 }
1157 }1183 }
1158}1184}

Subscribers

People subscribed via source and target branches

to all changes: