Merge lp:~ted/ubuntu-app-launch/libertine-detection into lp:ubuntu-app-launch/15.10
- libertine-detection
- Merge into trunk.15.10
Status: | Merged |
---|---|
Approved by: | Christopher Townsend |
Approved revision: | 223 |
Merged at revision: | 206 |
Proposed branch: | lp:~ted/ubuntu-app-launch/libertine-detection |
Merge into: | lp:ubuntu-app-launch/15.10 |
Prerequisite: | lp:~ted/ubuntu-app-launch/xmir-support |
Diff against target: |
866 lines (+454/-156) 13 files modified
helpers-shared.c (+1/-1) helpers.h (+2/-0) libubuntu-app-launch/CMakeLists.txt (+2/-0) libubuntu-app-launch/app-info.c (+245/-0) libubuntu-app-launch/app-info.h (+27/-0) libubuntu-app-launch/desktop-exec.c (+69/-2) libubuntu-app-launch/desktop-exec.h (+3/-1) libubuntu-app-launch/ubuntu-app-launch-trace.tp (+7/-0) libubuntu-app-launch/ubuntu-app-launch.c (+38/-148) tests/exec-util-test.cc (+37/-0) tests/libertine-data/libertine-container/container-name/rootfs/usr/share/applications/test.desktop (+4/-0) tests/libertine-home/libertine-container/user-data/container-name/.local/share/applications/user-app.desktop (+4/-0) tests/libual-test.cc (+15/-4) |
To merge this branch: | bzr merge lp:~ted/ubuntu-app-launch/libertine-detection |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Christopher Townsend | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Charles Kerr (community) | Approve | ||
Review via email: mp+264789@code.launchpad.net |
Commit message
Detect applications that are in a libertine container
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:211
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Charles Kerr (charlesk) wrote : | # |
Mostly LGTM, no blockers, a few suggestions/
Ted Gould (ted) wrote : | # |
Took your comments into account. The shared function was actually in a different branch I was working on, so I pulled it into this one. Also added the detection of libertine apps that are in the container's ~/.local/
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:217
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Charles Kerr (charlesk) : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:218
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:223
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Christopher Townsend (townsend) wrote : | # |
Ok, looks good.
Preview Diff
1 | === modified file 'helpers-shared.c' |
2 | --- helpers-shared.c 2014-11-21 21:17:18 +0000 |
3 | +++ helpers-shared.c 2015-08-11 22:16:35 +0000 |
4 | @@ -25,7 +25,7 @@ |
5 | #include "libubuntu-app-launch/recoverable-problem.h" |
6 | |
7 | /* Check to make sure we have the sections and keys we want */ |
8 | -static gboolean |
9 | +gboolean |
10 | verify_keyfile (GKeyFile * inkeyfile, const gchar * desktop) |
11 | { |
12 | if (inkeyfile == NULL) return FALSE; |
13 | |
14 | === modified file 'helpers.h' |
15 | --- helpers.h 2014-11-20 20:33:59 +0000 |
16 | +++ helpers.h 2015-08-11 22:16:35 +0000 |
17 | @@ -54,3 +54,5 @@ |
18 | const gchar * jobname, |
19 | const gchar * instancename); |
20 | |
21 | +gboolean verify_keyfile (GKeyFile * inkeyfile, |
22 | + const gchar * desktop); |
23 | |
24 | === modified file 'libubuntu-app-launch/CMakeLists.txt' |
25 | --- libubuntu-app-launch/CMakeLists.txt 2015-04-30 15:21:05 +0000 |
26 | +++ libubuntu-app-launch/CMakeLists.txt 2015-08-11 22:16:35 +0000 |
27 | @@ -18,6 +18,7 @@ |
28 | |
29 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") |
30 | add_definitions ( -DOOM_HELPER="${pkglibexecdir}/oom-adjust-setuid-helper" -DDEMANGLER_PATH="${pkglibexecdir}/socket-demangler" ) |
31 | +add_definitions ( -DLIBERTINE_LAUNCH="${CMAKE_INSTALL_FULL_BINDIR}/libertine-launch" ) |
32 | |
33 | set(LAUNCHER_HEADERS |
34 | ubuntu-app-launch.h |
35 | @@ -29,6 +30,7 @@ |
36 | click-exec.c |
37 | desktop-exec.c |
38 | ubuntu-app-launch-trace.c |
39 | +app-info.c |
40 | ) |
41 | |
42 | set(LAUNCHER_GEN_SOURCES |
43 | |
44 | === added file 'libubuntu-app-launch/app-info.c' |
45 | --- libubuntu-app-launch/app-info.c 1970-01-01 00:00:00 +0000 |
46 | +++ libubuntu-app-launch/app-info.c 2015-08-11 22:16:35 +0000 |
47 | @@ -0,0 +1,245 @@ |
48 | +/* |
49 | + * Copyright © 2015 Canonical Ltd. |
50 | + * |
51 | + * This program is free software: you can redistribute it and/or modify it |
52 | + * under the terms of the GNU General Public License version 3, as published |
53 | + * by the Free Software Foundation. |
54 | + * |
55 | + * This program is distributed in the hope that it will be useful, but |
56 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
57 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
58 | + * PURPOSE. See the GNU General Public License for more details. |
59 | + * |
60 | + * You should have received a copy of the GNU General Public License along |
61 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
62 | + * |
63 | + * Authors: |
64 | + * Ted Gould <ted.gould@canonical.com> |
65 | + */ |
66 | + |
67 | +#include <json-glib/json-glib.h> |
68 | +#include <click.h> |
69 | + |
70 | +#include "ubuntu-app-launch.h" |
71 | +#include "app-info.h" |
72 | + |
73 | +/* Try and get a manifest and do a couple sanity checks on it */ |
74 | +static JsonObject * |
75 | +get_manifest (const gchar * pkg) |
76 | +{ |
77 | + /* Get the directory from click */ |
78 | + GError * error = NULL; |
79 | + |
80 | + ClickDB * db = click_db_new(); |
81 | + /* If TEST_CLICK_DB is unset, this reads the system database. */ |
82 | + click_db_read(db, g_getenv("TEST_CLICK_DB"), &error); |
83 | + if (error != NULL) { |
84 | + g_warning("Unable to read Click database: %s", error->message); |
85 | + g_error_free(error); |
86 | + g_object_unref(db); |
87 | + return NULL; |
88 | + } |
89 | + /* If TEST_CLICK_USER is unset, this uses the current user name. */ |
90 | + ClickUser * user = click_user_new_for_user(db, g_getenv("TEST_CLICK_USER"), &error); |
91 | + if (error != NULL) { |
92 | + g_warning("Unable to read Click database: %s", error->message); |
93 | + g_error_free(error); |
94 | + g_object_unref(db); |
95 | + return NULL; |
96 | + } |
97 | + g_object_unref(db); |
98 | + JsonObject * manifest = click_user_get_manifest(user, pkg, &error); |
99 | + if (error != NULL) { |
100 | + g_warning("Unable to get manifest for '%s' package: %s", pkg, error->message); |
101 | + g_error_free(error); |
102 | + g_object_unref(user); |
103 | + return NULL; |
104 | + } |
105 | + g_object_unref(user); |
106 | + |
107 | + if (!json_object_has_member(manifest, "version")) { |
108 | + g_warning("Manifest file for package '%s' does not have a version", pkg); |
109 | + json_object_unref(manifest); |
110 | + return NULL; |
111 | + } |
112 | + |
113 | + return manifest; |
114 | +} |
115 | + |
116 | +/* Types of search we can do for an app name */ |
117 | +typedef enum _app_name_t app_name_t; |
118 | +enum _app_name_t { |
119 | + APP_NAME_ONLY, |
120 | + APP_NAME_FIRST, |
121 | + APP_NAME_LAST |
122 | +}; |
123 | + |
124 | +/* Figure out the app name if it's one of the keywords */ |
125 | +static const gchar * |
126 | +manifest_app_name (JsonObject ** manifest, const gchar * pkg, const gchar * original_app) |
127 | +{ |
128 | + app_name_t app_type = APP_NAME_FIRST; |
129 | + |
130 | + if (original_app == NULL) { |
131 | + /* first */ |
132 | + } else if (g_strcmp0(original_app, "first-listed-app") == 0) { |
133 | + /* first */ |
134 | + } else if (g_strcmp0(original_app, "last-listed-app") == 0) { |
135 | + app_type = APP_NAME_LAST; |
136 | + } else if (g_strcmp0(original_app, "only-listed-app") == 0) { |
137 | + app_type = APP_NAME_ONLY; |
138 | + } else { |
139 | + return original_app; |
140 | + } |
141 | + |
142 | + if (*manifest == NULL) { |
143 | + *manifest = get_manifest(pkg); |
144 | + } |
145 | + |
146 | + JsonObject * hooks = json_object_get_object_member(*manifest, "hooks"); |
147 | + |
148 | + if (hooks == NULL) { |
149 | + return NULL; |
150 | + } |
151 | + |
152 | + GList * apps = json_object_get_members(hooks); |
153 | + if (apps == NULL) { |
154 | + return NULL; |
155 | + } |
156 | + |
157 | + const gchar * retapp = NULL; |
158 | + |
159 | + switch (app_type) { |
160 | + case APP_NAME_ONLY: |
161 | + if (g_list_length(apps) == 1) { |
162 | + retapp = (const gchar *)apps->data; |
163 | + } |
164 | + break; |
165 | + case APP_NAME_FIRST: |
166 | + retapp = (const gchar *)apps->data; |
167 | + break; |
168 | + case APP_NAME_LAST: |
169 | + retapp = (const gchar *)(g_list_last(apps)->data); |
170 | + break; |
171 | + default: |
172 | + break; |
173 | + } |
174 | + |
175 | + g_list_free(apps); |
176 | + |
177 | + return retapp; |
178 | +} |
179 | + |
180 | +/* Figure out the app version using the manifest */ |
181 | +static const gchar * |
182 | +manifest_version (JsonObject ** manifest, const gchar * pkg, const gchar * original_ver) |
183 | +{ |
184 | + if (original_ver != NULL && g_strcmp0(original_ver, "current-user-version") != 0) { |
185 | + return original_ver; |
186 | + } else { |
187 | + if (*manifest == NULL) { |
188 | + *manifest = get_manifest(pkg); |
189 | + } |
190 | + g_return_val_if_fail(*manifest != NULL, NULL); |
191 | + |
192 | + return g_strdup(json_object_get_string_member(*manifest, "version")); |
193 | + } |
194 | + |
195 | + return NULL; |
196 | +} |
197 | + |
198 | +/* A click triplet can require using the Click DB and getting a |
199 | + manifest. This code does that to look up the versions */ |
200 | +gchar * |
201 | +click_triplet_to_app_id (const gchar * pkg, const gchar * app, const gchar * ver) |
202 | +{ |
203 | + const gchar * version = NULL; |
204 | + const gchar * application = NULL; |
205 | + JsonObject * manifest = NULL; |
206 | + |
207 | + version = manifest_version(&manifest, pkg, ver); |
208 | + g_return_val_if_fail(version != NULL, NULL); |
209 | + |
210 | + application = manifest_app_name(&manifest, pkg, app); |
211 | + g_return_val_if_fail(application != NULL, NULL); |
212 | + |
213 | + gchar * retval = g_strdup_printf("%s_%s_%s", pkg, application, version); |
214 | + |
215 | + /* The object may hold allocation for some of our strings used above */ |
216 | + if (manifest) |
217 | + json_object_unref(manifest); |
218 | + |
219 | + return retval; |
220 | +} |
221 | + |
222 | +/* Build an appid how we think it should exist and then make sure |
223 | + we can find it. Then pull it together. */ |
224 | +gchar * |
225 | +libertine_triplet_to_app_id (const gchar * pkg, const gchar * app, const gchar * ver) |
226 | +{ |
227 | + if (app == NULL) { |
228 | + return NULL; |
229 | + } |
230 | + |
231 | + gchar * synthappid = g_strdup_printf("%s_%s_0.0", pkg, app); |
232 | + if (app_info_libertine(synthappid, NULL, NULL)) { |
233 | + return synthappid; |
234 | + } else { |
235 | + g_free(synthappid); |
236 | + return NULL; |
237 | + } |
238 | +} |
239 | + |
240 | +/* Handle the libertine case where we look in the container */ |
241 | +gboolean |
242 | +app_info_libertine (const gchar * appid, gchar ** appdir, gchar ** appdesktop) |
243 | +{ |
244 | + char * container = NULL; |
245 | + char * app = NULL; |
246 | + |
247 | + if (!ubuntu_app_launch_app_id_parse(appid, &container, &app, NULL)) { |
248 | + return FALSE; |
249 | + } |
250 | + |
251 | + gchar * desktopname = g_strdup_printf("%s.desktop", app); |
252 | + |
253 | + gchar * desktopdir = g_build_filename(g_get_user_cache_dir(), "libertine-container", container, "rootfs", "usr", "share", NULL); |
254 | + gchar * desktopfile = g_build_filename(desktopdir, "applications", desktopname, NULL); |
255 | + |
256 | + if (!g_file_test(desktopfile, G_FILE_TEST_EXISTS)) { |
257 | + g_free(desktopdir); |
258 | + g_free(desktopfile); |
259 | + |
260 | + desktopdir = g_build_filename(g_get_user_data_dir(), "libertine-container", "user-data", container, ".local", "share", NULL); |
261 | + desktopfile = g_build_filename(desktopdir, "applications", desktopname, NULL); |
262 | + |
263 | + if (!g_file_test(desktopfile, G_FILE_TEST_EXISTS)) { |
264 | + g_free(desktopdir); |
265 | + g_free(desktopfile); |
266 | + |
267 | + g_free(desktopname); |
268 | + g_free(container); |
269 | + g_free(app); |
270 | + |
271 | + return FALSE; |
272 | + } |
273 | + } |
274 | + |
275 | + g_free(desktopname); |
276 | + g_free(container); |
277 | + g_free(app); |
278 | + |
279 | + if (appdir != NULL) { |
280 | + *appdir = desktopdir; |
281 | + } else { |
282 | + g_free(desktopdir); |
283 | + } |
284 | + |
285 | + if (appdesktop != NULL) { |
286 | + *appdesktop = desktopfile; |
287 | + } else { |
288 | + g_free(desktopfile); |
289 | + } |
290 | + |
291 | + return TRUE; |
292 | +} |
293 | |
294 | === added file 'libubuntu-app-launch/app-info.h' |
295 | --- libubuntu-app-launch/app-info.h 1970-01-01 00:00:00 +0000 |
296 | +++ libubuntu-app-launch/app-info.h 2015-08-11 22:16:35 +0000 |
297 | @@ -0,0 +1,27 @@ |
298 | +/* |
299 | + * Copyright © 2015 Canonical Ltd. |
300 | + * |
301 | + * This program is free software: you can redistribute it and/or modify it |
302 | + * under the terms of the GNU General Public License version 3, as published |
303 | + * by the Free Software Foundation. |
304 | + * |
305 | + * This program is distributed in the hope that it will be useful, but |
306 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
307 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
308 | + * PURPOSE. See the GNU General Public License for more details. |
309 | + * |
310 | + * You should have received a copy of the GNU General Public License along |
311 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
312 | + * |
313 | + * Authors: |
314 | + * Ted Gould <ted.gould@canonical.com> |
315 | + */ |
316 | + |
317 | +#pragma once |
318 | + |
319 | +#include <glib.h> |
320 | + |
321 | +gboolean app_info_libertine (const gchar * appid, gchar ** appdir, gchar ** appdesktop); |
322 | + |
323 | +gchar * click_triplet_to_app_id (const gchar * pkg, const gchar * app, const gchar * ver); |
324 | +gchar * libertine_triplet_to_app_id (const gchar * pkg, const gchar * app, const gchar * ver); |
325 | |
326 | === modified file 'libubuntu-app-launch/desktop-exec.c' |
327 | --- libubuntu-app-launch/desktop-exec.c 2015-08-11 22:16:34 +0000 |
328 | +++ libubuntu-app-launch/desktop-exec.c 2015-08-11 22:16:35 +0000 |
329 | @@ -27,6 +27,8 @@ |
330 | #include "ubuntu-app-launch-trace.h" |
331 | #include "recoverable-problem.h" |
332 | #include "ual-tracepoint.h" |
333 | +#include "ubuntu-app-launch.h" |
334 | +#include "app-info.h" |
335 | |
336 | /* Reports an error on the caller of UAL so that we can track |
337 | who is trying to launch bad AppIDs, and then fix their bug |
338 | @@ -70,8 +72,46 @@ |
339 | } |
340 | } |
341 | |
342 | +/* Get the keyfile object for a libertine container based application. Look into |
343 | + the container's filesystem on disk and find it in /usr/share/applications in there. |
344 | + Those are currently the only apps that we look at today. We're not ensuring anything |
345 | + about the file other than it has basic sanity. */ |
346 | +GKeyFile * |
347 | +keyfile_for_libertine (const gchar * appid, gchar ** outcontainer) |
348 | +{ |
349 | + gchar * desktopfile = NULL; |
350 | + |
351 | + if (!app_info_libertine(appid, NULL, &desktopfile)) { |
352 | + return NULL; |
353 | + } |
354 | + |
355 | + /* We now think we have a valid 'desktopfile' path */ |
356 | + GKeyFile * keyfile = g_key_file_new(); |
357 | + gboolean loaded = g_key_file_load_from_file(keyfile, desktopfile, G_KEY_FILE_NONE, NULL); |
358 | + |
359 | + if (!loaded) { |
360 | + g_free(desktopfile); |
361 | + g_key_file_free(keyfile); |
362 | + return NULL; |
363 | + } |
364 | + |
365 | + if (!verify_keyfile(keyfile, desktopfile)) { |
366 | + g_free(desktopfile); |
367 | + g_key_file_free(keyfile); |
368 | + return NULL; |
369 | + } |
370 | + |
371 | + g_free(desktopfile); |
372 | + |
373 | + if (outcontainer != NULL) { |
374 | + ubuntu_app_launch_app_id_parse(appid, outcontainer, NULL, NULL); |
375 | + } |
376 | + |
377 | + return keyfile; |
378 | +} |
379 | + |
380 | gboolean |
381 | -desktop_task_setup (GDBusConnection * bus, const gchar * app_id, EnvHandle * handle) |
382 | +desktop_task_setup (GDBusConnection * bus, const gchar * app_id, EnvHandle * handle, gboolean is_libertine) |
383 | { |
384 | if (app_id == NULL) { |
385 | g_error("No APP_ID environment variable defined"); |
386 | @@ -88,10 +128,18 @@ |
387 | ual_tracepoint(desktop_starting_sent, app_id); |
388 | |
389 | gchar * desktopfilename = NULL; |
390 | - GKeyFile * keyfile = keyfile_for_appid(app_id, &desktopfilename); |
391 | + GKeyFile * keyfile = NULL; |
392 | + gchar * libertinecontainer = NULL; |
393 | + if (is_libertine) { |
394 | + /* desktopfilename not set, not useful in this context */ |
395 | + keyfile = keyfile_for_libertine(app_id, &libertinecontainer); |
396 | + } else { |
397 | + keyfile = keyfile_for_appid(app_id, &desktopfilename); |
398 | + } |
399 | |
400 | if (keyfile == NULL) { |
401 | report_error_on_caller(app_id); |
402 | + g_free(libertinecontainer); |
403 | return FALSE; |
404 | } |
405 | |
406 | @@ -124,12 +172,31 @@ |
407 | } else { |
408 | env_handle_add(handle, "APP_XMIR_ENABLE", "0"); |
409 | } |
410 | + } else if (is_libertine) { |
411 | + /* Default to X for libertine stuff */ |
412 | + env_handle_add(handle, "APP_XMIR_ENABLE", "1"); |
413 | } |
414 | |
415 | /* This string is quoted using desktop file quoting: |
416 | http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables */ |
417 | gchar * execline = desktop_to_exec(keyfile, app_id); |
418 | g_return_val_if_fail(execline != NULL, 1); |
419 | + |
420 | + if (is_libertine) { |
421 | + static const gchar * libertine_launch = NULL; |
422 | + if (G_UNLIKELY(libertine_launch == NULL)) { |
423 | + libertine_launch = g_getenv("UBUNTU_APP_LAUNCH_LIBERTINE_LAUNCH"); |
424 | + if (libertine_launch == NULL) { |
425 | + libertine_launch = LIBERTINE_LAUNCH; |
426 | + } |
427 | + } |
428 | + |
429 | + gchar * libexec = g_strdup_printf("%s \"%s\" %s", libertine_launch, libertinecontainer, execline); |
430 | + g_free(execline); |
431 | + execline = libexec; |
432 | + } |
433 | + g_free(libertinecontainer); /* Handles NULL, let's be sure it goes away */ |
434 | + |
435 | env_handle_add(handle, "APP_EXEC", execline); |
436 | g_free(execline); |
437 | |
438 | |
439 | === modified file 'libubuntu-app-launch/desktop-exec.h' |
440 | --- libubuntu-app-launch/desktop-exec.h 2014-08-22 20:59:55 +0000 |
441 | +++ libubuntu-app-launch/desktop-exec.h 2015-08-11 22:16:35 +0000 |
442 | @@ -17,8 +17,10 @@ |
443 | * Ted Gould <ted.gould@canonical.com> |
444 | */ |
445 | |
446 | +#pragma once |
447 | + |
448 | #include <glib.h> |
449 | #include "helpers.h" |
450 | |
451 | -gboolean desktop_task_setup (GDBusConnection * bus, const gchar * appid, EnvHandle * envhandle); |
452 | +gboolean desktop_task_setup (GDBusConnection * bus, const gchar * appid, EnvHandle * envhandle, gboolean is_libertine); |
453 | |
454 | |
455 | === modified file 'libubuntu-app-launch/ubuntu-app-launch-trace.tp' |
456 | --- libubuntu-app-launch/ubuntu-app-launch-trace.tp 2014-08-21 21:00:53 +0000 |
457 | +++ libubuntu-app-launch/ubuntu-app-launch-trace.tp 2015-08-11 22:16:35 +0000 |
458 | @@ -18,6 +18,13 @@ |
459 | ctf_string(type, type) |
460 | ) |
461 | ) |
462 | +TRACEPOINT_EVENT(ubuntu_app_launch, libual_determine_libertine, |
463 | + TP_ARGS(const char *, appid, const char *, executionenv), |
464 | + TP_FIELDS( |
465 | + ctf_string(appid, appid) |
466 | + ctf_string(executionenv, executionenv) |
467 | + ) |
468 | +) |
469 | TRACEPOINT_EVENT(ubuntu_app_launch, libual_job_path_determined, |
470 | TP_ARGS(const char *, appid, const char *, job_path), |
471 | TP_FIELDS( |
472 | |
473 | === modified file 'libubuntu-app-launch/ubuntu-app-launch.c' |
474 | --- libubuntu-app-launch/ubuntu-app-launch.c 2015-06-04 20:22:27 +0000 |
475 | +++ libubuntu-app-launch/ubuntu-app-launch.c 2015-08-11 22:16:35 +0000 |
476 | @@ -18,8 +18,6 @@ |
477 | */ |
478 | |
479 | #include "ubuntu-app-launch.h" |
480 | -#include <json-glib/json-glib.h> |
481 | -#include <click.h> |
482 | #include <upstart.h> |
483 | #include <gio/gio.h> |
484 | #include <gio/gunixfdlist.h> |
485 | @@ -36,6 +34,7 @@ |
486 | #include "desktop-exec.h" |
487 | #include "recoverable-problem.h" |
488 | #include "proxy-socket-demangler.h" |
489 | +#include "app-info.h" |
490 | |
491 | static void apps_for_job (GDBusConnection * con, const gchar * name, GArray * apps, gboolean truncate_legacy); |
492 | static void free_helper (gpointer value); |
493 | @@ -208,6 +207,19 @@ |
494 | return click; |
495 | } |
496 | |
497 | +/* Determine whether an AppId is realated to a Libertine container by |
498 | + checking the container and program name. */ |
499 | +static gboolean |
500 | +is_libertine (const gchar * appid) |
501 | +{ |
502 | + if (app_info_libertine(appid, NULL, NULL)) { |
503 | + g_debug("Libertine application detected: %s", appid); |
504 | + return TRUE; |
505 | + } else { |
506 | + return FALSE; |
507 | + } |
508 | +} |
509 | + |
510 | static gboolean |
511 | start_application_core (const gchar * appid, const gchar * const * uris, gboolean test) |
512 | { |
513 | @@ -221,6 +233,14 @@ |
514 | gboolean click = is_click(appid); |
515 | ual_tracepoint(libual_determine_type, appid, click ? "click" : "legacy"); |
516 | |
517 | + /* Figure out if it is libertine */ |
518 | + gboolean libertine = FALSE; |
519 | + if (!click) { |
520 | + libertine = is_libertine(appid); |
521 | + } |
522 | + |
523 | + ual_tracepoint(libual_determine_libertine, appid, libertine ? "container" : "host"); |
524 | + |
525 | /* Figure out the DBus path for the job */ |
526 | const gchar * jobpath = NULL; |
527 | if (click) { |
528 | @@ -258,7 +278,7 @@ |
529 | } |
530 | |
531 | if (!click) { |
532 | - if (legacy_single_instance(appid)) { |
533 | + if (libertine || legacy_single_instance(appid)) { |
534 | g_variant_builder_add_value(&builder, g_variant_new_string("INSTANCE_ID=")); |
535 | } else { |
536 | gchar * instanceid = g_strdup_printf("INSTANCE_ID=%" G_GUINT64_FORMAT, g_get_real_time()); |
537 | @@ -274,7 +294,7 @@ |
538 | if (click) { |
539 | setup_complete = click_task_setup(con, appid, (EnvHandle*)&builder); |
540 | } else { |
541 | - setup_complete = desktop_task_setup(con, appid, (EnvHandle*)&builder); |
542 | + setup_complete = desktop_task_setup(con, appid, (EnvHandle*)&builder, libertine); |
543 | } |
544 | |
545 | if (setup_complete) { |
546 | @@ -694,7 +714,7 @@ |
547 | return path; |
548 | } |
549 | |
550 | - if (legacy_single_instance(appid)) { |
551 | + if (!is_libertine(appid) && legacy_single_instance(appid)) { |
552 | gchar * appfile = g_strdup_printf("application-legacy-%s-.log", appid); |
553 | path = g_build_filename(g_get_user_cache_dir(), "upstart", appfile, NULL); |
554 | g_free(appfile); |
555 | @@ -1490,7 +1510,7 @@ |
556 | |
557 | ual_tracepoint(pids_list_finished, appid, g_list_length(pids)); |
558 | return pids; |
559 | - } else if (legacy_single_instance(appid)) { |
560 | + } else if (!is_libertine(appid) && legacy_single_instance(appid)) { |
561 | gchar * jobname = g_strdup_printf("%s-", appid); |
562 | GList * pids = pids_from_cgroup(cgmanager, "application-legacy", jobname); |
563 | g_free(jobname); |
564 | @@ -1590,153 +1610,23 @@ |
565 | return TRUE; |
566 | } |
567 | |
568 | -/* Try and get a manifest and do a couple sanity checks on it */ |
569 | -static JsonObject * |
570 | -get_manifest (const gchar * pkg) |
571 | -{ |
572 | - /* Get the directory from click */ |
573 | - GError * error = NULL; |
574 | - |
575 | - ClickDB * db = click_db_new(); |
576 | - /* If TEST_CLICK_DB is unset, this reads the system database. */ |
577 | - click_db_read(db, g_getenv("TEST_CLICK_DB"), &error); |
578 | - if (error != NULL) { |
579 | - g_warning("Unable to read Click database: %s", error->message); |
580 | - g_error_free(error); |
581 | - g_object_unref(db); |
582 | - return NULL; |
583 | - } |
584 | - /* If TEST_CLICK_USER is unset, this uses the current user name. */ |
585 | - ClickUser * user = click_user_new_for_user(db, g_getenv("TEST_CLICK_USER"), &error); |
586 | - if (error != NULL) { |
587 | - g_warning("Unable to read Click database: %s", error->message); |
588 | - g_error_free(error); |
589 | - g_object_unref(db); |
590 | - return NULL; |
591 | - } |
592 | - g_object_unref(db); |
593 | - JsonObject * manifest = click_user_get_manifest(user, pkg, &error); |
594 | - if (error != NULL) { |
595 | - g_warning("Unable to get manifest for '%s' package: %s", pkg, error->message); |
596 | - g_error_free(error); |
597 | - g_object_unref(user); |
598 | - return NULL; |
599 | - } |
600 | - g_object_unref(user); |
601 | - |
602 | - if (!json_object_has_member(manifest, "version")) { |
603 | - g_warning("Manifest file for package '%s' does not have a version", pkg); |
604 | - json_object_unref(manifest); |
605 | - return NULL; |
606 | - } |
607 | - |
608 | - return manifest; |
609 | -} |
610 | - |
611 | -/* Types of search we can do for an app name */ |
612 | -typedef enum _app_name_t app_name_t; |
613 | -enum _app_name_t { |
614 | - APP_NAME_ONLY, |
615 | - APP_NAME_FIRST, |
616 | - APP_NAME_LAST |
617 | -}; |
618 | - |
619 | -/* Figure out the app name if it's one of the keywords */ |
620 | -static const gchar * |
621 | -manifest_app_name (JsonObject ** manifest, const gchar * pkg, const gchar * original_app) |
622 | -{ |
623 | - app_name_t app_type = APP_NAME_FIRST; |
624 | - |
625 | - if (original_app == NULL) { |
626 | - /* first */ |
627 | - } else if (g_strcmp0(original_app, "first-listed-app") == 0) { |
628 | - /* first */ |
629 | - } else if (g_strcmp0(original_app, "last-listed-app") == 0) { |
630 | - app_type = APP_NAME_LAST; |
631 | - } else if (g_strcmp0(original_app, "only-listed-app") == 0) { |
632 | - app_type = APP_NAME_ONLY; |
633 | - } else { |
634 | - return original_app; |
635 | - } |
636 | - |
637 | - if (*manifest == NULL) { |
638 | - *manifest = get_manifest(pkg); |
639 | - } |
640 | - |
641 | - JsonObject * hooks = json_object_get_object_member(*manifest, "hooks"); |
642 | - |
643 | - if (hooks == NULL) { |
644 | - return NULL; |
645 | - } |
646 | - |
647 | - GList * apps = json_object_get_members(hooks); |
648 | - if (apps == NULL) { |
649 | - return NULL; |
650 | - } |
651 | - |
652 | - const gchar * retapp = NULL; |
653 | - |
654 | - switch (app_type) { |
655 | - case APP_NAME_ONLY: |
656 | - if (g_list_length(apps) == 1) { |
657 | - retapp = (const gchar *)apps->data; |
658 | - } |
659 | - break; |
660 | - case APP_NAME_FIRST: |
661 | - retapp = (const gchar *)apps->data; |
662 | - break; |
663 | - case APP_NAME_LAST: |
664 | - retapp = (const gchar *)(g_list_last(apps)->data); |
665 | - break; |
666 | - default: |
667 | - break; |
668 | - } |
669 | - |
670 | - g_list_free(apps); |
671 | - |
672 | - return retapp; |
673 | -} |
674 | - |
675 | -/* Figure out the app version using the manifest */ |
676 | -static const gchar * |
677 | -manifest_version (JsonObject ** manifest, const gchar * pkg, const gchar * original_ver) |
678 | -{ |
679 | - if (original_ver != NULL && g_strcmp0(original_ver, "current-user-version") != 0) { |
680 | - return original_ver; |
681 | - } else { |
682 | - if (*manifest == NULL) { |
683 | - *manifest = get_manifest(pkg); |
684 | - } |
685 | - g_return_val_if_fail(*manifest != NULL, NULL); |
686 | - |
687 | - return g_strdup(json_object_get_string_member(*manifest, "version")); |
688 | - } |
689 | - |
690 | - return NULL; |
691 | -} |
692 | - |
693 | +/* Figure out whether we're a libertine container app or a click and then |
694 | + choose which function to use */ |
695 | gchar * |
696 | ubuntu_app_launch_triplet_to_app_id (const gchar * pkg, const gchar * app, const gchar * ver) |
697 | { |
698 | g_return_val_if_fail(pkg != NULL, NULL); |
699 | |
700 | - const gchar * version = NULL; |
701 | - const gchar * application = NULL; |
702 | - JsonObject * manifest = NULL; |
703 | - |
704 | - version = manifest_version(&manifest, pkg, ver); |
705 | - g_return_val_if_fail(version != NULL, NULL); |
706 | - |
707 | - application = manifest_app_name(&manifest, pkg, app); |
708 | - g_return_val_if_fail(application != NULL, NULL); |
709 | - |
710 | - gchar * retval = g_strdup_printf("%s_%s_%s", pkg, application, version); |
711 | - |
712 | - /* The object may hold allocation for some of our strings used above */ |
713 | - if (manifest) |
714 | - json_object_unref(manifest); |
715 | - |
716 | - return retval; |
717 | + /* Check if is a libertine container */ |
718 | + gchar * libertinepath = g_build_filename(g_get_user_cache_dir(), "libertine-container", pkg, NULL); |
719 | + gboolean libcontainer = g_file_test(libertinepath, G_FILE_TEST_EXISTS); |
720 | + g_free(libertinepath); |
721 | + |
722 | + if (libcontainer) { |
723 | + return libertine_triplet_to_app_id(pkg, app, ver); |
724 | + } else { |
725 | + return click_triplet_to_app_id(pkg, app, ver); |
726 | + } |
727 | } |
728 | |
729 | /* Print an error if we couldn't start it */ |
730 | |
731 | === modified file 'tests/exec-util-test.cc' |
732 | --- tests/exec-util-test.cc 2015-08-11 22:16:34 +0000 |
733 | +++ tests/exec-util-test.cc 2015-08-11 22:16:35 +0000 |
734 | @@ -40,6 +40,9 @@ |
735 | virtual void SetUp() { |
736 | g_setenv("UPSTART_JOB", "made-up-job", TRUE); |
737 | g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE); |
738 | + g_setenv("XDG_CACHE_HOME", CMAKE_SOURCE_DIR "/libertine-data", TRUE); |
739 | + g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE); |
740 | + g_setenv("UBUNTU_APP_LAUNCH_LIBERTINE_LAUNCH", "libertine-launch", TRUE); |
741 | |
742 | service = dbus_test_service_new(NULL); |
743 | |
744 | @@ -279,3 +282,37 @@ |
745 | EXPECT_STREQ("0", value); }}, |
746 | }); |
747 | } |
748 | + |
749 | +TEST_F(ExecUtil, LibertineExec) |
750 | +{ |
751 | + StartCheckEnv("container-name_test_0.0", { |
752 | + {"APP_EXEC", [](const gchar * value) { |
753 | + EXPECT_STREQ("libertine-launch \"container-name\" test", value); }}, |
754 | + {"APP_EXEC_POLICY", [](const gchar * value) { |
755 | + EXPECT_STREQ("unconfined", value); }}, |
756 | + {"APP_ID", [](const gchar * value) { |
757 | + EXPECT_STREQ("container-name_test_0.0", value); }}, |
758 | + {"APP_LAUNCHER_PID", [](const gchar * value) { |
759 | + EXPECT_EQ(getpid(), atoi(value)); }}, |
760 | + {"INSTANCE_ID", nocheck}, |
761 | + {"APP_XMIR_ENABLE", [](const gchar * value) { |
762 | + EXPECT_STREQ("1", value); }}, |
763 | + }); |
764 | +} |
765 | + |
766 | +TEST_F(ExecUtil, LibertineExecUser) |
767 | +{ |
768 | + StartCheckEnv("container-name_user-app_0.0", { |
769 | + {"APP_EXEC", [](const gchar * value) { |
770 | + EXPECT_STREQ("libertine-launch \"container-name\" user-app", value); }}, |
771 | + {"APP_EXEC_POLICY", [](const gchar * value) { |
772 | + EXPECT_STREQ("unconfined", value); }}, |
773 | + {"APP_ID", [](const gchar * value) { |
774 | + EXPECT_STREQ("container-name_user-app_0.0", value); }}, |
775 | + {"APP_LAUNCHER_PID", [](const gchar * value) { |
776 | + EXPECT_EQ(getpid(), atoi(value)); }}, |
777 | + {"INSTANCE_ID", nocheck}, |
778 | + {"APP_XMIR_ENABLE", [](const gchar * value) { |
779 | + EXPECT_STREQ("1", value); }}, |
780 | + }); |
781 | +} |
782 | |
783 | === added directory 'tests/libertine-data' |
784 | === added directory 'tests/libertine-data/libertine-container' |
785 | === added directory 'tests/libertine-data/libertine-container/container-name' |
786 | === added directory 'tests/libertine-data/libertine-container/container-name/rootfs' |
787 | === added directory 'tests/libertine-data/libertine-container/container-name/rootfs/usr' |
788 | === added directory 'tests/libertine-data/libertine-container/container-name/rootfs/usr/share' |
789 | === added directory 'tests/libertine-data/libertine-container/container-name/rootfs/usr/share/applications' |
790 | === added file 'tests/libertine-data/libertine-container/container-name/rootfs/usr/share/applications/test.desktop' |
791 | --- tests/libertine-data/libertine-container/container-name/rootfs/usr/share/applications/test.desktop 1970-01-01 00:00:00 +0000 |
792 | +++ tests/libertine-data/libertine-container/container-name/rootfs/usr/share/applications/test.desktop 2015-08-11 22:16:35 +0000 |
793 | @@ -0,0 +1,4 @@ |
794 | +[Desktop Entry] |
795 | +Name=Test |
796 | +Type=Application |
797 | +Exec=test |
798 | |
799 | === added directory 'tests/libertine-home' |
800 | === added directory 'tests/libertine-home/libertine-container' |
801 | === added directory 'tests/libertine-home/libertine-container/user-data' |
802 | === added directory 'tests/libertine-home/libertine-container/user-data/container-name' |
803 | === added directory 'tests/libertine-home/libertine-container/user-data/container-name/.local' |
804 | === added directory 'tests/libertine-home/libertine-container/user-data/container-name/.local/share' |
805 | === added directory 'tests/libertine-home/libertine-container/user-data/container-name/.local/share/applications' |
806 | === added file 'tests/libertine-home/libertine-container/user-data/container-name/.local/share/applications/user-app.desktop' |
807 | --- tests/libertine-home/libertine-container/user-data/container-name/.local/share/applications/user-app.desktop 1970-01-01 00:00:00 +0000 |
808 | +++ tests/libertine-home/libertine-container/user-data/container-name/.local/share/applications/user-app.desktop 2015-08-11 22:16:35 +0000 |
809 | @@ -0,0 +1,4 @@ |
810 | +[Desktop Entry] |
811 | +Name=User App |
812 | +Type=Application |
813 | +Exec=user-app |
814 | |
815 | === modified file 'tests/libual-test.cc' |
816 | --- tests/libual-test.cc 2015-06-04 20:22:27 +0000 |
817 | +++ tests/libual-test.cc 2015-08-11 22:16:35 +0000 |
818 | @@ -84,7 +84,8 @@ |
819 | g_free(linkfarmpath); |
820 | |
821 | g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE); |
822 | - g_setenv("XDG_CACHE_HOME", CMAKE_SOURCE_DIR, TRUE); |
823 | + g_setenv("XDG_CACHE_HOME", CMAKE_SOURCE_DIR "/libertine-data", TRUE); |
824 | + g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE); |
825 | |
826 | service = dbus_test_service_new(NULL); |
827 | |
828 | @@ -435,18 +436,22 @@ |
829 | |
830 | } |
831 | |
832 | +/* NOTE: The fact that there is 'libertine-data' in these strings is because |
833 | + we're using one CACHE_HOME for this test suite and the libertine functions |
834 | + need to pull things from there, where these are only comparisons. It's just |
835 | + what value is in the environment variable */ |
836 | TEST_F(LibUAL, ApplicationLog) |
837 | { |
838 | gchar * click_log = ubuntu_app_launch_application_log_path("com.test.good_application_1.2.3"); |
839 | - EXPECT_STREQ(CMAKE_SOURCE_DIR "/upstart/application-click-com.test.good_application_1.2.3.log", click_log); |
840 | + EXPECT_STREQ(CMAKE_SOURCE_DIR "/libertine-data/upstart/application-click-com.test.good_application_1.2.3.log", click_log); |
841 | g_free(click_log); |
842 | |
843 | gchar * legacy_single = ubuntu_app_launch_application_log_path("single"); |
844 | - EXPECT_STREQ(CMAKE_SOURCE_DIR "/upstart/application-legacy-single-.log", legacy_single); |
845 | + EXPECT_STREQ(CMAKE_SOURCE_DIR "/libertine-data/upstart/application-legacy-single-.log", legacy_single); |
846 | g_free(legacy_single); |
847 | |
848 | gchar * legacy_multiple = ubuntu_app_launch_application_log_path("bar"); |
849 | - EXPECT_STREQ(CMAKE_SOURCE_DIR "/upstart/application-legacy-bar-2342345.log", legacy_multiple); |
850 | + EXPECT_STREQ(CMAKE_SOURCE_DIR "/libertine-data/upstart/application-legacy-bar-2342345.log", legacy_multiple); |
851 | g_free(legacy_multiple); |
852 | } |
853 | |
854 | @@ -529,6 +534,12 @@ |
855 | EXPECT_EQ(nullptr, ubuntu_app_launch_triplet_to_app_id("com.test.no-json", NULL, NULL)); |
856 | EXPECT_EQ(nullptr, ubuntu_app_launch_triplet_to_app_id("com.test.no-object", NULL, NULL)); |
857 | EXPECT_EQ(nullptr, ubuntu_app_launch_triplet_to_app_id("com.test.no-version", NULL, NULL)); |
858 | + |
859 | + /* Libertine tests */ |
860 | + EXPECT_EQ(nullptr, ubuntu_app_launch_triplet_to_app_id("container-name", NULL, NULL)); |
861 | + EXPECT_EQ(nullptr, ubuntu_app_launch_triplet_to_app_id("container-name", "not-exist", NULL)); |
862 | + EXPECT_STREQ("container-name_test_0.0", ubuntu_app_launch_triplet_to_app_id("container-name", "test", NULL)); |
863 | + EXPECT_STREQ("container-name_user-app_0.0", ubuntu_app_launch_triplet_to_app_id("container-name", "user-app", NULL)); |
864 | } |
865 | |
866 | TEST_F(LibUAL, AppIdParse) |
FAILED: Continuous integration, rev:211 /code.launchpad .net/~ted/ ubuntu- app-launch/ libertine- detection/ +merge/ 264789/ +edit-commit- message
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:/
http:// jenkins. qa.ubuntu. com/job/ ubuntu- app-launch- ci/10/ jenkins. qa.ubuntu. com/job/ ubuntu- app-launch- wily-amd64- ci/10 jenkins. qa.ubuntu. com/job/ ubuntu- app-launch- wily-armhf- ci/10 jenkins. qa.ubuntu. com/job/ ubuntu- app-launch- wily-i386- ci/10
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- app-launch- ci/10/rebuild
http://