Merge lp:~ted/ubuntu-app-launch/libertine-detection into lp:ubuntu-app-launch/15.10

Proposed by Ted Gould
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
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

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

FAILED: Continuous integration, rev:211
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/~ted/ubuntu-app-launch/libertine-detection/+merge/264789/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-ci/10/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-wily-amd64-ci/10
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-wily-armhf-ci/10
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-wily-i386-ci/10

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-app-launch-ci/10/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) wrote :

Mostly LGTM, no blockers, a few suggestions/questions inline

review: Approve
Revision history for this message
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/share/applications, which is important for clients like Steam or WINE.

217. By Ted Gould

Update to latest xmir-support

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) :
review: Approve
218. By Ted Gould

Make triplet to appid work for libertine apps

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
219. By Ted Gould

Reshuffle code so that JSON and click stuff is all in one file

220. By Ted Gould

Grab the libertine cache dirs

221. By Ted Gould

Setting data home as well

222. By Ted Gould

Testing the libertine triplet cases

223. By Ted Gould

Thought of another one

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Christopher Townsend (townsend) wrote :

Ok, looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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)

Subscribers

People subscribed via source and target branches