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

Proposed by Ted Gould on 2015-07-15
Status: Merged
Approved by: Christopher Townsend on 2015-08-13
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 on 2015-08-13
PS Jenkins bot (community) continuous-integration Approve on 2015-08-11
Charles Kerr (community) 2015-07-15 Approve on 2015-08-11
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.
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)
Charles Kerr (charlesk) wrote :

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

review: Approve
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 on 2015-08-11

Update to latest xmir-support

Charles Kerr (charlesk) :
review: Approve
218. By Ted Gould on 2015-08-11

Make triplet to appid work for libertine apps

219. By Ted Gould on 2015-08-11

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

220. By Ted Gould on 2015-08-11

Grab the libertine cache dirs

221. By Ted Gould on 2015-08-11

Setting data home as well

222. By Ted Gould on 2015-08-11

Testing the libertine triplet cases

223. By Ted Gould on 2015-08-11

Thought of another one

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