Merge lp:~mvo/click/hide-apps-on-missing-framework into lp:click

Proposed by Michael Vogt
Status: Superseded
Proposed branch: lp:~mvo/click/hide-apps-on-missing-framework
Merge into: lp:click
Diff against target: 279 lines (+168/-18)
5 files modified
click/tests/helpers.py (+8/-0)
click/tests/test_hooks.py (+93/-0)
click/tests/test_install.py (+0/-8)
doc/index.rst (+3/-1)
lib/click/hooks.vala (+64/-9)
To merge this branch: bzr merge lp:~mvo/click/hide-apps-on-missing-framework
Reviewer Review Type Date Requested Status
Michael Vogt Needs Resubmitting
Colin Watson Needs Fixing
Review via email: mp+218949@code.launchpad.net

This proposal has been superseded by a proposal from 2014-05-15.

Description of the change

This branch fixes bug #1271944 - when the hooks are run it will check if the framework requirements are meet. If that is not the case, the hook symlink is removed and the hook command run.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

This looks good apart from the FIXME you identify - I agree with that comment and think this needs to be moved slightly.

review: Needs Fixing
429. By Michael Vogt

lib/click/hooks.vala: move validate_framework_for_package() check inside get_relevant_apps

Revision history for this message
Michael Vogt (mvo) wrote :

Thanks for the review! I moved the check for validate_framework_for_package() into the get_relevant_apps() now.

review: Needs Resubmitting

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'click/tests/helpers.py'
2--- click/tests/helpers.py 2014-05-08 18:18:39 +0000
3+++ click/tests/helpers.py 2014-05-13 17:58:01 +0000
4@@ -108,6 +108,14 @@
5 self.assertRaisesGError(
6 "click_user_error-quark", code, callableObj, *args, **kwargs)
7
8+ def _setup_frameworks(self, preloads, frameworks_dir=None, frameworks=[]):
9+ frameworks_dir = self._create_mock_framework_dir(frameworks_dir)
10+ shutil.rmtree(frameworks_dir, ignore_errors=True)
11+ for framework in frameworks:
12+ self._create_mock_framework_file(framework)
13+ preloads["click_get_frameworks_dir"].side_effect = (
14+ lambda: self.make_string(frameworks_dir))
15+
16 def _create_mock_framework_dir(self, frameworks_dir=None):
17 if frameworks_dir is None:
18 frameworks_dir = os.path.join(self.temp_dir, "frameworks")
19
20=== modified file 'click/tests/test_hooks.py'
21--- click/tests/test_hooks.py 2014-04-03 08:52:02 +0000
22+++ click/tests/test_hooks.py 2014-05-13 17:58:01 +0000
23@@ -107,6 +107,7 @@
24 hooks_dir = self.temp_dir
25 preloads["click_get_hooks_dir"].side_effect = (
26 lambda: self.make_string(hooks_dir))
27+ self.hooks_dir = hooks_dir
28
29 def g_spawn_sync_side_effect(self, status_map, working_directory, argv,
30 envp, flags, child_setup, user_data,
31@@ -1113,3 +1114,95 @@
32 self.assertFalse(os.path.lexists(unity_path))
33 self.assertFalse(os.path.lexists(yelp_docs_path))
34 self.assertFalse(os.path.lexists(yelp_other_path))
35+
36+
37+class TestPackageHooksValidateFramework(TestClickHookBase):
38+
39+ def _make_hook_file(self, hookname="test"):
40+ hook_file = os.path.join(self.hooks_dir, "%s.hook" % hookname)
41+ with mkfile(hook_file) as f:
42+ print("User-Level: yes", file=f)
43+ print("Pattern: %s/${id}.test" % self.temp_dir, file=f)
44+
45+ def _make_manifest(self, package="test-1",version="1.0",
46+ framework="ubuntu-sdk-13.10",
47+ hooks=None):
48+ if hooks is None:
49+ hooks = {"test1-app": {"test": "target-1"}}
50+ with mkfile_utf8(os.path.join(
51+ self.temp_dir, package, version, ".click", "info",
52+ "%s.manifest" % package)) as f:
53+ json.dump({
54+ "framework": framework,
55+ "hooks": hooks,
56+ }, f)
57+ os.symlink("1.0", os.path.join(self.temp_dir, package, "current"))
58+ user_db = Click.User.for_user(self.db, "test-user")
59+ user_db.set_version(package, version)
60+
61+ def _setup_test_env(self, preloads):
62+ preloads["click_get_user_home"].return_value = "/home/test-user"
63+ self._setup_hooks_dir(
64+ preloads, os.path.join(self.temp_dir, "hooks"))
65+ self._make_hook_file()
66+ self.hook_symlink_path = os.path.join(
67+ self.temp_dir, "test-1_test1-app_1.0.test")
68+
69+ def test_links_are_kept_on_validate_framework(self):
70+ with self.run_in_subprocess(
71+ "click_get_hooks_dir", "click_get_user_home",
72+ "click_get_frameworks_dir",
73+ ) as (enter, preloads):
74+ enter()
75+ self._setup_frameworks(
76+ preloads, frameworks=["ubuntu-sdk-13.10"])
77+ self._setup_test_env(preloads)
78+ self._make_manifest(framework="ubuntu-sdk-13.10")
79+ self.assertTrue(os.path.lexists(self.hook_symlink_path))
80+ # run the hooks
81+ Click.run_user_hooks(self.db, user_name="test-user")
82+ self.assertTrue(os.path.lexists(self.hook_symlink_path))
83+
84+ def test_links_are_kept_multiple_frameworks(self):
85+ with self.run_in_subprocess(
86+ "click_get_hooks_dir", "click_get_user_home",
87+ "click_get_frameworks_dir",
88+ ) as (enter, preloads):
89+ enter()
90+ self._setup_frameworks(
91+ preloads, frameworks=["ubuntu-sdk-14.04", "ubuntu-sdk-13.10"])
92+ self._setup_test_env(preloads)
93+ self._make_manifest(framework="ubuntu-sdk-13.10")
94+ self.assertTrue(os.path.lexists(self.hook_symlink_path))
95+ # run the hooks
96+ Click.run_user_hooks(self.db, user_name="test-user")
97+ self.assertTrue(os.path.lexists(self.hook_symlink_path))
98+
99+ def test_links_are_removed_on_missng_framework(self):
100+ with self.run_in_subprocess(
101+ "click_get_hooks_dir", "click_get_user_home",
102+ "click_get_frameworks_dir",
103+ ) as (enter, preloads):
104+ enter()
105+ self._setup_frameworks(preloads, frameworks=["missing"])
106+ self._setup_test_env(preloads)
107+ self._make_manifest(framework="ubuntu-sdk-13.10")
108+ self.assertTrue(os.path.lexists(self.hook_symlink_path))
109+ # run the hooks
110+ Click.run_user_hooks(self.db, user_name="test-user")
111+ self.assertFalse(os.path.lexists(self.hook_symlink_path))
112+
113+ def test_links_are_removed_on_missng_multiple_framework(self):
114+ with self.run_in_subprocess(
115+ "click_get_hooks_dir", "click_get_user_home",
116+ "click_get_frameworks_dir",
117+ ) as (enter, preloads):
118+ enter()
119+ self._setup_frameworks(preloads, frameworks=["ubuntu-sdk-13.10"])
120+ self._setup_test_env(preloads)
121+ self._make_manifest(
122+ framework="ubuntu-sdk-13.10,ubuntu-sdk-13.10-html")
123+ self.assertTrue(os.path.lexists(self.hook_symlink_path))
124+ # run the hooks
125+ Click.run_user_hooks(self.db, user_name="test-user")
126+ self.assertFalse(os.path.lexists(self.hook_symlink_path))
127
128=== modified file 'click/tests/test_install.py'
129--- click/tests/test_install.py 2014-05-05 13:23:35 +0000
130+++ click/tests/test_install.py 2014-05-13 17:58:01 +0000
131@@ -103,14 +103,6 @@
132 self.temp_dir, control_dir, data_dir, package_path)
133 return package_path
134
135- def _setup_frameworks(self, preloads, frameworks_dir=None, frameworks=[]):
136- frameworks_dir = self._create_mock_framework_dir(frameworks_dir)
137- shutil.rmtree(frameworks_dir, ignore_errors=True)
138- for framework in frameworks:
139- self._create_mock_framework_file(framework)
140- preloads["click_get_frameworks_dir"].side_effect = (
141- lambda: self.make_string(frameworks_dir))
142-
143 def test_audit_no_click_version(self):
144 path = self.make_fake_package()
145 self.assertRaisesRegex(
146
147=== modified file 'doc/index.rst'
148--- doc/index.rst 2014-05-08 12:49:11 +0000
149+++ doc/index.rst 2014-05-13 17:58:01 +0000
150@@ -38,7 +38,9 @@
151 Then run::
152
153 $ ./autogen.sh
154- $ ./configure --with-systemdsystemunitdir=/lib/systemd/system \
155+ $ ./configure --prefix=/usr \
156+ --sysconfdir=/etc \
157+ --with-systemdsystemunitdir=/lib/systemd/system \
158 --with-systemduserunitdir=/usr/lib/systemd/user
159 $ make
160
161
162=== modified file 'lib/click/hooks.vala'
163--- lib/click/hooks.vala 2014-04-08 09:31:40 +0000
164+++ lib/click/hooks.vala 2014-05-13 17:58:01 +0000
165@@ -56,8 +56,48 @@
166 INCOMPLETE
167 }
168
169+
170+/* vala implementation of click.framework.validate_framework()
171+ *
172+ * Note that the required_frameworks string has the form
173+ * framework1, framework2, ...
174+ * See doc/file-format.rst for details.
175+ */
176+private bool
177+validate_framework (string required_frameworks)
178+{
179+ // valid framework names, cf. debian policy ยง5.6.1
180+ var valid_framework_re = new Regex("^[a-z][a-z0-9.+-]+");
181+ var base_version = "";
182+ foreach (var framework_name in required_frameworks.split(","))
183+ {
184+ framework_name = framework_name.strip();
185+ if(!valid_framework_re.match(framework_name))
186+ return false;
187+ if(!Framework.has_framework(framework_name))
188+ return false;
189+ // now check the base-version
190+ var framework = Framework.open(framework_name);
191+ if (base_version == "")
192+ base_version = framework.get_base_version();
193+ if (base_version != framework.get_base_version())
194+ return false;
195+ }
196+ return true;
197+}
198+
199+private bool
200+validate_framework_for_package (DB db, string package, string? version)
201+{
202+ var manifest = read_manifest(db, package, version);
203+ if (!manifest.has_member("framework"))
204+ return true;
205+ var required_frameworks = manifest.get_string_member("framework");
206+ return validate_framework (required_frameworks);
207+}
208+
209 private Json.Object
210-read_manifest_hooks (DB db, string package, string? version)
211+read_manifest (DB db, string package, string? version)
212 throws DatabaseError
213 {
214 if (version == null)
215@@ -69,15 +109,23 @@
216 @"$package.manifest");
217 parser.load_from_file (manifest_path);
218 var manifest = parser.get_root ().get_object ();
219- if (! manifest.has_member ("hooks"))
220- return new Json.Object ();
221- var hooks = manifest.get_object_member ("hooks");
222- return hooks.ref ();
223+ return manifest.ref ();
224 } catch (Error e) {
225 return new Json.Object ();
226 }
227 }
228
229+private Json.Object
230+read_manifest_hooks (DB db, string package, string? version)
231+ throws DatabaseError
232+{
233+ var manifest = read_manifest (db, package, version);
234+ if (! manifest.has_member ("hooks"))
235+ return new Json.Object ();
236+ var hooks = manifest.get_object_member ("hooks");
237+ return hooks.ref ();
238+}
239+
240 private class PreviousEntry : Object, Gee.Hashable<PreviousEntry> {
241 public string path { get; construct; }
242 public string package { get; construct; }
243@@ -889,10 +937,16 @@
244 var ret = new List<RelevantApp> ();
245 var hook_name = get_hook_name ();
246 foreach (var unpacked in get_all_packages (user_name)) {
247- var manifest = read_manifest_hooks
248+ // if the app is not using a valid framework (anymore)
249+ // we don't consider it relevant (anymore)
250+ if (!validate_framework_for_package
251+ (db, unpacked.package, unpacked.version))
252+ continue;
253+
254+ var manifest_hooks = read_manifest_hooks
255 (db, unpacked.package, unpacked.version);
256- foreach (var app_name in manifest.get_members ()) {
257- var hooks = manifest.get_object_member
258+ foreach (var app_name in manifest_hooks.get_members ()) {
259+ var hooks = manifest_hooks.get_object_member
260 (app_name);
261 if (hooks.has_member (hook_name)) {
262 var relative_path = hooks.get_string_member
263@@ -960,6 +1014,7 @@
264 unowned string package = app.package;
265 unowned string version = app.version;
266 unowned string app_name = app.app_name;
267+
268 seen.add (@"$(package)_$(app_name)_$(version)");
269 if (is_user_level) {
270 var user_db = new User.for_user
271@@ -1016,7 +1071,7 @@
272 * @new_version: The new version of the package.
273 * @user_name: (allow-none): A user name, or null.
274 *
275- * Run hooks following removal of a Click package.
276+ * Run hooks following install of a Click package.
277 *
278 * If @user_name is null, only run system-level hooks. If @user_name is not
279 * null, only run user-level hooks for that user.

Subscribers

People subscribed via source and target branches

to all changes: