Merge lp:~ted/ubuntu-app-launch/rm-rf-click into lp:ubuntu-app-launch

Proposed by Ted Gould
Status: Merged
Approved by: Ken VanDine
Approved revision: 391
Merged at revision: 304
Proposed branch: lp:~ted/ubuntu-app-launch/rm-rf-click
Merge into: lp:ubuntu-app-launch
Prerequisite: lp:~ted/ubuntu-app-launch/rm-rf-upstart
Diff against target: 7412 lines (+1691/-4059)
62 files modified
CMakeLists.txt (+0/-33)
debian/control (+0/-3)
debian/rules (+1/-4)
desktop-hook.c (+0/-536)
docs/index.rst (+0/-23)
libubuntu-app-launch/CMakeLists.txt (+7/-18)
libubuntu-app-launch/app-info.c (+0/-277)
libubuntu-app-launch/app-store-base.cpp (+6/-15)
libubuntu-app-launch/app-store-click.cpp (+0/-248)
libubuntu-app-launch/app-store-click.h (+0/-60)
libubuntu-app-launch/app-store-snap.cpp (+19/-1)
libubuntu-app-launch/application-impl-base.cpp (+1/-1)
libubuntu-app-launch/application-impl-click.cpp (+0/-189)
libubuntu-app-launch/application-impl-click.h (+0/-82)
libubuntu-app-launch/glib-thread.cpp (+28/-17)
libubuntu-app-launch/glib-thread.h (+8/-6)
libubuntu-app-launch/helper.cpp (+28/-5)
libubuntu-app-launch/jobs-base.cpp (+68/-33)
libubuntu-app-launch/jobs-systemd.cpp (+19/-7)
libubuntu-app-launch/registry-impl.cpp (+8/-133)
libubuntu-app-launch/registry-impl.h (+7/-12)
libubuntu-app-launch/second-exec-core.c (+1/-1)
libubuntu-app-launch/type-tagger.h (+8/-0)
libubuntu-app-launch/ubuntu-app-launch.cpp (+16/-6)
libubuntu-app-launch/utils-shared.c (+1/-1)
libubuntu-app-launch/utils.c (+1/-102)
libubuntu-app-launch/utils.h (+0/-2)
tests/CMakeLists.txt (+5/-18)
tests/application-info-desktop.cpp (+5/-4)
tests/applications/foo.desktop (+1/-1)
tests/click-app-dir/.click/info/chatter.robert-ancell.manifest (+0/-8)
tests/click-app-dir/.click/info/com.test.bad-version.manifest (+0/-8)
tests/click-app-dir/.click/info/com.test.good.manifest (+0/-8)
tests/click-app-dir/.click/info/com.test.mir.manifest (+0/-11)
tests/click-app-dir/.click/info/com.test.multiple.manifest (+0/-20)
tests/click-app-dir/.click/info/com.test.no-app.manifest (+0/-8)
tests/click-app-dir/.click/info/com.test.no-hooks.manifest (+0/-8)
tests/click-app-dir/.click/info/com.test.no-json.manifest (+0/-5)
tests/click-app-dir/.click/info/com.test.no-object.manifest (+0/-6)
tests/click-app-dir/.click/info/com.test.no-version.manifest (+0/-8)
tests/click-app-dir/application.desktop (+0/-6)
tests/click-app-dir/chatter.desktop (+0/-9)
tests/click-app-dir/noxmir.desktop (+0/-9)
tests/click-app-dir/xmir.desktop (+0/-9)
tests/click-db-dir/test.conf.in (+0/-2)
tests/click-desktop-hook-db/test.conf.in (+0/-2)
tests/click-root-dir/com.test.good/1.2.4/.click/info/com.test.good.manifest (+0/-8)
tests/click-root-dir/com.test.good/1.2.5/.click/info/com.test.good.manifest (+0/-8)
tests/desktop-hook-test.sh.in (+0/-129)
tests/helper-handshake-test.cc (+1/-1)
tests/helper-test.cc (+3/-42)
tests/libertine-service.h (+1/-0)
tests/libual-cpp-test.cc (+356/-306)
tests/libual-test.cc (+860/-1495)
tests/list-apps.cpp (+23/-74)
tests/registry-mock.h (+158/-2)
tests/snapd-mock.h (+2/-0)
tests/spew-master.h (+2/-2)
tests/systemd-mock.h (+37/-20)
tests/zg-mock.h (+3/-3)
ubuntu-app-launch-desktop.click-hook.in (+0/-4)
utils/CMakeLists.txt (+7/-0)
To merge this branch: bzr merge lp:~ted/ubuntu-app-launch/rm-rf-click
Reviewer Review Type Date Requested Status
Pete Woods (community) Approve
Ken VanDine Approve
unity-api-1-bot continuous-integration Needs Fixing
Review via email: mp+318040@code.launchpad.net

Commit message

Removing support for Click

Description of the change

Removes the Click support but also fixes the tests from helper changes, removing Upstart and finally removing click. The tests should work at the end of this.

To post a comment you must log in.
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
384. By Ted Gould

Re-enable ABI checking

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
385. By Ted Gould

Drop click docs

386. By Ted Gould

A collection of fixes

387. By Ted Gould

Remove the click appstore

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Continuous integration, rev:387
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/267/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/1829/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1836
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1612/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1612
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1612/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1612
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1612/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1612
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1612/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1612
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1612/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1612/console

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/267/rebuild

review: Needs Fixing (continuous-integration)
388. By Ted Gould

Clean up set_exec tests a bit

389. By Ted Gould

Put a full path in to make sure there's nothing funky going on

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Continuous integration, rev:389
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/275/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/1844/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1851
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1627/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1627
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1627/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1627
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1627/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1627
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1627/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1627/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1627
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1627/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/275/rebuild

review: Needs Fixing (continuous-integration)
390. By Ted Gould

Merge through an updated jobs-helpers branch

391. By Ted Gould

Change to allApplicationJobs_

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Continuous integration, rev:391
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/280/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/1850/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1857
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1633
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1633/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1633/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1633
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1633/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1633
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1633/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1633
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1633/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1633
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1633/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/280/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Ken VanDine (ken-vandine) wrote :

Looks good

review: Approve
Revision history for this message
Pete Woods (pete-woods) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2017-03-21 03:26:39 +0000
3+++ CMakeLists.txt 2017-03-21 03:26:40 +0000
4@@ -76,9 +76,6 @@
5 pkg_check_modules(ZEITGEIST REQUIRED zeitgeist-2.0)
6 include_directories(${ZEITGEIST_INCLUDE_DIRS})
7
8-pkg_check_modules(CLICK REQUIRED click-0.4>=0.4.18)
9-include_directories(${CLICK_INCLUDE_DIRS})
10-
11 pkg_check_modules(DBUS REQUIRED dbus-1)
12 include_directories(${DBUS_INCLUDE_DIRS})
13
14@@ -110,36 +107,6 @@
15 add_definitions( -DXMIR_HELPER="${pkglibexecdir}/xmir-helper" )
16 add_definitions( -DSNAPPY_XMIR="${CMAKE_INSTALL_FULL_BINDIR}/snappy-xmir" )
17
18-####################
19-# Helpers
20-####################
21-
22-add_library(helpers STATIC helpers.c helpers-shared.c)
23-target_link_libraries(helpers ${GIO2_LIBRARIES} ${JSONGLIB_LIBRARIES} ${CLICK_LIBRARIES} ${WHOOPSIE_LIBRARIES})
24-
25-####################
26-# desktop-hook
27-####################
28-
29-add_executable(desktop-hook desktop-hook.c)
30-set_target_properties(desktop-hook PROPERTIES OUTPUT_NAME "desktop-hook")
31-target_link_libraries(desktop-hook helpers ${CLICK_LIBRARIES} ${WHOOPSIE_LIBRARIES})
32-install(TARGETS desktop-hook RUNTIME DESTINATION "${pkglibexecdir}")
33-
34-####################
35-# oom-adjust-setuid-helper
36-####################
37-
38-add_executable(oom-adjust-setuid-helper oom-adjust-setuid-helper.c)
39-set_target_properties(oom-adjust-setuid-helper PROPERTIES OUTPUT_NAME "oom-adjust-setuid-helper")
40-install(TARGETS oom-adjust-setuid-helper RUNTIME DESTINATION "${pkglibexecdir}")
41-
42-####################
43-# ubuntu-app-launch-desktop.click-hook
44-####################
45-
46-configure_file("ubuntu-app-launch-desktop.click-hook.in" "${CMAKE_CURRENT_SOURCE_DIR}/debian/ubuntu-app-launch-desktop.click-hook" @ONLY)
47-
48 add_subdirectory(libubuntu-app-launch)
49 add_subdirectory(tools)
50 add_subdirectory(ubuntu-app-test)
51
52=== modified file 'debian/control'
53--- debian/control 2017-03-21 03:26:39 +0000
54+++ debian/control 2017-03-21 03:26:40 +0000
55@@ -3,7 +3,6 @@
56 Priority: optional
57 Maintainer: Ted Gould <ted@ubuntu.com>
58 Build-Depends: abi-compliance-checker,
59- click-dev (>= 0.2.2),
60 cmake,
61 cmake-extras (>= 0.10),
62 dbus-x11,
63@@ -11,7 +10,6 @@
64 debhelper (>= 9),
65 googletest | google-mock,
66 libcgmanager-dev,
67- libclick-0.4-dev,
68 libcurl4-dev | libcurl4-gnutls-dev,
69 libdbus-1-dev,
70 libdbustest1-dev (>= 14.04.0),
71@@ -42,7 +40,6 @@
72 Architecture: any
73 Depends: ${shlibs:Depends},
74 ${misc:Depends},
75- click-apparmor,
76 dbus-user-session,
77 xmir [amd64 armhf i386],
78 zeitgeist-core,
79
80=== modified file 'debian/rules'
81--- debian/rules 2017-02-15 15:09:13 +0000
82+++ debian/rules 2017-03-21 03:26:40 +0000
83@@ -12,10 +12,7 @@
84 export DPKG_GENSYMBOLS_CHECK_LEVEL=4
85
86 %:
87- dh $@ --with click,gir --fail-missing
88-
89-override_dh_click:
90- dh_click --name ubuntu-app-launch-desktop
91+ dh $@ --with gir --fail-missing
92
93 override_dh_installdeb:
94 sed -e"s/#MULTIARCH#/$(DEB_HOST_MULTIARCH)/g" \
95
96=== removed file 'desktop-hook.c'
97--- desktop-hook.c 2016-04-06 16:19:02 +0000
98+++ desktop-hook.c 1970-01-01 00:00:00 +0000
99@@ -1,536 +0,0 @@
100-/*
101- * Copyright 2013 Canonical Ltd.
102- *
103- * This program is free software: you can redistribute it and/or modify it
104- * under the terms of the GNU General Public License version 3, as published
105- * by the Free Software Foundation.
106- *
107- * This program is distributed in the hope that it will be useful, but
108- * WITHOUT ANY WARRANTY; without even the implied warranties of
109- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
110- * PURPOSE. See the GNU General Public License for more details.
111- *
112- * You should have received a copy of the GNU General Public License along
113- * with this program. If not, see <http://www.gnu.org/licenses/>.
114- *
115- * Authors:
116- * Ted Gould <ted.gould@canonical.com>
117- */
118-
119-/*
120-
121-INTRODUCTION:
122-
123-This is a hook for Click packages. You can find information on Click package hooks in
124-the click documentation:
125-
126-https://click.readthedocs.org/en/latest/
127-
128-Probably the biggest thing to understand for how this code works is that you need to
129-understand that this hook is run after one, or many packages are installed. A set of
130-symbolic links are made to the desktop files per-application (not per-package) in the
131-directory specified in ubuntu-app-launcher-desktop.click-hook.in. Those desktop files
132-give us the App ID of the packages that are installed and have applications needing
133-desktop files in them. We then operate on each of them ensuring that they are synchronized
134-with the desktop files in ~/.local/share/applications/.
135-
136-The desktop files that we're creating there ARE NOT used for execution by the
137-ubuntu-app-launch Upstart jobs. They are there so that Unity can know which applications
138-are installed for this user and they provide an Exec line to allow compatibility with
139-desktop environments that are not using ubuntu-app-launch for launching applications.
140-You should not modify them and expect any executing under Unity to change.
141-
142-*/
143-
144-#include <gio/gio.h>
145-#include <glib/gstdio.h>
146-#include <click.h>
147-#include <string.h>
148-#include <errno.h>
149-#include <libwhoopsie/recoverable-problem.h>
150-
151-#include "helpers.h"
152-
153-typedef struct _app_state_t app_state_t;
154-struct _app_state_t {
155- gchar * app_id;
156- gboolean has_click;
157- gboolean has_desktop;
158- guint64 click_modified;
159- guint64 desktop_modified;
160-};
161-
162-/* Desktop Group */
163-#define DESKTOP_GROUP "Desktop Entry"
164-/* Desktop Keys */
165-#define APP_ID_KEY "X-Ubuntu-Application-ID"
166-#define PATH_KEY "Path"
167-#define EXEC_KEY "Exec"
168-#define ICON_KEY "Icon"
169-#define SYMBOLIC_ICON_KEY "X-Ubuntu-SymbolicIcon"
170-#define SOURCE_FILE_KEY "X-Ubuntu-UAL-Source-Desktop"
171-/* Other */
172-#define OLD_KEY_PREFIX "X-Ubuntu-Old-"
173-
174-/* Find an entry in the app array */
175-app_state_t *
176-find_app_entry (const gchar * name, GArray * app_array)
177-{
178- int i;
179- for (i = 0; i < app_array->len; i++) {
180- app_state_t * state = &g_array_index(app_array, app_state_t, i);
181-
182- if (g_strcmp0(state->app_id, name) == 0) {
183- return state;
184- }
185- }
186-
187- app_state_t newstate;
188- newstate.has_click = FALSE;
189- newstate.has_desktop = FALSE;
190- newstate.click_modified = 0;
191- newstate.desktop_modified = 0;
192- newstate.app_id = g_strdup(name);
193-
194- g_array_append_val(app_array, newstate);
195-
196- /* Note: The pointer needs to be the entry in the array, not the
197- one that we have on the stack. Criticaly important. */
198- app_state_t * statepntr = &g_array_index(app_array, app_state_t, app_array->len - 1);
199- return statepntr;
200-}
201-
202-/* Looks up the file creation time, which seems harder with GLib
203- than it should be */
204-guint64
205-modified_time (const gchar * dir, const gchar * filename)
206-{
207- gchar * path = g_build_filename(dir, filename, NULL);
208- GFile * file = g_file_new_for_path(path);
209- GFileInfo * info = g_file_query_info(file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL);
210-
211- guint64 time = g_file_info_get_attribute_uint64(info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
212-
213- g_object_unref(info);
214- g_object_unref(file);
215- g_free(path);
216-
217- return time;
218-}
219-
220-/* Look at an click package entry */
221-void
222-add_click_package (const gchar * dir, const gchar * name, GArray * app_array)
223-{
224- if (!g_str_has_suffix(name, ".desktop")) {
225- return;
226- }
227-
228- gchar * appid = g_strdup(name);
229- g_strstr_len(appid, -1, ".desktop")[0] = '\0';
230-
231- app_state_t * state = find_app_entry(appid, app_array);
232- state->has_click = TRUE;
233- state->click_modified = modified_time(dir, name);
234-
235- g_free(appid);
236-
237- return;
238-}
239-
240-/* Look at the desktop file and ensure that it was built by us, and if it
241- was that its source still exists */
242-gboolean
243-desktop_source_exists (const gchar * dir, const gchar * name)
244-{
245- gchar * desktopfile = g_build_filename(dir, name, NULL);
246-
247- GKeyFile * keyfile = g_key_file_new();
248- g_key_file_load_from_file(keyfile,
249- desktopfile,
250- G_KEY_FILE_NONE,
251- NULL); /* No error */
252-
253- if (!g_key_file_has_key(keyfile, DESKTOP_GROUP, SOURCE_FILE_KEY, NULL)) {
254- gboolean hasappid = g_key_file_has_key(keyfile, DESKTOP_GROUP, APP_ID_KEY, NULL);
255- g_free(desktopfile);
256- g_key_file_free(keyfile);
257- return hasappid;
258- }
259-
260- /* At this point we know the key exists, so if we can't find the source
261- file we want to delete the file as well. We need to replace it. */
262- gchar * originalfile = g_key_file_get_string(keyfile, DESKTOP_GROUP, SOURCE_FILE_KEY, NULL);
263- g_key_file_free(keyfile);
264- gboolean found = TRUE;
265-
266- if (!g_file_test(originalfile, G_FILE_TEST_EXISTS)) {
267- g_remove(desktopfile);
268- found = FALSE;
269- }
270-
271- g_free(originalfile);
272- g_free(desktopfile);
273-
274- return found;
275-}
276-
277-/* Look at an desktop file entry */
278-void
279-add_desktop_file (const gchar * dir, const gchar * name, GArray * app_array)
280-{
281- if (!g_str_has_suffix(name, ".desktop")) {
282- return;
283- }
284-
285- if (!desktop_source_exists(dir, name)) {
286- return;
287- }
288-
289- gchar * appid = g_strdup(name);
290- g_strstr_len(appid, -1, ".desktop")[0] = '\0';
291-
292- /* We only want valid APP IDs as desktop files */
293- if (!app_id_to_triplet(appid, NULL, NULL, NULL)) {
294- g_free(appid);
295- return;
296- }
297-
298- app_state_t * state = find_app_entry(appid, app_array);
299- state->has_desktop = TRUE;
300- state->desktop_modified = modified_time(dir, name);
301-
302- g_free(appid);
303- return;
304-}
305-
306-/* Open a directory and look at all the entries */
307-void
308-dir_for_each (const gchar * dirname, void(*func)(const gchar * dir, const gchar * name, GArray * app_array), GArray * app_array)
309-{
310- GError * error = NULL;
311- GDir * directory = g_dir_open(dirname, 0, &error);
312-
313- if (error != NULL) {
314- g_warning("Unable to read directory '%s': %s", dirname, error->message);
315- g_error_free(error);
316- return;
317- }
318-
319- const gchar * filename = NULL;
320- while ((filename = g_dir_read_name(directory)) != NULL) {
321- func(dirname, filename, app_array);
322- }
323-
324- g_dir_close(directory);
325- return;
326-}
327-
328-/* Code to report an error, so we can start tracking how important this is */
329-static void
330-report_recoverable_error (const gchar * app_id, const gchar * iconfield, const gchar * originalicon, const gchar * iconpath)
331-{
332- const char * properties[9] = {
333- "IconValue", NULL,
334- "AppID", NULL,
335- "IconPath", NULL,
336- "IconField", NULL,
337- NULL
338- };
339-
340- properties[1] = originalicon;
341- properties[3] = app_id;
342- properties[5] = iconpath;
343- properties[7] = iconfield;
344-
345- whoopsie_report_recoverable_problem("icon-path-unhandled", 0, TRUE, properties);
346-
347- return;
348-}
349-
350-/* Function to take the source Desktop file and build a new
351- one with similar, but not the same data in it */
352-static void
353-copy_desktop_file (const gchar * from, const gchar * to, const gchar * appdir, const gchar * app_id)
354-{
355- GError * error = NULL;
356- GKeyFile * keyfile = g_key_file_new();
357- g_key_file_load_from_file(keyfile,
358- from,
359- G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS,
360- &error);
361-
362- if (error != NULL) {
363- g_warning("Unable to read the desktop file '%s' in the application directory: %s", from, error->message);
364- g_error_free(error);
365- g_key_file_unref(keyfile);
366- return;
367- }
368-
369- /* Path Hanlding */
370- if (g_key_file_has_key(keyfile, DESKTOP_GROUP, PATH_KEY, NULL)) {
371- gchar * oldpath = g_key_file_get_string(keyfile, DESKTOP_GROUP, PATH_KEY, NULL);
372- g_debug("Desktop file '%s' has a Path set to '%s'. Setting as " OLD_KEY_PREFIX PATH_KEY ".", from, oldpath);
373-
374- g_key_file_set_string(keyfile, DESKTOP_GROUP, OLD_KEY_PREFIX PATH_KEY, oldpath);
375-
376- g_free(oldpath);
377- }
378-
379- g_key_file_set_string(keyfile, DESKTOP_GROUP, PATH_KEY, appdir);
380-
381- /* Icon Handling */
382- if (g_key_file_has_key(keyfile, DESKTOP_GROUP, ICON_KEY, NULL)) {
383- gchar * originalicon = g_key_file_get_string(keyfile, DESKTOP_GROUP, ICON_KEY, NULL);
384- gchar * iconpath = g_build_filename(appdir, originalicon, NULL);
385-
386- /* If the icon in the path exists, let's use that */
387- if (g_file_test(iconpath, G_FILE_TEST_EXISTS)) {
388- g_key_file_set_string(keyfile, DESKTOP_GROUP, ICON_KEY, iconpath);
389- /* Save the old value, because, debugging */
390- g_key_file_set_string(keyfile, DESKTOP_GROUP, OLD_KEY_PREFIX ICON_KEY, originalicon);
391- } else {
392- /* So here we are, realizing all is lost. Let's file a bug. */
393- /* The goal here is to realize how often this case is, so we know how to prioritize fixing it */
394-
395- report_recoverable_error(app_id, ICON_KEY, originalicon, iconpath);
396- }
397-
398- g_free(iconpath);
399- g_free(originalicon);
400- }
401-
402- /* SymbolicIcon Handling */
403- if (g_key_file_has_key(keyfile, DESKTOP_GROUP, SYMBOLIC_ICON_KEY, NULL)) {
404- gchar * originalicon = g_key_file_get_string(keyfile, DESKTOP_GROUP, SYMBOLIC_ICON_KEY, NULL);
405- gchar * iconpath = g_build_filename(appdir, originalicon, NULL);
406-
407- /* If the icon in the path exists, let's use that */
408- if (g_file_test(iconpath, G_FILE_TEST_EXISTS)) {
409- g_key_file_set_string(keyfile, DESKTOP_GROUP, SYMBOLIC_ICON_KEY, iconpath);
410- /* Save the old value, because, debugging */
411- g_key_file_set_string(keyfile, DESKTOP_GROUP, OLD_KEY_PREFIX SYMBOLIC_ICON_KEY, originalicon);
412- } else {
413- /* So here we are, realizing all is lost. Let's file a bug. */
414- /* The goal here is to realize how often this case is, so we know how to prioritize fixing it */
415-
416- report_recoverable_error(app_id, SYMBOLIC_ICON_KEY, originalicon, iconpath);
417- }
418-
419- g_free(iconpath);
420- g_free(originalicon);
421- }
422-
423- /* Exec Handling */
424- gchar * oldexec = desktop_to_exec(keyfile, from);
425- if (oldexec == NULL) {
426- g_key_file_unref(keyfile);
427- return;
428- }
429-
430- gchar * newexec = g_strdup_printf("aa-exec-click -p %s -- %s", app_id, oldexec);
431- g_key_file_set_string(keyfile, DESKTOP_GROUP, EXEC_KEY, newexec);
432- g_free(newexec);
433- g_free(oldexec);
434-
435- /* Adding an Application ID */
436- g_key_file_set_string(keyfile, DESKTOP_GROUP, APP_ID_KEY, app_id);
437-
438- /* Adding the source file path */
439- g_key_file_set_string(keyfile, DESKTOP_GROUP, SOURCE_FILE_KEY, from);
440-
441- /* Output */
442- gsize datalen = 0;
443- gchar * data = g_key_file_to_data(keyfile, &datalen, &error);
444- g_key_file_unref(keyfile);
445-
446- if (error != NULL) {
447- g_warning("Unable serialize keyfile built from '%s': %s", from, error->message);
448- g_error_free(error);
449- return;
450- }
451-
452- g_file_set_contents(to, data, datalen, &error);
453- g_free(data);
454-
455- if (error != NULL) {
456- g_warning("Unable to write out desktop file to '%s': %s", to, error->message);
457- g_error_free(error);
458- return;
459- }
460-
461- return;
462-}
463-
464-/* Build a desktop file in the user's home directory */
465-static void
466-build_desktop_file (app_state_t * state, const gchar * symlinkdir, const gchar * desktopdir)
467-{
468- GError * error = NULL;
469- gchar * package = NULL;
470- /* 'Parse' the App ID */
471- if (!app_id_to_triplet(state->app_id, &package, NULL, NULL)) {
472- return;
473- }
474-
475- /* Read in the database */
476- ClickDB * db = click_db_new();
477- click_db_read(db, g_getenv("TEST_CLICK_DB"), &error);
478- if (error != NULL) {
479- g_warning("Unable to read Click database: %s", error->message);
480- g_error_free(error);
481- g_free(package);
482- g_object_unref(db);
483- return;
484- }
485-
486- /* Check click to find out where the files are */
487- ClickUser * user = click_user_new_for_user(db, g_getenv("TEST_CLICK_USER"), &error);
488- g_object_unref(db);
489- if (error != NULL) {
490- g_warning("Unable to read Click database: %s", error->message);
491- g_error_free(error);
492- g_free(package);
493- return;
494- }
495-
496- gchar * pkgdir = click_user_get_path(user, package, &error);
497- if (error != NULL) {
498- g_warning("Unable to get the Click package directory for %s: %s", package, error->message);
499- g_error_free(error);
500- g_free(package);
501- return;
502- }
503- g_object_unref(user);
504- g_free(package);
505-
506- if (!g_file_test(pkgdir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
507- g_warning("Directory returned by click '%s' couldn't be found", pkgdir);
508- g_free(pkgdir);
509- return;
510- }
511-
512- gchar * indesktop = manifest_to_desktop(pkgdir, state->app_id);
513- if (indesktop == NULL) {
514- g_free(pkgdir);
515- return;
516- }
517-
518- /* Determine the desktop file name */
519- gchar * desktopfile = g_strdup_printf("%s.desktop", state->app_id);
520- gchar * desktoppath = g_build_filename(desktopdir, desktopfile, NULL);
521- g_free(desktopfile);
522-
523- copy_desktop_file(indesktop, desktoppath, pkgdir, state->app_id);
524-
525- g_free(desktoppath);
526- g_free(indesktop);
527- g_free(pkgdir);
528-
529- return;
530-}
531-
532-/* Remove the desktop file from the user's home directory */
533-static gboolean
534-remove_desktop_file (app_state_t * state, const gchar * desktopdir)
535-{
536- gchar * desktopfile = g_strdup_printf("%s.desktop", state->app_id);
537- gchar * desktoppath = g_build_filename(desktopdir, desktopfile, NULL);
538- g_free(desktopfile);
539-
540- GKeyFile * keyfile = g_key_file_new();
541- g_key_file_load_from_file(keyfile,
542- desktoppath,
543- G_KEY_FILE_NONE,
544- NULL);
545-
546- if (!g_key_file_has_key(keyfile, DESKTOP_GROUP, APP_ID_KEY, NULL)) {
547- g_debug("Desktop file '%s' is not one created by us.", desktoppath);
548- g_key_file_unref(keyfile);
549- g_free(desktoppath);
550- return FALSE;
551- }
552- g_key_file_unref(keyfile);
553-
554- if (g_unlink(desktoppath) != 0) {
555- g_warning("Unable to delete desktop file: %s", desktoppath);
556- }
557-
558- g_free(desktoppath);
559-
560- return TRUE;
561-}
562-
563-/* The main function */
564-int
565-main (int argc, char * argv[])
566-{
567- if (argc != 1) {
568- g_error("Shouldn't have arguments");
569- return 1;
570- }
571-
572- GArray * apparray = g_array_new(FALSE, FALSE, sizeof(app_state_t));
573-
574- /* Find all the symlinks of desktop files */
575- gchar * symlinkdir = g_build_filename(g_get_user_cache_dir(), "ubuntu-app-launch", "desktop", NULL);
576- if (!g_file_test(symlinkdir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
577- g_debug("No installed click packages");
578- } else {
579- dir_for_each(symlinkdir, add_click_package, apparray);
580- }
581-
582- /* Find all the click desktop files */
583- gchar * desktopdir = g_build_filename(g_get_user_data_dir(), "applications", NULL);
584- gboolean desktopdirexists = FALSE;
585- if (!g_file_test(desktopdir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
586- g_debug("No applications defined");
587- } else {
588- dir_for_each(desktopdir, add_desktop_file, apparray);
589- desktopdirexists = TRUE;
590- }
591-
592- /* Process the merge */
593- int i;
594- for (i = 0; i < apparray->len; i++) {
595- app_state_t * state = &g_array_index(apparray, app_state_t, i);
596- g_debug("Processing App ID: %s", state->app_id);
597-
598- if (state->has_click && state->has_desktop) {
599- if (state->click_modified > state->desktop_modified) {
600- g_debug("\tClick updated more recently");
601- g_debug("\tRemoving desktop file");
602- if (remove_desktop_file(state, desktopdir)) {
603- g_debug("\tBuilding desktop file");
604- build_desktop_file(state, symlinkdir, desktopdir);
605- }
606- } else {
607- g_debug("\tAlready synchronized");
608- }
609- } else if (state->has_click) {
610- if (!desktopdirexists) {
611- if (g_mkdir_with_parents(desktopdir, 0755) == 0) {
612- g_debug("\tCreated applications directory");
613- desktopdirexists = TRUE;
614- } else {
615- g_warning("\tUnable to create applications directory");
616- }
617- }
618- if (desktopdirexists) {
619- g_debug("\tBuilding desktop file");
620- build_desktop_file(state, symlinkdir, desktopdir);
621- }
622- } else if (state->has_desktop) {
623- g_debug("\tRemoving desktop file");
624- remove_desktop_file(state, desktopdir);
625- }
626-
627- g_free(state->app_id);
628- }
629-
630- g_array_free(apparray, TRUE);
631- g_free(desktopdir);
632- g_free(symlinkdir);
633-
634- return 0;
635-}
636
637=== modified file 'docs/index.rst'
638--- docs/index.rst 2017-03-21 03:26:39 +0000
639+++ docs/index.rst 2017-03-21 03:26:40 +0000
640@@ -37,9 +37,6 @@
641 UBUNTU_APP_LAUNCH_LIBERTINE_LAUNCH
642 Path to the libertine launch utility for setting up libertine containers and XMir based legacy apps.
643
644-UBUNTU_APP_LAUNCH_LINK_FARM
645- Path to the link farm that is created by Click of all the installed Click applications.
646-
647 UBUNTU_APP_LAUNCH_OOM_HELPER
648 Path to the setuid helper that configures OOM values on application processes that we otherwise couldn't, mostly this is for Oxide.
649
650@@ -119,16 +116,6 @@
651 :private-members:
652 :undoc-members:
653
654-Application Implementation Click
655---------------------------------
656-
657-.. doxygenclass:: ubuntu::app_launch::app_impls::Click
658- :project: libubuntu-app-launch
659- :members:
660- :protected-members:
661- :private-members:
662- :undoc-members:
663-
664 Application Implementation Legacy
665 ---------------------------------
666
667@@ -199,16 +186,6 @@
668 :private-members:
669 :undoc-members:
670
671-Application Storage Click
672--------------------------
673-
674-.. doxygenclass:: ubuntu::app_launch::app_store::Click
675- :project: libubuntu-app-launch
676- :members:
677- :protected-members:
678- :private-members:
679- :undoc-members:
680-
681 Application Storage Legacy
682 --------------------------
683
684
685=== modified file 'libubuntu-app-launch/CMakeLists.txt'
686--- libubuntu-app-launch/CMakeLists.txt 2017-03-21 03:26:39 +0000
687+++ libubuntu-app-launch/CMakeLists.txt 2017-03-21 03:26:40 +0000
688@@ -39,8 +39,6 @@
689 application.cpp
690 app-store-base.h
691 app-store-base.cpp
692-app-store-click.h
693-app-store-click.cpp
694 app-store-legacy.h
695 app-store-legacy.cpp
696 app-store-libertine.h
697@@ -54,12 +52,12 @@
698 registry-impl.cpp
699 application-impl-base.h
700 application-impl-base.cpp
701-application-impl-click.h
702-application-impl-click.cpp
703 application-impl-legacy.h
704 application-impl-legacy.cpp
705 application-impl-libertine.h
706 application-impl-libertine.cpp
707+application-impl-snap.h
708+application-impl-snap.cpp
709 application-info-desktop.h
710 application-info-desktop.cpp
711 application-icon-finder.h
712@@ -74,24 +72,17 @@
713 jobs-base.cpp
714 jobs-systemd.h
715 jobs-systemd.cpp
716+snapd-info.h
717+snapd-info.cpp
718 )
719
720 set(LAUNCHER_SOURCES
721 ubuntu-app-launch.cpp
722 second-exec-core.c
723 ubuntu-app-launch-trace.c
724-app-info.c
725-)
726-
727-if(CURL_FOUND)
728-add_definitions ( -DENABLE_SNAPPY=1 )
729-list(APPEND LAUNCHER_CPP_SOURCES
730-application-impl-snap.h
731-application-impl-snap.cpp
732-snapd-info.h
733-snapd-info.cpp
734-)
735-endif()
736+utils.c
737+utils-shared.c
738+)
739
740 add_custom_target(format
741 COMMAND clang-format -i -style=file ${LAUNCHER_CPP_HEADERS} ${LAUNCHER_CPP_SOURCES}
742@@ -117,7 +108,6 @@
743 ${LIBERTINE_LIBRARIES}
744 ${CURL_LIBRARIES}
745 -lpthread
746- helpers
747 -Wl,--no-undefined
748 )
749
750@@ -144,7 +134,6 @@
751 ${LIBERTINE_LIBRARIES}
752 ${CURL_LIBRARIES}
753 -lpthread
754- helpers
755 -Wl,--no-undefined
756 )
757
758
759=== removed file 'libubuntu-app-launch/app-info.c'
760--- libubuntu-app-launch/app-info.c 2016-08-24 20:29:25 +0000
761+++ libubuntu-app-launch/app-info.c 1970-01-01 00:00:00 +0000
762@@ -1,277 +0,0 @@
763-/*
764- * Copyright © 2015 Canonical Ltd.
765- *
766- * This program is free software: you can redistribute it and/or modify it
767- * under the terms of the GNU General Public License version 3, as published
768- * by the Free Software Foundation.
769- *
770- * This program is distributed in the hope that it will be useful, but
771- * WITHOUT ANY WARRANTY; without even the implied warranties of
772- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
773- * PURPOSE. See the GNU General Public License for more details.
774- *
775- * You should have received a copy of the GNU General Public License along
776- * with this program. If not, see <http://www.gnu.org/licenses/>.
777- *
778- * Authors:
779- * Ted Gould <ted.gould@canonical.com>
780- */
781-
782-#include <json-glib/json-glib.h>
783-#include <click.h>
784-
785-#include "ubuntu-app-launch.h"
786-
787-/* Prototypes */
788-static gboolean app_info_libertine (const gchar * appid, gchar ** appdir, gchar ** appdesktop);
789-
790-/* Try and get a manifest and do a couple sanity checks on it */
791-static JsonObject *
792-get_manifest (const gchar * pkg, gchar ** pkgpath)
793-{
794- /* Get the directory from click */
795- GError * error = NULL;
796-
797- ClickDB * db = click_db_new();
798- /* If TEST_CLICK_DB is unset, this reads the system database. */
799- click_db_read(db, g_getenv("TEST_CLICK_DB"), &error);
800- if (error != NULL) {
801- g_warning("Unable to read Click database: %s", error->message);
802- g_error_free(error);
803- g_object_unref(db);
804- return NULL;
805- }
806- /* If TEST_CLICK_USER is unset, this uses the current user name. */
807- ClickUser * user = click_user_new_for_user(db, g_getenv("TEST_CLICK_USER"), &error);
808- if (error != NULL) {
809- g_warning("Unable to read Click database: %s", error->message);
810- g_error_free(error);
811- g_object_unref(db);
812- return NULL;
813- }
814- g_object_unref(db);
815- JsonObject * manifest = click_user_get_manifest(user, pkg, &error);
816- if (error != NULL) {
817- g_warning("Unable to get manifest for '%s' package: %s", pkg, error->message);
818- g_error_free(error);
819- g_object_unref(user);
820- return NULL;
821- }
822-
823- if (pkgpath != NULL) {
824- *pkgpath = click_user_get_path(user, pkg, &error);
825- if (error != NULL) {
826- g_warning("Unable to get the Click package directory for %s: %s", pkg, error->message);
827- g_error_free(error);
828- g_object_unref(user);
829- return NULL;
830- }
831- }
832- g_object_unref(user);
833-
834- if (!json_object_has_member(manifest, "version")) {
835- g_warning("Manifest file for package '%s' does not have a version", pkg);
836- json_object_unref(manifest);
837- return NULL;
838- }
839-
840- return manifest;
841-}
842-
843-/* Look to see if the app id results in a desktop file, if so, fill in the params */
844-static gboolean
845-evaluate_dir (const gchar * dir, const gchar * desktop, gchar ** appdir, gchar ** appdesktop)
846-{
847- char * fulldir = g_build_filename(dir, "applications", desktop, NULL);
848- gboolean found = FALSE;
849-
850- if (g_file_test(fulldir, G_FILE_TEST_EXISTS)) {
851- if (appdir != NULL) {
852- *appdir = g_strdup(dir);
853- }
854-
855- if (appdesktop != NULL) {
856- *appdesktop = g_strdup_printf("applications/%s", desktop);
857- }
858-
859- found = TRUE;
860- }
861-
862- g_free(fulldir);
863- return found;
864-}
865-
866-/* Handle the legacy case where we look through the data directories */
867-static gboolean
868-app_info_legacy (const gchar * appid, gchar ** appdir, gchar ** appdesktop)
869-{
870- gchar * desktop = g_strdup_printf("%s.desktop", appid);
871-
872- /* Special case the user's dir */
873- if (evaluate_dir(g_get_user_data_dir(), desktop, appdir, appdesktop)) {
874- g_free(desktop);
875- return TRUE;
876- }
877-
878- const char * const * data_dirs = g_get_system_data_dirs();
879- int i;
880- for (i = 0; data_dirs[i] != NULL; i++) {
881- if (evaluate_dir(data_dirs[i], desktop, appdir, appdesktop)) {
882- g_free(desktop);
883- return TRUE;
884- }
885- }
886-
887- return FALSE;
888-}
889-
890-/* Handle the libertine case where we look in the container */
891-static gboolean
892-app_info_libertine (const gchar * appid, gchar ** appdir, gchar ** appdesktop)
893-{
894- char * container = NULL;
895- char * app = NULL;
896-
897- if (!ubuntu_app_launch_app_id_parse(appid, &container, &app, NULL)) {
898- return FALSE;
899- }
900-
901- gchar * desktopname = g_strdup_printf("%s.desktop", app);
902-
903- gchar * desktopdir = g_build_filename(g_get_user_cache_dir(), "libertine-container", container, "rootfs", "usr", "share", NULL);
904- gchar * desktopfile = g_build_filename(desktopdir, "applications", desktopname, NULL);
905-
906- if (!g_file_test(desktopfile, G_FILE_TEST_EXISTS)) {
907- g_free(desktopdir);
908- g_free(desktopfile);
909-
910- desktopdir = g_build_filename(g_get_user_data_dir(), "libertine-container", "user-data", container, ".local", "share", NULL);
911- desktopfile = g_build_filename(desktopdir, "applications", desktopname, NULL);
912-
913- if (!g_file_test(desktopfile, G_FILE_TEST_EXISTS)) {
914- g_free(desktopdir);
915- g_free(desktopfile);
916-
917- g_free(desktopname);
918- g_free(container);
919- g_free(app);
920-
921- return FALSE;
922- }
923- }
924-
925- if (appdir != NULL) {
926- *appdir = desktopdir;
927- } else {
928- g_free(desktopdir);
929- }
930-
931- if (appdesktop != NULL) {
932- *appdesktop = g_build_filename("applications", desktopname, NULL);
933- }
934-
935- g_free(desktopfile);
936- g_free(desktopname);
937- g_free(container);
938- g_free(app);
939-
940- return TRUE;
941-}
942-
943-/* Get the information on where the desktop file is from libclick */
944-static gboolean
945-app_info_click (const gchar * appid, gchar ** appdir, gchar ** appdesktop)
946-{
947- gchar * package = NULL;
948- gchar * application = NULL;
949-
950- if (!ubuntu_app_launch_app_id_parse(appid, &package, &application, NULL)) {
951- return FALSE;
952- }
953-
954- JsonObject * manifest = get_manifest(package, appdir);
955- if (manifest == NULL) {
956- g_free(package);
957- g_free(application);
958- return FALSE;
959- }
960-
961- g_free(package);
962-
963- if (appdesktop != NULL) {
964- JsonObject * hooks = json_object_get_object_member(manifest, "hooks");
965- if (hooks == NULL) {
966- json_object_unref(manifest);
967- g_free(application);
968- return FALSE;
969- }
970-
971- JsonObject * appobj = json_object_get_object_member(hooks, application);
972- g_free(application);
973-
974- if (appobj == NULL) {
975- json_object_unref(manifest);
976- return FALSE;
977- }
978-
979- const gchar * desktop = json_object_get_string_member(appobj, "desktop");
980- if (desktop == NULL) {
981- json_object_unref(manifest);
982- return FALSE;
983- }
984-
985- *appdesktop = g_strdup(desktop);
986- } else {
987- g_free(application);
988- }
989-
990- json_object_unref(manifest);
991-
992- return TRUE;
993-}
994-
995-/* Determine whether it's a click package by looking for the symlink
996- that is created by the desktop hook */
997-static gboolean
998-is_click (const gchar * appid)
999-{
1000- gchar * appiddesktop = g_strdup_printf("%s.desktop", appid);
1001- gchar * click_link = NULL;
1002- const gchar * link_farm_dir = g_getenv("UBUNTU_APP_LAUNCH_LINK_FARM");
1003- if (G_LIKELY(link_farm_dir == NULL)) {
1004- click_link = g_build_filename(g_get_user_cache_dir(), "ubuntu-app-launch", "desktop", appiddesktop, NULL);
1005- } else {
1006- click_link = g_build_filename(link_farm_dir, appiddesktop, NULL);
1007- }
1008- g_free(appiddesktop);
1009- gboolean click = g_file_test(click_link, G_FILE_TEST_EXISTS);
1010- g_free(click_link);
1011-
1012- return click;
1013-}
1014-
1015-/* Determine whether an AppId is realated to a Libertine container by
1016- checking the container and program name. */
1017-static gboolean
1018-is_libertine (const gchar * appid)
1019-{
1020- if (app_info_libertine(appid, NULL, NULL)) {
1021- g_debug("Libertine application detected: %s", appid);
1022- return TRUE;
1023- } else {
1024- return FALSE;
1025- }
1026-}
1027-
1028-gboolean
1029-ubuntu_app_launch_application_info (const gchar * appid, gchar ** appdir, gchar ** appdesktop)
1030-{
1031- if (is_click(appid)) {
1032- return app_info_click(appid, appdir, appdesktop);
1033- } else if (is_libertine(appid)) {
1034- return app_info_libertine(appid, appdir, appdesktop);
1035- } else {
1036- return app_info_legacy(appid, appdir, appdesktop);
1037- }
1038-}
1039-
1040
1041=== modified file 'libubuntu-app-launch/app-store-base.cpp'
1042--- libubuntu-app-launch/app-store-base.cpp 2017-03-21 03:26:39 +0000
1043+++ libubuntu-app-launch/app-store-base.cpp 2017-03-21 03:26:40 +0000
1044@@ -18,13 +18,9 @@
1045 */
1046
1047 #include "app-store-base.h"
1048-#include "app-store-click.h"
1049 #include "app-store-legacy.h"
1050 #include "app-store-libertine.h"
1051-
1052-#if ENABLE_SNAPPY
1053 #include "app-store-snap.h"
1054-#endif
1055
1056 namespace ubuntu
1057 {
1058@@ -44,17 +40,12 @@
1059
1060 std::list<std::shared_ptr<Base>> Base::allAppStores()
1061 {
1062- return
1063- {
1064- std::make_shared<Click>() /* Click */
1065- ,
1066- std::make_shared<Legacy>() /* Legacy */
1067- ,
1068- std::make_shared<Libertine>() /* Libertine */
1069-#if ENABLE_SNAPPY
1070- ,
1071- std::make_shared<Snap>() /* Snappy */
1072-#endif
1073+ return {
1074+ std::make_shared<Legacy>() /* Legacy */
1075+ ,
1076+ std::make_shared<Libertine>() /* Libertine */
1077+ ,
1078+ std::make_shared<Snap>() /* Snappy */
1079 };
1080 }
1081
1082
1083=== removed file 'libubuntu-app-launch/app-store-click.cpp'
1084--- libubuntu-app-launch/app-store-click.cpp 2017-03-21 03:26:39 +0000
1085+++ libubuntu-app-launch/app-store-click.cpp 1970-01-01 00:00:00 +0000
1086@@ -1,248 +0,0 @@
1087-/*
1088- * Copyright © 2017 Canonical Ltd.
1089- *
1090- * This program is free software: you can redistribute it and/or modify it
1091- * under the terms of the GNU General Public License version 3, as published
1092- * by the Free Software Foundation.
1093- *
1094- * This program is distributed in the hope that it will be useful, but
1095- * WITHOUT ANY WARRANTY; without even the implied warranties of
1096- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1097- * PURPOSE. See the GNU General Public License for more details.
1098- *
1099- * You should have received a copy of the GNU General Public License along
1100- * with this program. If not, see <http://www.gnu.org/licenses/>.
1101- *
1102- * Authors:
1103- * Ted Gould <ted.gould@canonical.com>
1104- */
1105-
1106-#include "app-store-click.h"
1107-#include "application-impl-click.h"
1108-#include "registry-impl.h"
1109-
1110-#include <algorithm>
1111-
1112-namespace ubuntu
1113-{
1114-namespace app_launch
1115-{
1116-namespace app_store
1117-{
1118-
1119-std::list<AppID::AppName> manifestApps(const std::shared_ptr<JsonObject>& manifest);
1120-AppID::Version manifestVersion(const std::shared_ptr<JsonObject>& manifest);
1121-
1122-Click::Click()
1123-{
1124-}
1125-
1126-Click::~Click()
1127-{
1128-}
1129-
1130-/** Tries to get the Click manifest for a package. If it can successfully
1131- get the manifest returns true.
1132-
1133- \param package Name of the package
1134- \param registry Persistent connections to use
1135-*/
1136-bool Click::verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry)
1137-{
1138- return registry->impl->getClickManifest(package) != nullptr;
1139-}
1140-
1141-/** Verifies the applicaiton name by getting the list of applications
1142- in the package manifest and seeing if the appname is in the list.
1143-
1144- \param package Name of the package
1145- \param appname Name of the application
1146- \param registry Persistent connections to use
1147-*/
1148-bool Click::verifyAppname(const AppID::Package& package,
1149- const AppID::AppName& appname,
1150- const std::shared_ptr<Registry>& registry)
1151-{
1152- auto manifest = registry->impl->getClickManifest(package);
1153- auto apps = manifestApps(manifest);
1154-
1155- return std::find_if(apps.begin(), apps.end(), [&appname](const AppID::AppName& listApp) -> bool {
1156- return appname.value() == listApp.value();
1157- }) != apps.end();
1158-}
1159-
1160-/** Finds an application name based on a wildcard search. Gets the list
1161- from the manifest, and then returns a value from that list.
1162-
1163- \param package Name of the package
1164- \param card Wildcard to search as
1165- \param registry Persistent connections to use
1166-*/
1167-AppID::AppName Click::findAppname(const AppID::Package& package,
1168- AppID::ApplicationWildcard card,
1169- const std::shared_ptr<Registry>& registry)
1170-{
1171- auto manifest = registry->impl->getClickManifest(package);
1172- auto apps = manifestApps(manifest);
1173-
1174- if (apps.empty())
1175- {
1176- throw std::runtime_error("No apps in package '" + package.value() + "' to find");
1177- }
1178-
1179- switch (card)
1180- {
1181- case AppID::ApplicationWildcard::FIRST_LISTED:
1182- return *apps.begin();
1183- case AppID::ApplicationWildcard::LAST_LISTED:
1184- return *apps.rbegin();
1185- case AppID::ApplicationWildcard::ONLY_LISTED:
1186- if (apps.size() != 1)
1187- {
1188- throw std::runtime_error("More than a single app in package '" + package.value() +
1189- "' when requested to find only app");
1190- }
1191- return *apps.begin();
1192- }
1193-
1194- throw std::logic_error("Got a value of the app wildcard enum that can't exist");
1195-}
1196-
1197-/** Find the version of a package that that is requested
1198-
1199- \param package Name of the package
1200- \param appname Name of the application (not used)
1201- \param registry Persistent connections to use
1202-*/
1203-AppID::Version Click::findVersion(const AppID::Package& package,
1204- const AppID::AppName& appname,
1205- const std::shared_ptr<Registry>& registry)
1206-{
1207- auto manifest = registry->impl->getClickManifest(package);
1208- return manifestVersion(manifest);
1209-}
1210-
1211-/** Check to see if this AppID has a desktop file that is in our link
1212- farm built by Click. Click puts a symoblic link there for every
1213- valid AppID.
1214-
1215- \param appid Application ID to check
1216- \param registry Persistent connections to use
1217-*/
1218-bool Click::hasAppId(const AppID& appid, const std::shared_ptr<Registry>& registry)
1219-{
1220- std::string appiddesktop = std::string(appid) + ".desktop";
1221- gchar* click_link = nullptr;
1222- const gchar* link_farm_dir = g_getenv("UBUNTU_APP_LAUNCH_LINK_FARM");
1223- if (G_LIKELY(link_farm_dir == nullptr))
1224- {
1225- click_link =
1226- g_build_filename(g_get_user_cache_dir(), "ubuntu-app-launch", "desktop", appiddesktop.c_str(), NULL);
1227- }
1228- else
1229- {
1230- click_link = g_build_filename(link_farm_dir, appiddesktop.c_str(), NULL);
1231- }
1232-
1233- bool click = g_file_test(click_link, G_FILE_TEST_EXISTS);
1234- g_free(click_link);
1235-
1236- return click;
1237-}
1238-
1239-std::list<std::shared_ptr<Application>> Click::list(const std::shared_ptr<Registry>& registry)
1240-{
1241- std::list<std::shared_ptr<Application>> applist;
1242-
1243- try
1244- {
1245- for (auto pkg : registry->impl->getClickPackages())
1246- {
1247- try
1248- {
1249- auto manifest = registry->impl->getClickManifest(pkg);
1250-
1251- for (auto appname : manifestApps(manifest))
1252- {
1253- try
1254- {
1255- AppID appid{pkg, appname, manifestVersion(manifest)};
1256- auto app = std::make_shared<app_impls::Click>(appid, manifest, registry);
1257- applist.emplace_back(app);
1258- }
1259- catch (std::runtime_error& e)
1260- {
1261- g_debug("Unable to create Click for application '%s' in package '%s': %s",
1262- appname.value().c_str(), pkg.value().c_str(), e.what());
1263- }
1264- }
1265- }
1266- catch (std::runtime_error& e)
1267- {
1268- g_debug("Unable to get information to build Click app on package '%s': %s", pkg.value().c_str(),
1269- e.what());
1270- }
1271- }
1272- }
1273- catch (std::runtime_error& e)
1274- {
1275- g_debug("Unable to get packages from Click database: %s", e.what());
1276- }
1277-
1278- return applist;
1279-}
1280-
1281-std::shared_ptr<app_impls::Base> Click::create(const AppID& appid, const std::shared_ptr<Registry>& registry)
1282-{
1283- return std::make_shared<app_impls::Click>(appid, registry);
1284-}
1285-
1286-std::list<AppID::AppName> manifestApps(const std::shared_ptr<JsonObject>& manifest)
1287-{
1288- JsonObject* hooks = nullptr;
1289- if (!json_object_has_member(manifest.get(), "hooks") ||
1290- (hooks = json_object_get_object_member(manifest.get(), "hooks")) == nullptr)
1291- {
1292- throw std::runtime_error("Manifest does not have a 'hooks' field: " + Registry::Impl::printJson(manifest));
1293- }
1294-
1295- auto gapps = json_object_get_members(hooks);
1296- if (gapps == nullptr)
1297- {
1298- throw std::runtime_error("GLib JSON confusion, please talk to your library vendor");
1299- }
1300-
1301- std::list<AppID::AppName> apps;
1302-
1303- for (GList* item = gapps; item != nullptr; item = g_list_next(item))
1304- {
1305- auto appname = (const gchar*)item->data;
1306-
1307- auto hooklist = json_object_get_object_member(hooks, appname);
1308-
1309- if (json_object_has_member(hooklist, "desktop") == TRUE)
1310- {
1311- apps.emplace_back(AppID::AppName::from_raw(appname));
1312- }
1313- }
1314-
1315- g_list_free(gapps);
1316- return apps;
1317-}
1318-
1319-AppID::Version manifestVersion(const std::shared_ptr<JsonObject>& manifest)
1320-{
1321- const gchar* cstr = nullptr;
1322- if (!json_object_has_member(manifest.get(), "version") ||
1323- (cstr = json_object_get_string_member(manifest.get(), "version")) == nullptr)
1324- {
1325- throw std::runtime_error("Unable to find version number in manifest: " + Registry::Impl::printJson(manifest));
1326- }
1327-
1328- auto cppstr = AppID::Version::from_raw(cstr);
1329- return cppstr;
1330-}
1331-
1332-} // namespace app_store
1333-} // namespace app_launch
1334-} // namespace ubuntu
1335
1336=== removed file 'libubuntu-app-launch/app-store-click.h'
1337--- libubuntu-app-launch/app-store-click.h 2017-03-21 03:26:39 +0000
1338+++ libubuntu-app-launch/app-store-click.h 1970-01-01 00:00:00 +0000
1339@@ -1,60 +0,0 @@
1340-/*
1341- * Copyright © 2017 Canonical Ltd.
1342- *
1343- * This program is free software: you can redistribute it and/or modify it
1344- * under the terms of the GNU General Public License version 3, as published
1345- * by the Free Software Foundation.
1346- *
1347- * This program is distributed in the hope that it will be useful, but
1348- * WITHOUT ANY WARRANTY; without even the implied warranties of
1349- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1350- * PURPOSE. See the GNU General Public License for more details.
1351- *
1352- * You should have received a copy of the GNU General Public License along
1353- * with this program. If not, see <http://www.gnu.org/licenses/>.
1354- *
1355- * Authors:
1356- * Ted Gould <ted.gould@canonical.com>
1357- */
1358-
1359-#pragma once
1360-
1361-#include "app-store-base.h"
1362-
1363-namespace ubuntu
1364-{
1365-namespace app_launch
1366-{
1367-namespace app_store
1368-{
1369-
1370-class Click : public Base
1371-{
1372-public:
1373- Click();
1374- virtual ~Click();
1375-
1376- /* Discover tools */
1377- virtual bool verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry) override;
1378- virtual bool verifyAppname(const AppID::Package& package,
1379- const AppID::AppName& appname,
1380- const std::shared_ptr<Registry>& registry) override;
1381- virtual AppID::AppName findAppname(const AppID::Package& package,
1382- AppID::ApplicationWildcard card,
1383- const std::shared_ptr<Registry>& registry) override;
1384- virtual AppID::Version findVersion(const AppID::Package& package,
1385- const AppID::AppName& appname,
1386- const std::shared_ptr<Registry>& registry) override;
1387- virtual bool hasAppId(const AppID& appid, const std::shared_ptr<Registry>& registry) override;
1388-
1389- /* Possible apps */
1390- virtual std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry) override;
1391-
1392- /* Application Creation */
1393- virtual std::shared_ptr<app_impls::Base> create(const AppID& appid,
1394- const std::shared_ptr<Registry>& registry) override;
1395-};
1396-
1397-} // namespace app_store
1398-} // namespace app_launch
1399-} // namespace ubuntu
1400
1401=== modified file 'libubuntu-app-launch/app-store-snap.cpp'
1402--- libubuntu-app-launch/app-store-snap.cpp 2017-03-21 03:26:39 +0000
1403+++ libubuntu-app-launch/app-store-snap.cpp 2017-03-21 03:26:40 +0000
1404@@ -109,6 +109,12 @@
1405 }
1406
1407 auto pkgInfo = registry->impl->snapdInfo.pkgInfo(package);
1408+
1409+ if (!pkgInfo)
1410+ {
1411+ return false;
1412+ }
1413+
1414 return pkgInfo->appnames.find(appname) != pkgInfo->appnames.end();
1415 }
1416
1417@@ -125,6 +131,11 @@
1418 {
1419 auto pkgInfo = registry->impl->snapdInfo.pkgInfo(package);
1420
1421+ if (!pkgInfo)
1422+ {
1423+ throw std::runtime_error("Packge '" + package.value() + "' doesn't have valid info.");
1424+ }
1425+
1426 if (pkgInfo->appnames.empty())
1427 {
1428 throw std::runtime_error("No apps in package '" + package.value() + "' to find");
1429@@ -159,7 +170,14 @@
1430 const std::shared_ptr<Registry>& registry)
1431 {
1432 auto pkgInfo = registry->impl->snapdInfo.pkgInfo(package);
1433- return AppID::Version::from_raw(pkgInfo->revision);
1434+ if (pkgInfo)
1435+ {
1436+ return AppID::Version::from_raw(pkgInfo->revision);
1437+ }
1438+ else
1439+ {
1440+ return AppID::Version::from_raw({});
1441+ }
1442 }
1443
1444 /** Operator to compare apps for our sets */
1445
1446=== modified file 'libubuntu-app-launch/application-impl-base.cpp'
1447--- libubuntu-app-launch/application-impl-base.cpp 2017-03-21 03:26:39 +0000
1448+++ libubuntu-app-launch/application-impl-base.cpp 2017-03-21 03:26:40 +0000
1449@@ -24,9 +24,9 @@
1450 #include <numeric>
1451
1452 #include "application-impl-base.h"
1453-#include "helpers.h"
1454 #include "registry-impl.h"
1455 #include "second-exec-core.h"
1456+#include "utils.h"
1457
1458 extern "C" {
1459 #include "ubuntu-app-launch-trace.h"
1460
1461=== removed file 'libubuntu-app-launch/application-impl-click.cpp'
1462--- libubuntu-app-launch/application-impl-click.cpp 2017-03-21 03:26:39 +0000
1463+++ libubuntu-app-launch/application-impl-click.cpp 1970-01-01 00:00:00 +0000
1464@@ -1,189 +0,0 @@
1465-/*
1466- * Copyright © 2016 Canonical Ltd.
1467- *
1468- * This program is free software: you can redistribute it and/or modify it
1469- * under the terms of the GNU General Public License version 3, as published
1470- * by the Free Software Foundation.
1471- *
1472- * This program is distributed in the hope that it will be useful, but
1473- * WITHOUT ANY WARRANTY; without even the implied warranties of
1474- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1475- * PURPOSE. See the GNU General Public License for more details.
1476- *
1477- * You should have received a copy of the GNU General Public License along
1478- * with this program. If not, see <http://www.gnu.org/licenses/>.
1479- *
1480- * Authors:
1481- * Ted Gould <ted.gould@canonical.com>
1482- */
1483-
1484-#include "application-impl-click.h"
1485-#include "application-info-desktop.h"
1486-#include "registry-impl.h"
1487-
1488-#include <algorithm>
1489-
1490-namespace ubuntu
1491-{
1492-namespace app_launch
1493-{
1494-namespace app_impls
1495-{
1496-
1497-std::pair<std::shared_ptr<GKeyFile>, std::string> manifestAppDesktop(const std::shared_ptr<JsonObject>& manifest,
1498- const std::string& package,
1499- const std::string& app,
1500- const std::string& clickDir);
1501-
1502-Click::Click(const AppID& appid, const std::shared_ptr<Registry>& registry)
1503- : Click(appid, registry->impl->getClickManifest(appid.package), registry)
1504-{
1505-}
1506-
1507-Click::Click(const AppID& appid, const std::shared_ptr<JsonObject>& manifest, const std::shared_ptr<Registry>& registry)
1508- : Base(registry)
1509- , _appid(appid)
1510- , _manifest(manifest)
1511- , _clickDir(registry->impl->getClickDir(appid.package))
1512-{
1513- std::tie(_keyfile, desktopPath_) = manifestAppDesktop(_manifest, appid.package, appid.appname, _clickDir);
1514- if (!_keyfile)
1515- throw std::runtime_error{"No keyfile found for click application: " + std::string(appid)};
1516-
1517- g_debug("Application Click object for appid '%s'", std::string(appid).c_str());
1518-}
1519-
1520-AppID Click::appId()
1521-{
1522- return _appid;
1523-}
1524-
1525-std::shared_ptr<Application::Info> Click::info()
1526-{
1527- if (!_info)
1528- {
1529- _info = std::make_shared<app_info::Desktop>(appId(), _keyfile, _clickDir, _clickDir,
1530- app_info::DesktopFlags::NONE, nullptr);
1531- }
1532-
1533- return _info;
1534-}
1535-
1536-AppID::Version manifestVersion(const std::shared_ptr<JsonObject>& manifest)
1537-{
1538- const gchar* cstr = nullptr;
1539- if (!json_object_has_member(manifest.get(), "version") ||
1540- (cstr = json_object_get_string_member(manifest.get(), "version")) == nullptr)
1541- {
1542- throw std::runtime_error("Unable to find version number in manifest: " + Registry::Impl::printJson(manifest));
1543- }
1544-
1545- auto cppstr = AppID::Version::from_raw(cstr);
1546- return cppstr;
1547-}
1548-
1549-std::pair<std::shared_ptr<GKeyFile>, std::string> manifestAppDesktop(const std::shared_ptr<JsonObject>& manifest,
1550- const std::string& package,
1551- const std::string& app,
1552- const std::string& clickDir)
1553-{
1554- if (!manifest)
1555- {
1556- throw std::runtime_error("No manifest for package '" + package + "'");
1557- }
1558-
1559- JsonObject* hooks = nullptr;
1560- if (!json_object_has_member(manifest.get(), "hooks") ||
1561- (hooks = json_object_get_object_member(manifest.get(), "hooks")) == nullptr)
1562- {
1563- throw std::runtime_error("Manifest for application '" + app +
1564- "' does not have a 'hooks' field: " + Registry::Impl::printJson(manifest));
1565- }
1566-
1567- auto gapps = json_object_get_members(hooks);
1568- if (gapps == nullptr)
1569- {
1570- throw std::runtime_error("GLib JSON confusion, please talk to your library vendor");
1571- }
1572- else
1573- {
1574- g_list_free(gapps);
1575- }
1576-
1577- JsonObject* hooklist = nullptr;
1578- if (!json_object_has_member(hooks, app.c_str()) ||
1579- (hooklist = json_object_get_object_member(hooks, app.c_str())) == nullptr)
1580- {
1581- throw std::runtime_error("Manifest for does not have an application '" + app +
1582- "': " + Registry::Impl::printJson(manifest));
1583- }
1584-
1585- auto desktoppath = json_object_get_string_member(hooklist, "desktop");
1586- if (desktoppath == nullptr)
1587- throw std::runtime_error("Manifest for application '" + app +
1588- "' does not have a 'desktop' hook: " + Registry::Impl::printJson(manifest));
1589-
1590- auto path = std::shared_ptr<gchar>(g_build_filename(clickDir.c_str(), desktoppath, nullptr), g_free);
1591-
1592- std::shared_ptr<GKeyFile> keyfile(g_key_file_new(), g_key_file_free);
1593- GError* error = nullptr;
1594- g_key_file_load_from_file(keyfile.get(), path.get(), G_KEY_FILE_NONE, &error);
1595- if (error != nullptr)
1596- {
1597- auto perror = std::shared_ptr<GError>(error, g_error_free);
1598- throw std::runtime_error(perror.get()->message);
1599- }
1600-
1601- return std::make_pair(keyfile, std::string(path.get()));
1602-}
1603-
1604-std::vector<std::shared_ptr<Application::Instance>> Click::instances()
1605-{
1606- auto vbase = _registry->impl->jobs->instances(appId(), "application-click");
1607- return std::vector<std::shared_ptr<Application::Instance>>(vbase.begin(), vbase.end());
1608-}
1609-
1610-/** Grabs all the environment variables for the application to
1611- launch in. It sets up the confinement ones and then adds in
1612- the APP_EXEC line and whether to use XMir */
1613-std::list<std::pair<std::string, std::string>> Click::launchEnv()
1614-{
1615- auto retval = confinedEnv(_appid.package, _clickDir);
1616-
1617- retval.emplace_back(std::make_pair("APP_DIR", _clickDir));
1618- retval.emplace_back(std::make_pair("APP_DESKTOP_FILE_PATH", desktopPath_));
1619-
1620- retval.emplace_back(std::make_pair("QML2_IMPORT_PATH", _clickDir + "/lib/" + UBUNTU_APP_LAUNCH_ARCH + "/qml"));
1621-
1622- info();
1623-
1624- retval.emplace_back(std::make_pair("APP_XMIR_ENABLE", _info->xMirEnable().value() ? "1" : "0"));
1625- retval.emplace_back(std::make_pair("APP_EXEC", _info->execLine().value()));
1626-
1627- retval.emplace_back(std::make_pair("APP_EXEC_POLICY", std::string(appId())));
1628-
1629- return retval;
1630-}
1631-
1632-std::shared_ptr<Application::Instance> Click::launch(const std::vector<Application::URL>& urls)
1633-{
1634- std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this]() { return launchEnv(); };
1635- return _registry->impl->jobs->launch(appId(), "application-click", {}, urls, jobs::manager::launchMode::STANDARD,
1636- envfunc);
1637-}
1638-
1639-std::shared_ptr<Application::Instance> Click::launchTest(const std::vector<Application::URL>& urls)
1640-{
1641- std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this]() { return launchEnv(); };
1642- return _registry->impl->jobs->launch(appId(), "application-click", {}, urls, jobs::manager::launchMode::TEST,
1643- envfunc);
1644-}
1645-
1646-std::shared_ptr<Application::Instance> Click::findInstance(const std::string& instanceid)
1647-{
1648- return _registry->impl->jobs->existing(appId(), "application-click", instanceid, std::vector<Application::URL>{});
1649-}
1650-
1651-} // namespace app_impls
1652-} // namespace app_launch
1653-} // namespace ubuntu
1654
1655=== removed file 'libubuntu-app-launch/application-impl-click.h'
1656--- libubuntu-app-launch/application-impl-click.h 2017-03-21 03:26:39 +0000
1657+++ libubuntu-app-launch/application-impl-click.h 1970-01-01 00:00:00 +0000
1658@@ -1,82 +0,0 @@
1659-/*
1660- * Copyright © 2016 Canonical Ltd.
1661- *
1662- * This program is free software: you can redistribute it and/or modify it
1663- * under the terms of the GNU General Public License version 3, as published
1664- * by the Free Software Foundation.
1665- *
1666- * This program is distributed in the hope that it will be useful, but
1667- * WITHOUT ANY WARRANTY; without even the implied warranties of
1668- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1669- * PURPOSE. See the GNU General Public License for more details.
1670- *
1671- * You should have received a copy of the GNU General Public License along
1672- * with this program. If not, see <http://www.gnu.org/licenses/>.
1673- *
1674- * Authors:
1675- * Ted Gould <ted.gould@canonical.com>
1676- */
1677-
1678-#include "application-impl-base.h"
1679-#include "application-info-desktop.h"
1680-
1681-#include <gio/gdesktopappinfo.h>
1682-#include <json-glib/json-glib.h>
1683-
1684-#pragma once
1685-
1686-namespace ubuntu
1687-{
1688-namespace app_launch
1689-{
1690-namespace app_impls
1691-{
1692-
1693-/** Application Implmentation for Click packages. Click packages
1694- are installed via the click tool and have information avaialable
1695- on them via libclick. There is one version per-user on the system
1696- and a Ubuntu App Launch hook makes a link to each of those versions
1697- in the user's cache directory. Click ensures this is up-to-date.
1698-
1699- Application IDs for Click packages are the standard it was built on.
1700- Typically a package name is "$(application).$(developer id)" though
1701- there isn't a requirement in the local Click tools to require that. The
1702- appname element is gotten from the JSON manifest in the Click package and
1703- should reference a desktop file. All Click packages also have a version.
1704-
1705- More info: http://click.readthedocs.io/
1706-*/
1707-class Click : public Base
1708-{
1709-public:
1710- Click(const AppID& appid, const std::shared_ptr<Registry>& registry);
1711- Click(const AppID& appid, const std::shared_ptr<JsonObject>& manifest, const std::shared_ptr<Registry>& registry);
1712-
1713- AppID appId() override;
1714-
1715- std::shared_ptr<Info> info() override;
1716-
1717- std::vector<std::shared_ptr<Instance>> instances() override;
1718-
1719- std::shared_ptr<Instance> launch(const std::vector<Application::URL>& urls = {}) override;
1720- std::shared_ptr<Instance> launchTest(const std::vector<Application::URL>& urls = {}) override;
1721-
1722- virtual std::shared_ptr<Application::Instance> findInstance(const std::string& instanceid) override;
1723-
1724-private:
1725- AppID _appid;
1726-
1727- std::shared_ptr<JsonObject> _manifest;
1728-
1729- std::string _clickDir;
1730- std::shared_ptr<GKeyFile> _keyfile;
1731- std::string desktopPath_;
1732-
1733- std::shared_ptr<app_info::Desktop> _info;
1734-
1735- std::list<std::pair<std::string, std::string>> launchEnv();
1736-};
1737-
1738-} // namespace app_impls
1739-} // namespace app_launch
1740-} // namespace ubuntu
1741
1742=== modified file 'libubuntu-app-launch/glib-thread.cpp'
1743--- libubuntu-app-launch/glib-thread.cpp 2016-08-12 23:13:00 +0000
1744+++ libubuntu-app-launch/glib-thread.cpp 2017-03-21 03:26:40 +0000
1745@@ -119,7 +119,7 @@
1746 return _cancel;
1747 }
1748
1749-void ContextThread::simpleSource(std::function<GSource*()> srcBuilder, std::function<void()> work)
1750+guint ContextThread::simpleSource(std::function<GSource*()> srcBuilder, std::function<void()> work)
1751 {
1752 if (isCancelled())
1753 {
1754@@ -144,22 +144,33 @@
1755 delete heapWork;
1756 });
1757
1758- g_source_attach(source.get(), _context.get());
1759-}
1760-
1761-void ContextThread::executeOnThread(std::function<void()> work)
1762-{
1763- simpleSource(g_idle_source_new, work);
1764-}
1765-
1766-void ContextThread::timeout(const std::chrono::milliseconds& length, std::function<void()> work)
1767-{
1768- simpleSource([length]() { return g_timeout_source_new(length.count()); }, work);
1769-}
1770-
1771-void ContextThread::timeoutSeconds(const std::chrono::seconds& length, std::function<void()> work)
1772-{
1773- simpleSource([length]() { return g_timeout_source_new_seconds(length.count()); }, work);
1774+ return g_source_attach(source.get(), _context.get());
1775+}
1776+
1777+guint ContextThread::executeOnThread(std::function<void()> work)
1778+{
1779+ return simpleSource(g_idle_source_new, work);
1780+}
1781+
1782+guint ContextThread::timeout(const std::chrono::milliseconds& length, std::function<void()> work)
1783+{
1784+ return simpleSource([length]() { return g_timeout_source_new(length.count()); }, work);
1785+}
1786+
1787+guint ContextThread::timeoutSeconds(const std::chrono::seconds& length, std::function<void()> work)
1788+{
1789+ return simpleSource([length]() { return g_timeout_source_new_seconds(length.count()); }, work);
1790+}
1791+
1792+void ContextThread::removeSource(guint sourceid)
1793+{
1794+ auto source = g_main_context_find_source_by_id(_context.get(), sourceid);
1795+ if (source == nullptr)
1796+ {
1797+ return;
1798+ }
1799+
1800+ g_source_destroy(source);
1801 }
1802
1803 } // ns GLib
1804
1805=== modified file 'libubuntu-app-launch/glib-thread.h'
1806--- libubuntu-app-launch/glib-thread.h 2016-08-24 02:53:12 +0000
1807+++ libubuntu-app-launch/glib-thread.h 2017-03-21 03:26:40 +0000
1808@@ -46,7 +46,7 @@
1809 bool isCancelled();
1810 std::shared_ptr<GCancellable> getCancellable();
1811
1812- void executeOnThread(std::function<void()> work);
1813+ guint executeOnThread(std::function<void()> work);
1814 template <typename T>
1815 auto executeOnThread(std::function<T()> work) -> T
1816 {
1817@@ -75,21 +75,23 @@
1818 return future.get();
1819 }
1820
1821- void timeout(const std::chrono::milliseconds& length, std::function<void()> work);
1822+ guint timeout(const std::chrono::milliseconds& length, std::function<void()> work);
1823 template <class Rep, class Period>
1824- void timeout(const std::chrono::duration<Rep, Period>& length, std::function<void()> work)
1825+ guint timeout(const std::chrono::duration<Rep, Period>& length, std::function<void()> work)
1826 {
1827 return timeout(std::chrono::duration_cast<std::chrono::milliseconds>(length), work);
1828 }
1829
1830- void timeoutSeconds(const std::chrono::seconds& length, std::function<void()> work);
1831+ guint timeoutSeconds(const std::chrono::seconds& length, std::function<void()> work);
1832 template <class Rep, class Period>
1833- void timeoutSeconds(const std::chrono::duration<Rep, Period>& length, std::function<void()> work)
1834+ guint timeoutSeconds(const std::chrono::duration<Rep, Period>& length, std::function<void()> work)
1835 {
1836 return timeoutSeconds(std::chrono::duration_cast<std::chrono::seconds>(length), work);
1837 }
1838
1839+ void removeSource(guint sourceid);
1840+
1841 private:
1842- void simpleSource(std::function<GSource*()> srcBuilder, std::function<void()> work);
1843+ guint simpleSource(std::function<GSource*()> srcBuilder, std::function<void()> work);
1844 };
1845 }
1846
1847=== modified file 'libubuntu-app-launch/helper.cpp'
1848--- libubuntu-app-launch/helper.cpp 2017-03-21 03:26:39 +0000
1849+++ libubuntu-app-launch/helper.cpp 2017-03-21 03:26:40 +0000
1850@@ -86,7 +86,7 @@
1851 std::vector<std::shared_ptr<Helper::Instance>> Base::instances()
1852 {
1853 auto insts = _registry->impl->jobs->instances(_appid, _type.value());
1854- std::vector<std::shared_ptr<Helper::Instance>> wrapped;
1855+ std::vector<std::shared_ptr<Helper::Instance>> wrapped{insts.size()};
1856
1857 std::transform(insts.begin(), insts.end(), wrapped.begin(),
1858 [](std::shared_ptr<jobs::instance::Base>& inst) { return std::make_shared<BaseInstance>(inst); });
1859@@ -110,8 +110,12 @@
1860 std::vector<Application::URL> appURL(const std::vector<Helper::URL>& in)
1861 {
1862 std::vector<Application::URL> out;
1863- std::transform(in.begin(), in.end(), out.begin(),
1864- [](Helper::URL url) { return Application::URL::from_raw(url.value()); });
1865+
1866+ for (const auto& hurl : in)
1867+ {
1868+ out.push_back(Application::URL::from_raw(hurl.value()));
1869+ }
1870+
1871 return out;
1872 }
1873
1874@@ -191,6 +195,8 @@
1875 return accum.empty() ? addon : accum + " " + addon;
1876 })));
1877
1878+ envs.emplace_back(std::make_pair("HELPER_TYPE", _type.value()));
1879+
1880 return envs;
1881 }
1882
1883@@ -206,14 +212,17 @@
1884 class MirFDProxy
1885 {
1886 public:
1887+ std::shared_ptr<Registry> reg_;
1888 int mirfd;
1889 std::shared_ptr<proxySocketDemangler> skel;
1890 guint handle;
1891 std::string path;
1892 std::string name;
1893+ guint timeout{0};
1894
1895 MirFDProxy(MirPromptSession* session, const AppID& appid, const std::shared_ptr<Registry>& reg)
1896- : name(g_dbus_connection_get_unique_name(reg->impl->_dbus.get()))
1897+ : reg_(reg)
1898+ , name(g_dbus_connection_get_unique_name(reg->impl->_dbus.get()))
1899 {
1900 if (appid.empty())
1901 {
1902@@ -291,6 +300,7 @@
1903
1904 ~MirFDProxy()
1905 {
1906+ g_debug("Mir Prompt Proxy shutdown");
1907 if (mirfd != 0)
1908 {
1909 close(mirfd);
1910@@ -304,6 +314,11 @@
1911 g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(skel.get()));
1912 }
1913
1914+ void setTimeout(guint timeoutin)
1915+ {
1916+ timeout = timeoutin;
1917+ }
1918+
1919 static std::string dbusSafe(const std::string& in)
1920 {
1921 std::string out = in;
1922@@ -347,6 +362,13 @@
1923 }
1924
1925 mirfd = 0;
1926+
1927+ /* Remove the timeout on the mainloop */
1928+ auto reg = reg_;
1929+ auto timeoutlocal = timeout;
1930+
1931+ reg->impl->thread.executeOnThread([reg, timeoutlocal]() { reg->impl->thread.removeSource(timeoutlocal); });
1932+
1933 return true;
1934 }
1935
1936@@ -391,7 +413,8 @@
1937
1938 /* This will maintain a reference to the proxy for two
1939 seconds. And then it'll be dropped. */
1940- _registry->impl->thread.timeout(std::chrono::seconds{2}, [proxy]() { g_debug("Mir Proxy Timeout"); });
1941+ proxy->setTimeout(
1942+ _registry->impl->thread.timeout(std::chrono::seconds{2}, [proxy]() { g_debug("Mir Proxy Timeout"); }));
1943
1944 return std::make_shared<BaseInstance>(_registry->impl->jobs->launch(
1945 _appid, _type.value(), genInstanceId(), appURL(urls), jobs::manager::launchMode::STANDARD, envfunc));
1946
1947=== modified file 'libubuntu-app-launch/jobs-base.cpp'
1948--- libubuntu-app-launch/jobs-base.cpp 2017-03-21 03:26:39 +0000
1949+++ libubuntu-app-launch/jobs-base.cpp 2017-03-21 03:26:40 +0000
1950@@ -39,7 +39,7 @@
1951
1952 Base::Base(const std::shared_ptr<Registry>& registry)
1953 : registry_(registry)
1954- , allApplicationJobs_{"application-click", "application-legacy", "application-snap"}
1955+ , allApplicationJobs_{"application-legacy", "application-snap"}
1956 , dbus_(registry->impl->_dbus)
1957 {
1958 }
1959@@ -84,13 +84,20 @@
1960 return;
1961 }
1962
1963- auto reg = registry_.lock();
1964-
1965- auto appId = AppID::find(reg, appid);
1966- auto app = Application::create(appId, reg);
1967- auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(instanceid);
1968-
1969- sig_appStarted(app, inst);
1970+ try
1971+ {
1972+ auto reg = registry_.lock();
1973+
1974+ auto appId = AppID::find(reg, appid);
1975+ auto app = Application::create(appId, reg);
1976+ auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(instanceid);
1977+
1978+ sig_appStarted(app, inst);
1979+ }
1980+ catch (std::runtime_error& e)
1981+ {
1982+ g_warning("Error in appStarted signal from job: %s", e.what());
1983+ }
1984 });
1985 });
1986
1987@@ -107,13 +114,20 @@
1988 return;
1989 }
1990
1991- auto reg = registry_.lock();
1992-
1993- auto appId = AppID::find(reg, appid);
1994- auto app = Application::create(appId, reg);
1995- auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(instanceid);
1996-
1997- sig_appStopped(app, inst);
1998+ try
1999+ {
2000+ auto reg = registry_.lock();
2001+
2002+ auto appId = AppID::find(reg, appid);
2003+ auto app = Application::create(appId, reg);
2004+ auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(instanceid);
2005+
2006+ sig_appStopped(app, inst);
2007+ }
2008+ catch (std::runtime_error& e)
2009+ {
2010+ g_warning("Error in appStopped signal from job: %s", e.what());
2011+ }
2012 });
2013 });
2014
2015@@ -132,13 +146,20 @@
2016 return;
2017 }
2018
2019- auto reg = registry_.lock();
2020-
2021- auto appId = AppID::find(reg, appid);
2022- auto app = Application::create(appId, reg);
2023- auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(instanceid);
2024-
2025- sig_appFailed(app, inst, reason);
2026+ try
2027+ {
2028+ auto reg = registry_.lock();
2029+
2030+ auto appId = AppID::find(reg, appid);
2031+ auto app = Application::create(appId, reg);
2032+ auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(instanceid);
2033+
2034+ sig_appFailed(app, inst, reason);
2035+ }
2036+ catch (std::runtime_error& e)
2037+ {
2038+ g_warning("Error in appFailed signal from job: %s", e.what());
2039+ }
2040 });
2041 });
2042
2043@@ -487,16 +508,23 @@
2044 return;
2045 }
2046
2047- auto vparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
2048- auto conn = std::shared_ptr<GDBusConnection>(reinterpret_cast<GDBusConnection*>(g_object_ref(cconn)),
2049- [](GDBusConnection* con) { g_clear_object(&con); });
2050- std::string sender = csender;
2051- std::shared_ptr<Application> app;
2052- std::shared_ptr<Application::Instance> instance;
2053-
2054- std::tie(app, instance) = managerParams(vparams, reg);
2055-
2056- data->func(reg, app, instance, conn, sender, vparams);
2057+ try
2058+ {
2059+ auto vparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
2060+ auto conn = std::shared_ptr<GDBusConnection>(reinterpret_cast<GDBusConnection*>(g_object_ref(cconn)),
2061+ [](GDBusConnection* con) { g_clear_object(&con); });
2062+ std::string sender = csender;
2063+ std::shared_ptr<Application> app;
2064+ std::shared_ptr<Application::Instance> instance;
2065+
2066+ std::tie(app, instance) = managerParams(vparams, reg);
2067+
2068+ data->func(reg, app, instance, conn, sender, vparams);
2069+ }
2070+ catch (std::runtime_error& e)
2071+ {
2072+ g_warning("Unable to call signal handler for manager signal: %s", e.what());
2073+ }
2074 },
2075 focusdata,
2076 [](gpointer user_data) {
2077@@ -632,7 +660,14 @@
2078 continue;
2079 }
2080
2081- apps.emplace_back(Application::create(id, registry));
2082+ try
2083+ {
2084+ apps.emplace_back(Application::create(id, registry));
2085+ }
2086+ catch (std::runtime_error& e)
2087+ {
2088+ g_debug("Error adding appid '%s' to running apps list: %s", appid.c_str(), e.what());
2089+ }
2090 }
2091
2092 return apps;
2093
2094=== modified file 'libubuntu-app-launch/jobs-systemd.cpp'
2095--- libubuntu-app-launch/jobs-systemd.cpp 2017-03-21 03:26:39 +0000
2096+++ libubuntu-app-launch/jobs-systemd.cpp 2017-03-21 03:26:40 +0000
2097@@ -19,9 +19,9 @@
2098
2099 #include "jobs-systemd.h"
2100 #include "application-impl-base.h"
2101-#include "helpers.h"
2102 #include "registry-impl.h"
2103 #include "second-exec-core.h"
2104+#include "utils.h"
2105
2106 extern "C" {
2107 #include "ubuntu-app-launch-trace.h"
2108@@ -587,6 +587,9 @@
2109 if (appId.empty())
2110 return {};
2111
2112+ bool isApplication =
2113+ std::find(allApplicationJobs_.begin(), allApplicationJobs_.end(), job) != allApplicationJobs_.end();
2114+
2115 auto registry = registry_.lock();
2116 return registry->impl->thread.executeOnThread<std::shared_ptr<instance::SystemD>>(
2117 [&]() -> std::shared_ptr<instance::SystemD> {
2118@@ -602,10 +605,15 @@
2119 timeout = 0;
2120 }
2121
2122- auto handshake = starting_handshake_start(appIdStr.c_str(), instance.c_str(), timeout);
2123- if (handshake == nullptr)
2124+ handshake_t* handshake{nullptr};
2125+
2126+ if (isApplication)
2127 {
2128- g_warning("Unable to setup starting handshake");
2129+ handshake = starting_handshake_start(appIdStr.c_str(), instance.c_str(), timeout);
2130+ if (handshake == nullptr)
2131+ {
2132+ g_warning("Unable to setup starting handshake");
2133+ }
2134 }
2135
2136 /* Figure out the unit name for the job */
2137@@ -903,8 +911,7 @@
2138 }
2139
2140 /* TODO: Application job names */
2141-const std::regex unitNaming{
2142- "^ubuntu\\-app\\-launch\\-(application\\-(?:click|legacy|snap))\\-(.*)\\-([0-9]*)\\.service$"};
2143+const std::regex unitNaming{"^ubuntu\\-app\\-launch\\-\\-(.*)\\-\\-(.*)\\-\\-([0-9]*)\\.service$"};
2144
2145 SystemD::UnitInfo SystemD::parseUnit(const std::string& unit) const
2146 {
2147@@ -919,7 +926,7 @@
2148
2149 std::string SystemD::unitName(const SystemD::UnitInfo& info) const
2150 {
2151- return std::string{"ubuntu-app-launch-"} + info.job + "-" + info.appid + "-" + info.inst + ".service";
2152+ return std::string{"ubuntu-app-launch--"} + info.job + "--" + info.appid + "--" + info.inst + ".service";
2153 }
2154
2155 std::string SystemD::unitPath(const SystemD::UnitInfo& info)
2156@@ -1347,6 +1354,11 @@
2157 auto cancel = registry->impl->thread.getCancellable();
2158
2159 registry->impl->thread.executeOnThread([bus, unitname, cancel] {
2160+ if (g_cancellable_is_cancelled(cancel.get()))
2161+ {
2162+ return;
2163+ }
2164+
2165 g_dbus_connection_call(bus.get(), /* user bus */
2166 SYSTEMD_DBUS_ADDRESS, /* bus name */
2167 SYSTEMD_DBUS_PATH_MANAGER, /* path */
2168
2169=== modified file 'libubuntu-app-launch/registry-impl.cpp'
2170--- libubuntu-app-launch/registry-impl.cpp 2017-03-21 03:26:39 +0000
2171+++ libubuntu-app-launch/registry-impl.cpp 2017-03-21 03:26:40 +0000
2172@@ -28,11 +28,13 @@
2173 {
2174
2175 Registry::Impl::Impl(Registry* registry)
2176+ : Impl(registry, app_store::Base::allAppStores())
2177+{
2178+}
2179+
2180+Registry::Impl::Impl(Registry* registry, std::list<std::shared_ptr<app_store::Base>> appStores)
2181 : thread([]() {},
2182 [this]() {
2183- _clickUser.reset();
2184- _clickDB.reset();
2185-
2186 zgLog_.reset();
2187 jobs.reset();
2188
2189@@ -42,7 +44,7 @@
2190 })
2191 , _registry{registry}
2192 , _iconFinders()
2193- , _appStores(app_store::Base::allAppStores())
2194+ , _appStores(appStores)
2195 {
2196 auto cancel = thread.getCancellable();
2197 _dbus = thread.executeOnThread<std::shared_ptr<GDBusConnection>>([cancel]() {
2198@@ -62,52 +64,6 @@
2199 }
2200 }
2201
2202-void Registry::Impl::initClick()
2203-{
2204- if (_clickDB && _clickUser)
2205- {
2206- return;
2207- }
2208-
2209- auto init = thread.executeOnThread<bool>([this]() {
2210- GError* error = nullptr;
2211-
2212- if (!_clickDB)
2213- {
2214- _clickDB = std::shared_ptr<ClickDB>(click_db_new(), [](ClickDB* db) { g_clear_object(&db); });
2215- /* If TEST_CLICK_DB is unset, this reads the system database. */
2216- click_db_read(_clickDB.get(), g_getenv("TEST_CLICK_DB"), &error);
2217-
2218- if (error != nullptr)
2219- {
2220- auto perror = std::shared_ptr<GError>(error, [](GError* error) { g_error_free(error); });
2221- throw std::runtime_error(perror->message);
2222- }
2223- }
2224-
2225- if (!_clickUser)
2226- {
2227- _clickUser =
2228- std::shared_ptr<ClickUser>(click_user_new_for_user(_clickDB.get(), g_getenv("TEST_CLICK_USER"), &error),
2229- [](ClickUser* user) { g_clear_object(&user); });
2230-
2231- if (error != nullptr)
2232- {
2233- auto perror = std::shared_ptr<GError>(error, [](GError* error) { g_error_free(error); });
2234- throw std::runtime_error(perror->message);
2235- }
2236- }
2237-
2238- g_debug("Initialized Click DB");
2239- return true;
2240- });
2241-
2242- if (!init)
2243- {
2244- throw std::runtime_error("Unable to initialize the Click Database");
2245- }
2246-}
2247-
2248 /** Helper function for printing JSON objects to debug output */
2249 std::string Registry::Impl::printJson(std::shared_ptr<JsonObject> jsonobj)
2250 {
2251@@ -133,89 +89,8 @@
2252 return retval;
2253 }
2254
2255-std::shared_ptr<JsonObject> Registry::Impl::getClickManifest(const std::string& package)
2256-{
2257- initClick();
2258-
2259- auto retval = thread.executeOnThread<std::shared_ptr<JsonObject>>([this, package]() {
2260- GError* error = nullptr;
2261- auto mani = click_user_get_manifest(_clickUser.get(), package.c_str(), &error);
2262-
2263- if (error != nullptr)
2264- {
2265- auto perror = std::shared_ptr<GError>(error, [](GError* error) { g_error_free(error); });
2266- g_debug("Error parsing manifest for package '%s': %s", package.c_str(), perror->message);
2267- return std::shared_ptr<JsonObject>();
2268- }
2269-
2270- auto node = json_node_alloc();
2271- json_node_init_object(node, mani);
2272- json_object_unref(mani);
2273-
2274- auto retval = std::shared_ptr<JsonObject>(json_node_dup_object(node), json_object_unref);
2275-
2276- json_node_free(node);
2277-
2278- return retval;
2279- });
2280-
2281- if (!retval)
2282- throw std::runtime_error("Unable to get Click manifest for package: " + package);
2283-
2284- return retval;
2285-}
2286-
2287-std::list<AppID::Package> Registry::Impl::getClickPackages()
2288-{
2289- initClick();
2290-
2291- return thread.executeOnThread<std::list<AppID::Package>>([this]() {
2292- GError* error = nullptr;
2293- GList* pkgs = click_user_get_package_names(_clickUser.get(), &error);
2294-
2295- if (error != nullptr)
2296- {
2297- auto perror = std::shared_ptr<GError>(error, [](GError* error) { g_error_free(error); });
2298- throw std::runtime_error(perror->message);
2299- }
2300-
2301- std::list<AppID::Package> list;
2302- for (GList* item = pkgs; item != nullptr; item = g_list_next(item))
2303- {
2304- auto pkgobj = static_cast<gchar*>(item->data);
2305- if (pkgobj)
2306- {
2307- list.emplace_back(AppID::Package::from_raw(pkgobj));
2308- }
2309- }
2310-
2311- g_list_free_full(pkgs, g_free);
2312- return list;
2313- });
2314-}
2315-
2316-std::string Registry::Impl::getClickDir(const std::string& package)
2317-{
2318- initClick();
2319-
2320- return thread.executeOnThread<std::string>([this, package]() {
2321- GError* error = nullptr;
2322- auto dir = click_user_get_path(_clickUser.get(), package.c_str(), &error);
2323-
2324- if (error != nullptr)
2325- {
2326- auto perror = std::shared_ptr<GError>(error, [](GError* error) { g_error_free(error); });
2327- throw std::runtime_error(perror->message);
2328- }
2329-
2330- std::string cppdir(dir);
2331- g_free(dir);
2332- return cppdir;
2333- });
2334-}
2335-
2336-/** Send an event to Zeitgeist using the registry thread so that
2337- the callback comes back in the right place. */
2338+/** Send an event to Zietgeist using the registry thread so that
2339+ the callback comes back in the right place. */
2340 void Registry::Impl::zgSendEvent(AppID appid, const std::string& eventtype)
2341 {
2342 thread.executeOnThread([this, appid, eventtype] {
2343
2344=== modified file 'libubuntu-app-launch/registry-impl.h'
2345--- libubuntu-app-launch/registry-impl.h 2017-03-21 03:26:39 +0000
2346+++ libubuntu-app-launch/registry-impl.h 2017-03-21 03:26:40 +0000
2347@@ -23,7 +23,6 @@
2348 #include "jobs-base.h"
2349 #include "registry.h"
2350 #include "snapd-info.h"
2351-#include <click.h>
2352 #include <gio/gio.h>
2353 #include <json-glib/json-glib.h>
2354 #include <map>
2355@@ -47,15 +46,13 @@
2356 {
2357 public:
2358 Impl(Registry* registry);
2359+ Impl(Registry* registry, std::list<std::shared_ptr<app_store::Base>> appStores);
2360+
2361 virtual ~Impl()
2362 {
2363 thread.quit();
2364 }
2365
2366- std::shared_ptr<JsonObject> getClickManifest(const std::string& package);
2367- std::list<AppID::Package> getClickPackages();
2368- std::string getClickDir(const std::string& package);
2369-
2370 static void setManager(const std::shared_ptr<Registry::Manager>& manager,
2371 const std::shared_ptr<Registry>& registry);
2372 void clearManager();
2373@@ -66,10 +63,8 @@
2374 /** DBus shared connection for the session bus */
2375 std::shared_ptr<GDBusConnection> _dbus;
2376
2377-#ifdef ENABLE_SNAPPY
2378 /** Snapd information object */
2379 snapd::Info snapdInfo;
2380-#endif
2381
2382 std::shared_ptr<jobs::manager::Base> jobs;
2383
2384@@ -105,14 +100,14 @@
2385 return _appStores;
2386 }
2387
2388+ void setAppStores(std::list<std::shared_ptr<app_store::Base>>& newlist)
2389+ {
2390+ _appStores = newlist;
2391+ }
2392+
2393 private:
2394 Registry* _registry; /**< The Registry that we're spawned from */
2395
2396- std::shared_ptr<ClickDB> _clickDB; /**< Shared instance of the Click Database */
2397- std::shared_ptr<ClickUser> _clickUser; /**< Click database filtered by the current user */
2398-
2399- void initClick();
2400-
2401 /** Shared instance of the Zeitgeist Log */
2402 std::shared_ptr<ZeitgeistLog> zgLog_;
2403
2404
2405=== modified file 'libubuntu-app-launch/second-exec-core.c'
2406--- libubuntu-app-launch/second-exec-core.c 2017-03-21 03:26:39 +0000
2407+++ libubuntu-app-launch/second-exec-core.c 2017-03-21 03:26:40 +0000
2408@@ -19,7 +19,7 @@
2409
2410 #include <gio/gio.h>
2411 #include "libubuntu-app-launch/ubuntu-app-launch.h"
2412-#include "helpers.h"
2413+#include "utils.h"
2414 #include "second-exec-core.h"
2415 #include "ubuntu-app-launch-trace.h"
2416 #include "ual-tracepoint.h"
2417
2418=== modified file 'libubuntu-app-launch/type-tagger.h'
2419--- libubuntu-app-launch/type-tagger.h 2016-06-09 14:55:34 +0000
2420+++ libubuntu-app-launch/type-tagger.h 2017-03-21 03:26:40 +0000
2421@@ -32,6 +32,14 @@
2422 {
2423 return _value;
2424 }
2425+ bool operator==(const TypeTagger<Tag, T>& b) const
2426+ {
2427+ return _value == b._value;
2428+ }
2429+ bool operator==(const T& b) const
2430+ {
2431+ return _value == b;
2432+ }
2433 ~TypeTagger()
2434 {
2435 }
2436
2437=== renamed file 'ual-tracepoint.h' => 'libubuntu-app-launch/ual-tracepoint.h'
2438=== modified file 'libubuntu-app-launch/ubuntu-app-launch.cpp'
2439--- libubuntu-app-launch/ubuntu-app-launch.cpp 2017-03-21 03:26:39 +0000
2440+++ libubuntu-app-launch/ubuntu-app-launch.cpp 2017-03-21 03:26:40 +0000
2441@@ -28,7 +28,7 @@
2442 #include <libwhoopsie/recoverable-problem.h>
2443
2444 #include "ubuntu-app-launch-trace.h"
2445-#include "helpers.h"
2446+#include "utils.h"
2447 #include "ual-tracepoint.h"
2448 #include "proxy-socket-demangler.h"
2449 }
2450@@ -423,11 +423,12 @@
2451 ubuntu_app_launch_observer_add_app_failed (UbuntuAppLaunchAppFailedObserver observer, gpointer user_data)
2452 {
2453 auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); });
2454+ auto reg = ubuntu::app_launch::Registry::getDefault();
2455
2456 appFailedObservers.emplace(std::make_pair(
2457 std::make_pair(observer, user_data),
2458 core::ScopedConnection(
2459- ubuntu::app_launch::Registry::appFailed().connect([context, observer, user_data](std::shared_ptr<ubuntu::app_launch::Application> app, std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, ubuntu::app_launch::Registry::FailureType type) {
2460+ ubuntu::app_launch::Registry::appFailed(reg).connect([context, observer, user_data](std::shared_ptr<ubuntu::app_launch::Application> app, std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, ubuntu::app_launch::Registry::FailureType type) {
2461 std::string appid = app->appId();
2462 executeOnContext(context, [appid, type, observer, user_data]() {
2463 UbuntuAppLaunchAppFailed ctype{UBUNTU_APP_LAUNCH_APP_FAILED_CRASH};
2464@@ -524,7 +525,8 @@
2465 }
2466
2467 return (gchar **)g_array_free(apps, FALSE);
2468- } catch (...) {
2469+ } catch (const std::exception& e) {
2470+ g_debug("Unable to list applications: %s", e.what());
2471 return nullptr;
2472 }
2473 }
2474@@ -539,7 +541,8 @@
2475 auto appId = ubuntu::app_launch::AppID::find(appid);
2476 auto app = ubuntu::app_launch::Application::create(appId, registry);
2477 return app->instances().at(0)->primaryPid();
2478- } catch (...) {
2479+ } catch (const std::exception& e) {
2480+ g_debug("Unable to get primary pid: %s", e.what());
2481 return 0;
2482 }
2483 }
2484@@ -637,6 +640,7 @@
2485
2486 auto appid = ubuntu::app_launch::AppID::discover(package, appname, version);
2487 if (appid.empty()) {
2488+ g_debug("Triplet lookup for '%s' '%s' '%s' returned empty", pkg, app, ver);
2489 return nullptr;
2490 }
2491
2492@@ -666,10 +670,10 @@
2493 throw std::runtime_error{"Empty instance"};
2494 }
2495
2496- return true;
2497+ return TRUE;
2498 } catch (std::runtime_error &e) {
2499 g_warning("Unable to launch helper of type '%s' id '%s': %s", type, appid, e.what());
2500- return false;
2501+ return FALSE;
2502 }
2503 }
2504
2505@@ -954,3 +958,9 @@
2506 }
2507 }
2508
2509+gboolean
2510+ubuntu_app_launch_application_info (const gchar * appid, gchar ** appdir, gchar ** appdesktop)
2511+{
2512+ /* TODO: Remove next ABI break */
2513+ return FALSE;
2514+}
2515
2516=== renamed file 'helpers-shared.c' => 'libubuntu-app-launch/utils-shared.c'
2517--- helpers-shared.c 2016-11-09 23:13:38 +0000
2518+++ libubuntu-app-launch/utils-shared.c 2017-03-21 03:26:40 +0000
2519@@ -17,7 +17,7 @@
2520 * Ted Gould <ted.gould@canonical.com>
2521 */
2522
2523-#include "helpers.h"
2524+#include "utils.h"
2525 #include <gio/gio.h>
2526 #include <cgmanager/cgmanager.h>
2527
2528
2529=== renamed file 'helpers.c' => 'libubuntu-app-launch/utils.c'
2530--- helpers.c 2017-03-21 03:26:39 +0000
2531+++ libubuntu-app-launch/utils.c 2017-03-21 03:26:40 +0000
2532@@ -18,8 +18,7 @@
2533 */
2534
2535 #include <json-glib/json-glib.h>
2536-#include <click.h>
2537-#include "helpers.h"
2538+#include "utils.h"
2539
2540 /* Take an app ID and validate it and then break it up
2541 and spit it out. These are newly allocated strings */
2542@@ -56,106 +55,6 @@
2543 return TRUE;
2544 }
2545
2546-/* Take a manifest, parse it, find the application and
2547- and then return the path to the desktop file */
2548-gchar *
2549-manifest_to_desktop (const gchar * app_dir, const gchar * app_id)
2550-{
2551- gchar * package = NULL;
2552- gchar * application = NULL;
2553- gchar * version = NULL;
2554- ClickDB * db = NULL;
2555- ClickUser * user = NULL;
2556- JsonObject * manifest = NULL;
2557- gchar * desktoppath = NULL;
2558- GError * error = NULL;
2559-
2560- if (!app_id_to_triplet(app_id, &package, &application, &version)) {
2561- g_warning("Unable to parse triplet: %s", app_id);
2562- return NULL;
2563- }
2564-
2565- db = click_db_new();
2566- /* If TEST_CLICK_DB is unset, this reads the system database. */
2567- click_db_read(db, g_getenv("TEST_CLICK_DB"), &error);
2568- if (error != NULL) {
2569- g_warning("Unable to read Click database: %s", error->message);
2570- goto manifest_out;
2571- }
2572- /* If TEST_CLICK_USER is unset, this uses the current user name. */
2573- user = click_user_new_for_user(db, g_getenv("TEST_CLICK_USER"), &error);
2574- if (error != NULL) {
2575- g_warning("Unable to read Click database: %s", error->message);
2576- goto manifest_out;
2577- }
2578- manifest = click_user_get_manifest(user, package, &error);
2579- if (error != NULL) {
2580- g_warning("Unable to get manifest for '%s': %s", package, error->message);
2581- goto manifest_out;
2582- }
2583-
2584- if (!json_object_has_member(manifest, "version")) {
2585- g_warning("Manifest '%s' doesn't have a version", package);
2586- goto manifest_out;
2587- }
2588-
2589- if (g_strcmp0(json_object_get_string_member(manifest, "version"), version) != 0) {
2590- g_warning("Manifest '%s' version '%s' doesn't match AppID version '%s'", package, json_object_get_string_member(manifest, "version"), version);
2591- goto manifest_out;
2592- }
2593-
2594- if (!json_object_has_member(manifest, "hooks")) {
2595- g_warning("Manifest '%s' doesn't have an hooks section", package);
2596- goto manifest_out;
2597- }
2598-
2599- JsonObject * appsobj = json_object_get_object_member(manifest, "hooks");
2600- if (appsobj == NULL) {
2601- g_warning("Manifest '%s' has an hooks section that is not a JSON object", package);
2602- goto manifest_out;
2603- }
2604-
2605- if (!json_object_has_member(appsobj, application)) {
2606- g_warning("Manifest '%s' doesn't have the application '%s' defined", package, application);
2607- goto manifest_out;
2608- }
2609-
2610- JsonObject * appobj = json_object_get_object_member(appsobj, application);
2611- if (appobj == NULL) {
2612- g_warning("Manifest '%s' has a definition for application '%s' that is not an object", package, application);
2613- goto manifest_out;
2614- }
2615-
2616- gchar * filename = NULL;
2617- if (json_object_has_member(appobj, "desktop")) {
2618- filename = g_strdup(json_object_get_string_member(appobj, "desktop"));
2619- } else {
2620- filename = g_strdup_printf("%s.desktop", application);
2621- }
2622-
2623- desktoppath = g_build_filename(app_dir, filename, NULL);
2624- g_free(filename);
2625-
2626- if (!g_file_test(desktoppath, G_FILE_TEST_EXISTS)) {
2627- g_warning("Application desktop file '%s' doesn't exist", desktoppath);
2628- g_free(desktoppath);
2629- desktoppath = NULL;
2630- }
2631-
2632-manifest_out:
2633- if (error != NULL)
2634- g_error_free(error);
2635- if (manifest != NULL)
2636- json_object_unref(manifest);
2637- g_clear_object(&user);
2638- g_clear_object(&db);
2639- g_free(package);
2640- g_free(application);
2641- g_free(version);
2642-
2643- return desktoppath;
2644-}
2645-
2646 /* Take a desktop file, make sure that it makes sense and
2647 then return the exec line */
2648 gchar *
2649
2650=== renamed file 'helpers.h' => 'libubuntu-app-launch/utils.h'
2651--- helpers.h 2017-03-21 03:26:39 +0000
2652+++ libubuntu-app-launch/utils.h 2017-03-21 03:26:40 +0000
2653@@ -25,8 +25,6 @@
2654 gchar ** package,
2655 gchar ** application,
2656 gchar ** version);
2657-gchar * manifest_to_desktop (const gchar * app_dir,
2658- const gchar * app_id);
2659 gchar * desktop_to_exec (GKeyFile * desktop_file,
2660 const gchar * from);
2661 GArray * desktop_exec_parse (const gchar * execline,
2662
2663=== modified file 'tests/CMakeLists.txt'
2664--- tests/CMakeLists.txt 2017-03-21 03:26:39 +0000
2665+++ tests/CMakeLists.txt 2017-03-21 03:26:40 +0000
2666@@ -1,13 +1,5 @@
2667 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
2668
2669-configure_file ("click-db-dir/test.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/click-db-dir/test.conf" @ONLY)
2670-set_directory_properties (PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/click-db-dir/test.conf")
2671-
2672-if(CURL_FOUND)
2673-add_definitions ( -DENABLE_SNAPPY=1 )
2674-endif()
2675-
2676-
2677 # Google Test
2678
2679 find_package(GMock)
2680@@ -17,14 +9,14 @@
2681 add_executable (helper-test helper-test.cc)
2682 add_definitions ( -DCMAKE_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" )
2683 add_definitions ( -DCMAKE_BINARY_DIR="${CMAKE_CURRENT_BINARY_DIR}" )
2684-target_link_libraries (helper-test helpers gtest_main ${GTEST_MAIN_LIBRARIES} ${DBUSTEST_LIBRARIES})
2685+target_link_libraries (helper-test launcher-static gtest_main ${GTEST_MAIN_LIBRARIES} ${DBUSTEST_LIBRARIES})
2686
2687 add_test (helper-test helper-test)
2688
2689 # Helper test
2690
2691 add_executable (helper-handshake-test helper-handshake-test.cc)
2692-target_link_libraries (helper-handshake-test helpers gtest_main ${GTEST_MAIN_LIBRARIES})
2693+target_link_libraries (helper-handshake-test launcher-static gtest_main ${GTEST_MAIN_LIBRARIES})
2694
2695 add_test (helper-handshake-test helper-handshake-test)
2696
2697@@ -33,7 +25,7 @@
2698 include_directories("${CMAKE_SOURCE_DIR}/libubuntu-app-launch")
2699 add_definitions ( -DSPEW_UTILITY="${CMAKE_CURRENT_BINARY_DIR}/data-spew" )
2700 add_definitions ( -DSESSION_TEMP_FILE="${CMAKE_CURRENT_BINARY_DIR}/libual-test-session-start-temp" )
2701-add_definitions ( -DSOCKET_DEMANGLER="${CMAKE_BINARY_DIR}/socket-demangler" )
2702+add_definitions ( -DSOCKET_DEMANGLER="${CMAKE_BINARY_DIR}/utils/socket-demangler" )
2703 add_definitions ( -DSOCKET_DEMANGLER_INSTALL="${pkglibexecdir}/socket-demangler" )
2704 add_definitions ( -DSOCKET_TOOL="${CMAKE_CURRENT_BINARY_DIR}/socket-tool" )
2705 add_definitions ( -DSNAP_BASEDIR="${CMAKE_CURRENT_SOURCE_DIR}/snap-basedir" )
2706@@ -46,7 +38,7 @@
2707 add_executable (libual-cpp-test
2708 libual-cpp-test.cc
2709 mir-mock.cpp)
2710-target_link_libraries (libual-cpp-test gtest_main ${GTEST_MAIN_LIBRARIES} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} launcher-static)
2711+target_link_libraries (libual-cpp-test gtest_main ${GMOCK_LIBRARIES} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} launcher-static)
2712
2713 add_executable (data-spew
2714 data-spew.c)
2715@@ -122,12 +114,6 @@
2716
2717 file(COPY data DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
2718
2719-# Desktop Hook Test
2720-
2721-configure_file ("click-desktop-hook-db/test.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/click-desktop-hook-db/test.conf" @ONLY)
2722-configure_file ("desktop-hook-test.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/desktop-hook-test.sh" @ONLY)
2723-add_test (desktop-hook-test desktop-hook-test.sh)
2724-
2725 # XMir helper Test
2726
2727 configure_file ("xmir-helper-test.in" "${CMAKE_CURRENT_BINARY_DIR}/xmir-helper-test" @ONLY)
2728@@ -144,6 +130,7 @@
2729 COMMAND clang-format -i -style=file
2730 application-info-desktop.cpp
2731 libual-cpp-test.cc
2732+ libual-test.cc
2733 list-apps.cpp
2734 eventually-fixture.h
2735 info-watcher-zg.cpp
2736
2737=== modified file 'tests/application-info-desktop.cpp'
2738--- tests/application-info-desktop.cpp 2017-02-09 19:43:14 +0000
2739+++ tests/application-info-desktop.cpp 2017-03-21 03:26:40 +0000
2740@@ -408,10 +408,11 @@
2741 .WillOnce(testing::Return(ubuntu::app_launch::Application::Info::Popularity::from_raw(5u)));
2742
2743 auto keyfile = defaultKeyfile();
2744- EXPECT_EQ(5u, ubuntu::app_launch::app_info::Desktop(simpleAppID(), keyfile, "/", {},
2745- ubuntu::app_launch::app_info::DesktopFlags::NONE, registry())
2746- .popularity()
2747- .value());
2748+ EXPECT_EQ(5u,
2749+ ubuntu::app_launch::app_info::Desktop(simpleAppID(), keyfile, "/", {},
2750+ ubuntu::app_launch::app_info::DesktopFlags::NONE, registry())
2751+ .popularity()
2752+ .value());
2753 }
2754
2755 } // anonymous namespace
2756
2757=== modified file 'tests/applications/foo.desktop'
2758--- tests/applications/foo.desktop 2017-01-10 18:41:25 +0000
2759+++ tests/applications/foo.desktop 2017-03-21 03:26:40 +0000
2760@@ -1,7 +1,7 @@
2761 [Desktop Entry]
2762 Name=Foo
2763 Type=Application
2764-Exec=foo
2765+Exec=foo %U
2766 NoDisplay=false
2767 Hidden=false
2768 Terminal=false
2769
2770=== removed directory 'tests/click-app-dir'
2771=== removed directory 'tests/click-app-dir/.click'
2772=== removed directory 'tests/click-app-dir/.click/info'
2773=== removed file 'tests/click-app-dir/.click/info/chatter.robert-ancell.manifest'
2774--- tests/click-app-dir/.click/info/chatter.robert-ancell.manifest 2016-08-23 14:52:49 +0000
2775+++ tests/click-app-dir/.click/info/chatter.robert-ancell.manifest 1970-01-01 00:00:00 +0000
2776@@ -1,8 +0,0 @@
2777-{
2778- "version": "2",
2779- "hooks": {
2780- "chatter": {
2781- "desktop": "chatter.desktop"
2782- }
2783- }
2784-}
2785
2786=== removed file 'tests/click-app-dir/.click/info/com.test.bad-version.manifest'
2787--- tests/click-app-dir/.click/info/com.test.bad-version.manifest 2013-09-24 03:48:52 +0000
2788+++ tests/click-app-dir/.click/info/com.test.bad-version.manifest 1970-01-01 00:00:00 +0000
2789@@ -1,8 +0,0 @@
2790-{
2791- "version": "4.5.6",
2792- "hooks": {
2793- "application": {
2794- "desktop": "application.desktop"
2795- }
2796- }
2797-}
2798
2799=== removed file 'tests/click-app-dir/.click/info/com.test.good.manifest'
2800--- tests/click-app-dir/.click/info/com.test.good.manifest 2014-08-25 20:01:18 +0000
2801+++ tests/click-app-dir/.click/info/com.test.good.manifest 1970-01-01 00:00:00 +0000
2802@@ -1,8 +0,0 @@
2803-{
2804- "version": "1.2.3",
2805- "hooks": {
2806- "application": {
2807- "desktop": "application.desktop"
2808- }
2809- }
2810-}
2811
2812=== removed file 'tests/click-app-dir/.click/info/com.test.mir.manifest'
2813--- tests/click-app-dir/.click/info/com.test.mir.manifest 2015-07-02 02:38:56 +0000
2814+++ tests/click-app-dir/.click/info/com.test.mir.manifest 1970-01-01 00:00:00 +0000
2815@@ -1,11 +0,0 @@
2816-{
2817- "version": "1",
2818- "hooks": {
2819- "mir": {
2820- "desktop": "xmir.desktop"
2821- },
2822- "nomir": {
2823- "desktop": "noxmir.desktop"
2824- }
2825- }
2826-}
2827
2828=== removed file 'tests/click-app-dir/.click/info/com.test.multiple.manifest'
2829--- tests/click-app-dir/.click/info/com.test.multiple.manifest 2014-01-29 02:19:41 +0000
2830+++ tests/click-app-dir/.click/info/com.test.multiple.manifest 1970-01-01 00:00:00 +0000
2831@@ -1,20 +0,0 @@
2832-{
2833- "version": "1.2.3",
2834- "hooks": {
2835- "first": {
2836- "desktop": "application.desktop"
2837- },
2838- "second": {
2839- "desktop": "application.desktop"
2840- },
2841- "third": {
2842- "desktop": "application.desktop"
2843- },
2844- "fourth": {
2845- "desktop": "application.desktop"
2846- },
2847- "fifth": {
2848- "desktop": "application.desktop"
2849- }
2850- }
2851-}
2852
2853=== removed file 'tests/click-app-dir/.click/info/com.test.no-app.manifest'
2854--- tests/click-app-dir/.click/info/com.test.no-app.manifest 2013-09-24 03:48:52 +0000
2855+++ tests/click-app-dir/.click/info/com.test.no-app.manifest 1970-01-01 00:00:00 +0000
2856@@ -1,8 +0,0 @@
2857-{
2858- "version": "1.2.3",
2859- "hooks": {
2860- "no-application": {
2861- "desktop": "application.desktop"
2862- }
2863- }
2864-}
2865
2866=== removed file 'tests/click-app-dir/.click/info/com.test.no-hooks.manifest'
2867--- tests/click-app-dir/.click/info/com.test.no-hooks.manifest 2013-09-24 03:48:52 +0000
2868+++ tests/click-app-dir/.click/info/com.test.no-hooks.manifest 1970-01-01 00:00:00 +0000
2869@@ -1,8 +0,0 @@
2870-{
2871- "version": "1.2.3",
2872- "hookie": {
2873- "application": {
2874- "desktop": "application.desktop"
2875- }
2876- }
2877-}
2878
2879=== removed file 'tests/click-app-dir/.click/info/com.test.no-json.manifest'
2880--- tests/click-app-dir/.click/info/com.test.no-json.manifest 2013-09-24 03:48:52 +0000
2881+++ tests/click-app-dir/.click/info/com.test.no-json.manifest 1970-01-01 00:00:00 +0000
2882@@ -1,5 +0,0 @@
2883-<xmlFile>
2884- <moreData>
2885- Lovin' some data
2886- </moreData>
2887-</xmlFile>
2888
2889=== removed file 'tests/click-app-dir/.click/info/com.test.no-object.manifest'
2890--- tests/click-app-dir/.click/info/com.test.no-object.manifest 2013-09-24 03:48:52 +0000
2891+++ tests/click-app-dir/.click/info/com.test.no-object.manifest 1970-01-01 00:00:00 +0000
2892@@ -1,6 +0,0 @@
2893-[
2894- "foo",
2895- "bar",
2896- 5,
2897- 6
2898-]
2899
2900=== removed file 'tests/click-app-dir/.click/info/com.test.no-version.manifest'
2901--- tests/click-app-dir/.click/info/com.test.no-version.manifest 2013-09-24 03:48:52 +0000
2902+++ tests/click-app-dir/.click/info/com.test.no-version.manifest 1970-01-01 00:00:00 +0000
2903@@ -1,8 +0,0 @@
2904-{
2905- "ver": "1.2.3",
2906- "hooks": {
2907- "application": {
2908- "desktop": "application.desktop"
2909- }
2910- }
2911-}
2912
2913=== removed file 'tests/click-app-dir/application.desktop'
2914--- tests/click-app-dir/application.desktop 2016-07-15 21:51:39 +0000
2915+++ tests/click-app-dir/application.desktop 1970-01-01 00:00:00 +0000
2916@@ -1,6 +0,0 @@
2917-[Desktop Entry]
2918-Version=1.0
2919-Name=Application
2920-Type=Application
2921-Exec=grep
2922-Icon=foo.png
2923
2924=== removed file 'tests/click-app-dir/chatter.desktop'
2925--- tests/click-app-dir/chatter.desktop 2016-04-27 13:44:44 +0000
2926+++ tests/click-app-dir/chatter.desktop 1970-01-01 00:00:00 +0000
2927@@ -1,9 +0,0 @@
2928-[Desktop Entry]
2929-Name=Chatter
2930-Comment=Chat on Internet Relay Chat (IRC) networks
2931-Keywords=irc,online,chat,freenode
2932-Exec=chatter
2933-Icon=chatter.png
2934-Terminal=false
2935-Type=Application
2936-X-Ubuntu-Touch=true
2937
2938=== removed file 'tests/click-app-dir/noxmir.desktop'
2939--- tests/click-app-dir/noxmir.desktop 2016-07-15 19:18:49 +0000
2940+++ tests/click-app-dir/noxmir.desktop 1970-01-01 00:00:00 +0000
2941@@ -1,9 +0,0 @@
2942-[Desktop Entry]
2943-Name=No XMir Needed
2944-Type=Application
2945-Exec=noxmir
2946-NoDisplay=false
2947-Hidden=false
2948-Terminal=false
2949-X-Ubuntu-XMir-Enable=false
2950-Icon=nomir.png
2951
2952=== removed file 'tests/click-app-dir/xmir.desktop'
2953--- tests/click-app-dir/xmir.desktop 2016-07-15 19:18:49 +0000
2954+++ tests/click-app-dir/xmir.desktop 1970-01-01 00:00:00 +0000
2955@@ -1,9 +0,0 @@
2956-[Desktop Entry]
2957-Name=X Application
2958-Type=Application
2959-Exec=xfoo
2960-NoDisplay=false
2961-Hidden=false
2962-Terminal=false
2963-X-Ubuntu-XMir-Enable=true
2964-Icon=xfoo.png
2965
2966=== removed directory 'tests/click-db-dir'
2967=== removed file 'tests/click-db-dir/test.conf.in'
2968--- tests/click-db-dir/test.conf.in 2014-03-07 12:33:01 +0000
2969+++ tests/click-db-dir/test.conf.in 1970-01-01 00:00:00 +0000
2970@@ -1,2 +0,0 @@
2971-[Click Database]
2972-root = @CMAKE_CURRENT_SOURCE_DIR@/click-root-dir
2973
2974=== removed directory 'tests/click-desktop-hook-db'
2975=== removed file 'tests/click-desktop-hook-db/test.conf.in'
2976--- tests/click-desktop-hook-db/test.conf.in 2015-04-06 21:28:13 +0000
2977+++ tests/click-desktop-hook-db/test.conf.in 1970-01-01 00:00:00 +0000
2978@@ -1,2 +0,0 @@
2979-[Click Database]
2980-root = @CMAKE_CURRENT_BINARY_DIR@/click-root-desktop-hook
2981
2982=== removed directory 'tests/click-root-dir'
2983=== removed directory 'tests/click-root-dir/.click'
2984=== removed directory 'tests/click-root-dir/.click/users'
2985=== removed directory 'tests/click-root-dir/.click/users/test-user'
2986=== removed directory 'tests/click-root-dir/.click/users/test-user-4'
2987=== removed symlink 'tests/click-root-dir/.click/users/test-user-4/com.test.good'
2988=== target was u'../../../com.test.good/1.2.4/'
2989=== removed directory 'tests/click-root-dir/.click/users/test-user-5'
2990=== removed symlink 'tests/click-root-dir/.click/users/test-user-5/com.test.good'
2991=== target was u'../../../com.test.good/1.2.5/'
2992=== removed symlink 'tests/click-root-dir/.click/users/test-user/chatter.robert-ancell'
2993=== target was u'../../../chatter.robert-ancell/2/'
2994=== removed symlink 'tests/click-root-dir/.click/users/test-user/com.test.bad-version'
2995=== target was u'../../../com.test.bad-version/1.2.3'
2996=== removed symlink 'tests/click-root-dir/.click/users/test-user/com.test.good'
2997=== target was u'../../../com.test.good/1.2.3'
2998=== removed symlink 'tests/click-root-dir/.click/users/test-user/com.test.mir'
2999=== target was u'../../../com.test.mir/1/'
3000=== removed symlink 'tests/click-root-dir/.click/users/test-user/com.test.multiple'
3001=== target was u'../../../com.test.multiple/1.2.3'
3002=== removed symlink 'tests/click-root-dir/.click/users/test-user/com.test.no-app'
3003=== target was u'../../../com.test.no-app/1.2.3'
3004=== removed symlink 'tests/click-root-dir/.click/users/test-user/com.test.no-hooks'
3005=== target was u'../../../com.test.no-hooks/1.2.3'
3006=== removed symlink 'tests/click-root-dir/.click/users/test-user/com.test.no-json'
3007=== target was u'../../../com.test.no-json/1.2.3'
3008=== removed symlink 'tests/click-root-dir/.click/users/test-user/com.test.no-object'
3009=== target was u'../../../com.test.no-object/1.2.3'
3010=== removed symlink 'tests/click-root-dir/.click/users/test-user/com.test.no-version'
3011=== target was u'../../../com.test.no-version/1.2.3'
3012=== removed directory 'tests/click-root-dir/chatter.robert-ancell'
3013=== removed symlink 'tests/click-root-dir/chatter.robert-ancell/2'
3014=== target was u'../../click-app-dir/'
3015=== removed directory 'tests/click-root-dir/com.test.bad-version'
3016=== removed symlink 'tests/click-root-dir/com.test.bad-version/1.2.3'
3017=== target was u'../../click-app-dir'
3018=== removed directory 'tests/click-root-dir/com.test.good'
3019=== removed symlink 'tests/click-root-dir/com.test.good/1.2.3'
3020=== target was u'../../click-app-dir'
3021=== removed directory 'tests/click-root-dir/com.test.good/1.2.4'
3022=== removed directory 'tests/click-root-dir/com.test.good/1.2.4/.click'
3023=== removed directory 'tests/click-root-dir/com.test.good/1.2.4/.click/info'
3024=== removed file 'tests/click-root-dir/com.test.good/1.2.4/.click/info/com.test.good.manifest'
3025--- tests/click-root-dir/com.test.good/1.2.4/.click/info/com.test.good.manifest 2015-06-03 20:26:39 +0000
3026+++ tests/click-root-dir/com.test.good/1.2.4/.click/info/com.test.good.manifest 1970-01-01 00:00:00 +0000
3027@@ -1,8 +0,0 @@
3028-{
3029- "version": "1.2.4",
3030- "hooks": {
3031- "application": {
3032- "desktop": "application.desktop"
3033- }
3034- }
3035-}
3036
3037=== removed symlink 'tests/click-root-dir/com.test.good/1.2.4/application.desktop'
3038=== target was u'../../../click-app-dir/application.desktop'
3039=== removed directory 'tests/click-root-dir/com.test.good/1.2.5'
3040=== removed directory 'tests/click-root-dir/com.test.good/1.2.5/.click'
3041=== removed directory 'tests/click-root-dir/com.test.good/1.2.5/.click/info'
3042=== removed file 'tests/click-root-dir/com.test.good/1.2.5/.click/info/com.test.good.manifest'
3043--- tests/click-root-dir/com.test.good/1.2.5/.click/info/com.test.good.manifest 2015-06-03 20:26:39 +0000
3044+++ tests/click-root-dir/com.test.good/1.2.5/.click/info/com.test.good.manifest 1970-01-01 00:00:00 +0000
3045@@ -1,8 +0,0 @@
3046-{
3047- "version": "1.2.5",
3048- "hooks": {
3049- "application": {
3050- "desktop": "application.desktop"
3051- }
3052- }
3053-}
3054
3055=== removed symlink 'tests/click-root-dir/com.test.good/1.2.5/application.desktop'
3056=== target was u'../../../click-app-dir/application.desktop'
3057=== removed directory 'tests/click-root-dir/com.test.mir'
3058=== removed symlink 'tests/click-root-dir/com.test.mir/1'
3059=== target was u'../../click-app-dir/'
3060=== removed directory 'tests/click-root-dir/com.test.multiple'
3061=== removed symlink 'tests/click-root-dir/com.test.multiple/1.2.3'
3062=== target was u'../../click-app-dir'
3063=== removed directory 'tests/click-root-dir/com.test.no-app'
3064=== removed symlink 'tests/click-root-dir/com.test.no-app/1.2.3'
3065=== target was u'../../click-app-dir'
3066=== removed directory 'tests/click-root-dir/com.test.no-hooks'
3067=== removed symlink 'tests/click-root-dir/com.test.no-hooks/1.2.3'
3068=== target was u'../../click-app-dir'
3069=== removed directory 'tests/click-root-dir/com.test.no-json'
3070=== removed symlink 'tests/click-root-dir/com.test.no-json/1.2.3'
3071=== target was u'../../click-app-dir'
3072=== removed directory 'tests/click-root-dir/com.test.no-object'
3073=== removed symlink 'tests/click-root-dir/com.test.no-object/1.2.3'
3074=== target was u'../../click-app-dir'
3075=== removed directory 'tests/click-root-dir/com.test.no-version'
3076=== removed symlink 'tests/click-root-dir/com.test.no-version/1.2.3'
3077=== target was u'../../click-app-dir'
3078=== removed file 'tests/desktop-hook-test.sh.in'
3079--- tests/desktop-hook-test.sh.in 2015-06-03 20:36:34 +0000
3080+++ tests/desktop-hook-test.sh.in 1970-01-01 00:00:00 +0000
3081@@ -1,129 +0,0 @@
3082-#!/bin/bash -e
3083-
3084-TEST_DIR=@CMAKE_CURRENT_BINARY_DIR@
3085-SRC_DIR=@CMAKE_CURRENT_SOURCE_DIR@
3086-
3087-CACHE_DIR=${TEST_DIR}/desktop-hook-test-click-dir
3088-CLICK_DIR=${CACHE_DIR}/ubuntu-app-launch/desktop/
3089-
3090-DATA_DIR=${TEST_DIR}/desktop-hook-test-apps-dir
3091-APPS_DIR=${DATA_DIR}/applications/
3092-
3093-# Remove the old directories
3094-rm -rf ${CACHE_DIR}
3095-rm -rf ${DATA_DIR}
3096-rm -f @CMAKE_CURRENT_BINARY_DIR@/click-root-desktop-hook
3097-
3098-# Copy our source applications
3099-mkdir -p ${CLICK_DIR}
3100-cp ${SRC_DIR}/link-farm/* ${CLICK_DIR}
3101-
3102-# Build our root dir
3103-ln -s @CMAKE_CURRENT_SOURCE_DIR@/click-root-dir @CMAKE_CURRENT_BINARY_DIR@/click-root-desktop-hook
3104-
3105-# Setup the environment
3106-export XDG_CACHE_HOME=${CACHE_DIR}
3107-export XDG_DATA_HOME=${DATA_DIR}
3108-export TEST_CLICK_DB=@CMAKE_CURRENT_BINARY_DIR@/click-desktop-hook-db
3109-export TEST_CLICK_USER=test-user
3110-
3111-# Run the tool
3112-@CMAKE_BINARY_DIR@/desktop-hook
3113-
3114-# Check that the files exist
3115-
3116-if [ ! -e ${APPS_DIR}/com.test.good_application_1.2.3.desktop ] ; then
3117- echo "Desktop file not created for: com.test.good_application_1.2.3"
3118- exit 1
3119-fi
3120-
3121-if [ ! -e ${APPS_DIR}/com.test.multiple_first_1.2.3.desktop ] ; then
3122- echo "Desktop file not created for: com.test.multiple_first_1.2.3"
3123- exit 1
3124-fi
3125-
3126-# Verify we're adding containment to them
3127-
3128-grep "^Exec=aa-exec-click -p com.test.good_application_1.2.3 --" ${APPS_DIR}/com.test.good_application_1.2.3.desktop > /dev/null
3129-grep "^Exec=aa-exec-click -p com.test.multiple_first_1.2.3 --" ${APPS_DIR}/com.test.multiple_first_1.2.3.desktop > /dev/null
3130-
3131-# Make sure they have the AppID (people started using it) :-/
3132-
3133-grep "^X-Ubuntu-Application-ID=com.test.good_application_1.2.3" ${APPS_DIR}/com.test.good_application_1.2.3.desktop > /dev/null
3134-grep "^X-Ubuntu-Application-ID=com.test.multiple_first_1.2.3" ${APPS_DIR}/com.test.multiple_first_1.2.3.desktop > /dev/null
3135-
3136-# Remove a file and ensure it gets recreated
3137-
3138-rm -f ${APPS_DIR}/com.test.good_application_1.2.3.desktop
3139-@CMAKE_BINARY_DIR@/desktop-hook
3140-
3141-if [ ! -e ${APPS_DIR}/com.test.good_application_1.2.3.desktop ] ; then
3142- echo "Desktop file not recreated for: com.test.good_application_1.2.3"
3143- exit 1
3144-fi
3145-
3146-# Remove a source file and make sure it goes
3147-
3148-rm -f ${CLICK_DIR}/com.test.multiple_first_1.2.3.desktop
3149-@CMAKE_BINARY_DIR@/desktop-hook
3150-if [ -e ${APPS_DIR}/com.test.multiple_first_1.2.3.desktop ] ; then
3151- echo "Not cleaning up deleted files"
3152- exit 1
3153-fi
3154-
3155-# Verify the good file is in the desktop hook root
3156-grep "^X-Ubuntu-UAL-Source-Desktop=@CMAKE_CURRENT_BINARY_DIR@/click-root-desktop-hook" ${APPS_DIR}/com.test.good_application_1.2.3.desktop > /dev/null
3157-
3158-# Remove our root
3159-rm -f @CMAKE_CURRENT_BINARY_DIR@/click-root-desktop-hook
3160-
3161-# Point to the new db and run
3162-export TEST_CLICK_DB=@CMAKE_CURRENT_BINARY_DIR@/click-db-dir
3163-@CMAKE_BINARY_DIR@/desktop-hook
3164-
3165-# Verify that we have the file and it's in the new root
3166-if [ ! -e ${APPS_DIR}/com.test.good_application_1.2.3.desktop ] ; then
3167- echo "Desktop file not created for: com.test.good_application_1.2.3"
3168- exit 1
3169-fi
3170-
3171-grep "^X-Ubuntu-UAL-Source-Desktop=@CMAKE_CURRENT_SOURCE_DIR@/click-root-dir" ${APPS_DIR}/com.test.good_application_1.2.3.desktop > /dev/null
3172-
3173-# Upgrade the good application
3174-
3175-mv ${CLICK_DIR}/com.test.good_application_1.2.3.desktop ${CLICK_DIR}/com.test.good_application_1.2.4.desktop
3176-export TEST_CLICK_USER=test-user-4
3177-
3178-@CMAKE_BINARY_DIR@/desktop-hook
3179-
3180-if [ -e ${APPS_DIR}/com.test.good_application_1.2.3.desktop ] ; then
3181- echo "Desktop file not removed for: com.test.good_application_1.2.3"
3182- exit 1
3183-fi
3184-
3185-if [ ! -e ${APPS_DIR}/com.test.good_application_1.2.4.desktop ] ; then
3186- echo "Desktop file not created for: com.test.good_application_1.2.4"
3187- exit 1
3188-fi
3189-
3190-# Upgrade the good application, but don't have a Source line like in an upgrade scenario
3191-
3192-mv ${CLICK_DIR}/com.test.good_application_1.2.4.desktop ${CLICK_DIR}/com.test.good_application_1.2.5.desktop
3193-cat ${APPS_DIR}/com.test.good_application_1.2.4.desktop | grep -v "^X-Ubuntu-UAL-Source-Desktop" > ${APPS_DIR}/com.test.good_application_1.2.4.desktop.tmp
3194-rm ${APPS_DIR}/com.test.good_application_1.2.4.desktop
3195-mv ${APPS_DIR}/com.test.good_application_1.2.4.desktop.tmp ${APPS_DIR}/com.test.good_application_1.2.4.desktop
3196-
3197-export TEST_CLICK_USER=test-user-5
3198-
3199-
3200-@CMAKE_BINARY_DIR@/desktop-hook
3201-
3202-if [ -e ${APPS_DIR}/com.test.good_application_1.2.4.desktop ] ; then
3203- echo "Desktop file not removed for: com.test.good_application_1.2.4"
3204- exit 1
3205-fi
3206-
3207-if [ ! -e ${APPS_DIR}/com.test.good_application_1.2.5.desktop ] ; then
3208- echo "Desktop file not created for: com.test.good_application_1.2.5"
3209- exit 1
3210-fi
3211
3212=== modified file 'tests/helper-handshake-test.cc'
3213--- tests/helper-handshake-test.cc 2016-12-14 21:23:09 +0000
3214+++ tests/helper-handshake-test.cc 2017-03-21 03:26:40 +0000
3215@@ -22,7 +22,7 @@
3216 #include <gio/gio.h>
3217
3218 extern "C" {
3219-#include "../helpers.h"
3220+#include "utils.h"
3221 }
3222
3223 class HelperHandshakeTest : public ::testing::Test
3224
3225=== modified file 'tests/helper-test.cc'
3226--- tests/helper-test.cc 2017-03-21 03:26:39 +0000
3227+++ tests/helper-test.cc 2017-03-21 03:26:40 +0000
3228@@ -23,7 +23,7 @@
3229 #include <gio/gio.h>
3230
3231 extern "C" {
3232-#include "../helpers.h"
3233+#include "utils.h"
3234 }
3235
3236 class HelperTest : public ::testing::Test
3237@@ -78,7 +78,7 @@
3238 g_array_free(output, TRUE);
3239
3240 /* Little u with a single URL */
3241- output = desktop_exec_parse("foo %u", "http://ubuntu.com");
3242+ output = desktop_exec_parse("foo %U", "http://ubuntu.com");
3243 ASSERT_EQ(guint(2), output->len);
3244 ASSERT_STREQ(g_array_index(output, gchar *, 0), "foo");
3245 ASSERT_STREQ(g_array_index(output, gchar *, 1), "http://ubuntu.com");
3246@@ -273,7 +273,7 @@
3247 ASSERT_TRUE(g_key_file_load_from_file(keyfile, CMAKE_SOURCE_DIR "/applications/foo.desktop", G_KEY_FILE_NONE, NULL));
3248 exec = desktop_to_exec(keyfile, "");
3249 ASSERT_TRUE(exec != NULL);
3250- ASSERT_STREQ(exec, "foo");
3251+ ASSERT_STREQ(exec, "foo %U");
3252 g_free(exec);
3253 g_key_file_free(keyfile);
3254
3255@@ -316,42 +316,3 @@
3256 return;
3257 }
3258
3259-TEST_F(HelperTest, ManifestToDesktop)
3260-{
3261- gchar * desktop = NULL;
3262-
3263- g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE);
3264- g_setenv("TEST_CLICK_USER", "test-user", TRUE);
3265-
3266- desktop = manifest_to_desktop(CMAKE_SOURCE_DIR "/click-app-dir/", "com.test.good_application_1.2.3");
3267- ASSERT_STREQ(CMAKE_SOURCE_DIR "/click-app-dir/application.desktop", desktop);
3268- g_free(desktop);
3269- desktop = NULL;
3270-
3271- desktop = manifest_to_desktop(CMAKE_SOURCE_DIR "/click-app-dir/", "com.test.bad-version_application_1.2.3");
3272- ASSERT_TRUE(desktop == NULL);
3273-
3274- desktop = manifest_to_desktop(CMAKE_SOURCE_DIR "/click-app-dir/", "com.test.no-app_application_1.2.3");
3275- ASSERT_TRUE(desktop == NULL);
3276-
3277- desktop = manifest_to_desktop(CMAKE_SOURCE_DIR "/click-app-dir/", "com.test.no-hooks_application_1.2.3");
3278- ASSERT_TRUE(desktop == NULL);
3279-
3280- desktop = manifest_to_desktop(CMAKE_SOURCE_DIR "/click-app-dir/", "com.test.no-version_application_1.2.3");
3281- ASSERT_TRUE(desktop == NULL);
3282-
3283- desktop = manifest_to_desktop(CMAKE_SOURCE_DIR "/click-app-dir/", "com.test.no-exist_application_1.2.3");
3284- ASSERT_TRUE(desktop == NULL);
3285-
3286- desktop = manifest_to_desktop(CMAKE_SOURCE_DIR "/click-app-dir/", "com.test.no-json_application_1.2.3");
3287- ASSERT_TRUE(desktop == NULL);
3288-
3289- desktop = manifest_to_desktop(CMAKE_SOURCE_DIR "/click-app-dir/", "com.test.no-object_application_1.2.3");
3290- ASSERT_TRUE(desktop == NULL);
3291-
3292- /* Bad App ID */
3293- desktop = manifest_to_desktop(CMAKE_SOURCE_DIR "/click-app-dir/", "com.test.good_application-1.2.3");
3294- ASSERT_TRUE(desktop == NULL);
3295-
3296- return;
3297-}
3298
3299=== modified file 'tests/libertine-service.h'
3300--- tests/libertine-service.h 2017-02-15 15:03:41 +0000
3301+++ tests/libertine-service.h 2017-03-21 03:26:40 +0000
3302@@ -42,6 +42,7 @@
3303
3304 wait = dbus_test_task_new();
3305 dbus_test_task_set_wait_for(wait, "com.canonical.libertine.Service");
3306+ dbus_test_task_set_name(wait, "lib-wait");
3307 }
3308
3309 ~LibertineService()
3310
3311=== modified file 'tests/libual-cpp-test.cc'
3312--- tests/libual-cpp-test.cc 2017-03-21 03:26:39 +0000
3313+++ tests/libual-cpp-test.cc 2017-03-21 03:26:40 +0000
3314@@ -31,6 +31,7 @@
3315
3316 #include "application.h"
3317 #include "glib-thread.h"
3318+#include "helper-impl.h"
3319 #include "helper.h"
3320 #include "jobs-base.h"
3321 #include "registry.h"
3322@@ -39,17 +40,15 @@
3323 #include "eventually-fixture.h"
3324 #include "libertine-service.h"
3325 #include "mir-mock.h"
3326+#include "registry-mock.h"
3327+#include "snapd-mock.h"
3328 #include "spew-master.h"
3329 #include "systemd-mock.h"
3330 #include "zg-mock.h"
3331
3332-#ifdef ENABLE_SNAPPY
3333-#include "snapd-mock.h"
3334-
3335 #define LOCAL_SNAPD_TEST_SOCKET (SNAPD_TEST_SOCKET "-libual-cpp-test")
3336-#endif
3337
3338-#define CGROUP_DIR (CMAKE_BINARY_DIR "/systemd-cgroups")
3339+#define CGROUP_DIR (CMAKE_BINARY_DIR "/systemd-libual-cpp-cgroups")
3340
3341 class LibUAL : public EventuallyFixture
3342 {
3343@@ -99,6 +98,7 @@
3344 const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance,
3345 std::function<void(bool)> reply) override
3346 {
3347+ g_debug("Manager Mock: Starting Request: %s", std::string(app->appId()).c_str());
3348 thread.timeout(startingTimeout, [this, app, instance, reply]() {
3349 lastStartedApp = app->appId();
3350 reply(startingResponse);
3351@@ -109,6 +109,7 @@
3352 const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance,
3353 std::function<void(bool)> reply) override
3354 {
3355+ g_debug("Manager Mock: Focus Request: %s", std::string(app->appId()).c_str());
3356 thread.timeout(focusTimeout, [this, app, instance, reply]() {
3357 lastFocusedApp = app->appId();
3358 reply(focusResponse);
3359@@ -119,6 +120,7 @@
3360 const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance,
3361 std::function<void(bool)> reply) override
3362 {
3363+ g_debug("Manager Mock: Resume Request: %s", std::string(app->appId()).c_str());
3364 thread.timeout(resumeTimeout, [this, app, instance, reply]() {
3365 lastResumedApp = app->appId();
3366 reply(resumeResponse);
3367@@ -147,24 +149,15 @@
3368
3369 virtual void SetUp()
3370 {
3371- /* Click DB test mode */
3372- g_setenv("TEST_CLICK_DB", CMAKE_BINARY_DIR "/click-db-dir", TRUE);
3373- g_setenv("TEST_CLICK_USER", "test-user", TRUE);
3374-
3375- gchar* linkfarmpath = g_build_filename(CMAKE_SOURCE_DIR, "link-farm", NULL);
3376- g_setenv("UBUNTU_APP_LAUNCH_LINK_FARM", linkfarmpath, TRUE);
3377- g_free(linkfarmpath);
3378-
3379 g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);
3380 g_setenv("XDG_CACHE_HOME", CMAKE_SOURCE_DIR "/libertine-data", TRUE);
3381 g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE);
3382
3383-#ifdef ENABLE_SNAPPY
3384 g_setenv("UBUNTU_APP_LAUNCH_SNAPD_SOCKET", LOCAL_SNAPD_TEST_SOCKET, TRUE);
3385 g_setenv("UBUNTU_APP_LAUNCH_SNAP_BASEDIR", SNAP_BASEDIR, TRUE);
3386 g_setenv("UBUNTU_APP_LAUNCH_DISABLE_SNAPD_TIMEOUT", "You betcha!", TRUE);
3387 g_unlink(LOCAL_SNAPD_TEST_SOCKET);
3388-#endif
3389+
3390 g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH", "/this/should/not/exist", TRUE);
3391 /* Setting the cgroup temp directory */
3392 g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_CGROUP_ROOT", CGROUP_DIR, TRUE);
3393@@ -175,12 +168,11 @@
3394
3395 systemd = std::make_shared<SystemdMock>(
3396 std::list<SystemdMock::Instance>{
3397- {"application-click", "com.test.good_application_1.2.3", {}, getpid(), {100, 200, 300}},
3398 {"application-snap", "unity8-package_foo_x123", {}, getpid(), {100, 200, 300}},
3399 {"application-legacy", "multiple", "2342345", 5678, {100, 200, 300}},
3400- {"application-legacy", "single", {}, 5678, {100, 200, 300}},
3401- {"helper", "com.foo_bar_43.23.12", {}, 1, {100, 200, 300}},
3402- {"helper", "com.bar_foo_8432.13.1", "24034582324132", 1, {100, 200, 300}}},
3403+ {"application-legacy", "single", {}, getpid(), {getpid()}},
3404+ {"untrusted-helper", "com.foo_bar_43.23.12", {}, 1, {100, 200, 300}},
3405+ {"untrusted-helper", "com.bar_foo_8432.13.1", "24034582324132", 1, {100, 200, 300}}},
3406 CGROUP_DIR);
3407
3408 /* Put it together */
3409@@ -197,9 +189,6 @@
3410 g_dbus_connection_set_exit_on_close(bus, FALSE);
3411 g_object_add_weak_pointer(G_OBJECT(bus), (gpointer*)&bus);
3412
3413- /* Make sure we pretend the CG manager is just on our bus */
3414- g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_SESSION_BUS", "YES", TRUE);
3415-
3416 registry = std::make_shared<ubuntu::app_launch::Registry>();
3417
3418 manager = std::make_shared<ManagerMock>();
3419@@ -226,9 +215,7 @@
3420
3421 ASSERT_EVENTUALLY_EQ(nullptr, bus);
3422
3423-#ifdef ENABLE_SNAPPY
3424 g_unlink(LOCAL_SNAPD_TEST_SOCKET);
3425-#endif
3426 }
3427
3428 static std::string find_env(std::set<std::string>& envs, std::string var)
3429@@ -266,6 +253,55 @@
3430 }
3431 return split_env(val).second == value;
3432 }
3433+
3434+ void storeForApp(const ubuntu::app_launch::AppID& appid, const std::string& jobtype, const std::string& instanceid)
3435+ {
3436+ auto store = storeForHelper(appid);
3437+
3438+ ON_CALL(*store, list(testing::_))
3439+ .WillByDefault(testing::Return(std::list<std::shared_ptr<ubuntu::app_launch::Application>>{}));
3440+
3441+ auto app = std::make_shared<MockApp>(appid, registry);
3442+ ON_CALL(*store, create(appid, testing::_)).WillByDefault(testing::Return(app));
3443+
3444+ if (!instanceid.empty())
3445+ {
3446+ std::vector<ubuntu::app_launch::Application::URL> urls;
3447+ auto inst = std::make_shared<MockInst>(appid, jobtype, instanceid, urls, registry);
3448+ ON_CALL(*app, findInstance(instanceid)).WillByDefault(testing::Return(inst));
3449+ ON_CALL(*app, launch(testing::_)).WillByDefault(testing::Return(inst));
3450+ ON_CALL(*app, launchTest(testing::_)).WillByDefault(testing::Return(inst));
3451+ ON_CALL(*app, hasInstances()).WillByDefault(testing::Return(true));
3452+ }
3453+ else
3454+ {
3455+ ON_CALL(*app, hasInstances()).WillByDefault(testing::Return(false));
3456+ }
3457+
3458+ std::list<std::shared_ptr<ubuntu::app_launch::app_store::Base>> list;
3459+ list.push_back(store);
3460+ registry->impl->setAppStores(list);
3461+ }
3462+
3463+ std::shared_ptr<MockStore> storeForHelper(const ubuntu::app_launch::AppID& appid)
3464+ {
3465+ /* Setup a store for looking up the AppID */
3466+ auto store = std::make_shared<MockStore>();
3467+
3468+ ON_CALL(*store, verifyPackage(appid.package, testing::_)).WillByDefault(testing::Return(true));
3469+ ON_CALL(*store, verifyAppname(appid.package, appid.appname, testing::_)).WillByDefault(testing::Return(true));
3470+ ON_CALL(*store, findAppname(appid.package, testing::_, testing::_))
3471+ .WillByDefault(testing::Return(appid.appname));
3472+ ON_CALL(*store, findVersion(appid.package, appid.appname, testing::_))
3473+ .WillByDefault(testing::Return(appid.version));
3474+ ON_CALL(*store, hasAppId(appid, testing::_)).WillByDefault(testing::Return(true));
3475+
3476+ std::list<std::shared_ptr<ubuntu::app_launch::app_store::Base>> list;
3477+ list.push_back(store);
3478+ registry->impl->setAppStores(list);
3479+
3480+ return store;
3481+ }
3482 };
3483
3484 #define TASK_STATE(task) \
3485@@ -274,7 +310,6 @@
3486 [&task] { return dbus_test_task_get_state(DBUS_TEST_TASK(task)); } \
3487 }
3488
3489-#ifdef ENABLE_SNAPPY
3490 /* Snapd mock data */
3491 static std::pair<std::string, std::string> interfaces{
3492 "GET /v2/interfaces HTTP/1.1\r\nHost: snapd\r\nAccept: */*\r\n\r\n",
3493@@ -286,8 +321,8 @@
3494 "unity8-package", "active", "app", "1.2.3.4", "x123", {"foo", "single", "xmir", "noxmir"})))};
3495 static std::pair<std::string, std::string> helloPackage{
3496 "GET /v2/snaps/hello HTTP/1.1\r\nHost: snapd\r\nAccept: */*\r\n\r\n",
3497- SnapdMock::httpJsonResponse(SnapdMock::snapdOkay(SnapdMock::packageJson(
3498- "hello", "active", "app", "1.0", "1", {"hello"})))};
3499+ SnapdMock::httpJsonResponse(
3500+ SnapdMock::snapdOkay(SnapdMock::packageJson("hello", "active", "app", "1.0", "1", {"hello"})))};
3501
3502 TEST_F(LibUAL, ApplicationIdSnap)
3503 {
3504@@ -356,23 +391,20 @@
3505
3506 auto appid = ubuntu::app_launch::AppID::parse("hello_hello_1");
3507
3508- try {
3509- ubuntu::app_launch::Application::create(appid, registry);
3510- FAIL() << "Expected std::runtime_error";
3511- }
3512- catch(std::runtime_error const & err) {
3513- EXPECT_EQ(err.what(), std::string("Graphical interface not found for: hello_hello_1"));
3514- }
3515- catch(...) {
3516- FAIL() << "Expected std::runtime_error";
3517- }
3518+ EXPECT_THROW(ubuntu::app_launch::Application::create(appid, registry), std::runtime_error);
3519 }
3520-#endif
3521
3522 TEST_F(LibUAL, ApplicationPid)
3523 {
3524+ /* Queries come in threes, apparently */
3525+ SnapdMock snapd{LOCAL_SNAPD_TEST_SOCKET,
3526+ {
3527+ u8Package, interfaces, u8Package, /* App */
3528+ }};
3529+ registry = std::make_shared<ubuntu::app_launch::Registry>();
3530+
3531 /* Check bad params */
3532- auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
3533+ auto appid = ubuntu::app_launch::AppID::parse("unity8-package_foo_x123");
3534 auto app = ubuntu::app_launch::Application::create(appid, registry);
3535
3536 ASSERT_LT(0, int(app->instances().size()));
3537@@ -393,93 +425,143 @@
3538 ASSERT_LT(0, int(instances.size()));
3539 EXPECT_EQ(5678, instances[0]->primaryPid());
3540
3541- /* Look at the full PID list from CG Manager */
3542- DbusTestDbusMockObject* cgobject = dbus_test_dbus_mock_get_object(cgmock, "/org/linuxcontainers/cgmanager",
3543- "org.linuxcontainers.cgmanager0_0", NULL);
3544- const DbusTestDbusMockCall* calls = NULL;
3545- guint len = 0;
3546-
3547- /* Click in the set */
3548- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(cgmock, cgobject, NULL));
3549- EXPECT_TRUE(app->instances()[0]->hasPid(100));
3550- calls = dbus_test_dbus_mock_object_get_method_calls(cgmock, cgobject, "GetTasksRecursive", &len, NULL);
3551- ASSERT_EQ(1u, len);
3552- EXPECT_STREQ("GetTasksRecursive", calls->name);
3553- EXPECT_TRUE(g_variant_equal(
3554- calls->params, g_variant_new("(ss)", "freezer", "upstart/application-click-com.test.good_application_1.2.3")));
3555- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(cgmock, cgobject, NULL));
3556-
3557- /* Click out of the set */
3558- EXPECT_FALSE(app->instances()[0]->hasPid(101));
3559- calls = dbus_test_dbus_mock_object_get_method_calls(cgmock, cgobject, "GetTasksRecursive", &len, NULL);
3560- ASSERT_EQ(1u, len);
3561- EXPECT_STREQ("GetTasksRecursive", calls->name);
3562- EXPECT_TRUE(g_variant_equal(
3563- calls->params, g_variant_new("(ss)", "freezer", "upstart/application-click-com.test.good_application_1.2.3")));
3564- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(cgmock, cgobject, NULL));
3565-
3566 /* Legacy Single Instance */
3567 auto singleappid = ubuntu::app_launch::AppID::find(registry, "single");
3568 auto singleapp = ubuntu::app_launch::Application::create(singleappid, registry);
3569
3570 ASSERT_LT(0, int(singleapp->instances().size()));
3571- EXPECT_TRUE(singleapp->instances()[0]->hasPid(100));
3572-
3573- calls = dbus_test_dbus_mock_object_get_method_calls(cgmock, cgobject, "GetTasksRecursive", &len, NULL);
3574- ASSERT_EQ(1u, len);
3575- EXPECT_STREQ("GetTasksRecursive", calls->name);
3576- EXPECT_TRUE(g_variant_equal(calls->params, g_variant_new("(ss)", "freezer", "upstart/application-legacy-single-")));
3577- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(cgmock, cgobject, NULL));
3578-
3579- /* Legacy Multi Instance */
3580- EXPECT_TRUE(multiapp->instances()[0]->hasPid(100));
3581- calls = dbus_test_dbus_mock_object_get_method_calls(cgmock, cgobject, "GetTasksRecursive", &len, NULL);
3582- ASSERT_EQ(1u, len);
3583- EXPECT_STREQ("GetTasksRecursive", calls->name);
3584- EXPECT_TRUE(g_variant_equal(calls->params,
3585- g_variant_new("(ss)", "freezer", "upstart/application-legacy-multiple-2342345")));
3586- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(cgmock, cgobject, NULL));
3587+ EXPECT_TRUE(singleapp->instances()[0]->hasPid(getpid()));
3588 }
3589
3590 TEST_F(LibUAL, ApplicationId)
3591 {
3592- g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE);
3593- g_setenv("TEST_CLICK_USER", "test-user", TRUE);
3594+ auto mockstore = std::make_shared<MockStore>();
3595+ registry =
3596+ std::make_shared<RegistryMock>(std::list<std::shared_ptr<ubuntu::app_launch::app_store::Base>>{mockstore});
3597+
3598+ EXPECT_CALL(*mockstore, verifyPackage(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"), testing::_))
3599+ .WillOnce(testing::Return(true));
3600+ EXPECT_CALL(*mockstore, verifyAppname(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
3601+ ubuntu::app_launch::AppID::AppName::from_raw("application"), testing::_))
3602+ .WillOnce(testing::Return(true));
3603+ EXPECT_CALL(*mockstore, findVersion(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
3604+ ubuntu::app_launch::AppID::AppName::from_raw("application"), testing::_))
3605+ .WillOnce(testing::Return(ubuntu::app_launch::AppID::Version::from_raw("1.2.3")));
3606
3607 /* Test with current-user-version, should return the version in the manifest */
3608 EXPECT_EQ("com.test.good_application_1.2.3",
3609 (std::string)ubuntu::app_launch::AppID::discover(registry, "com.test.good", "application"));
3610
3611+ EXPECT_CALL(*mockstore, verifyPackage(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"), testing::_))
3612+ .WillOnce(testing::Return(true));
3613+ EXPECT_CALL(*mockstore, verifyAppname(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
3614+ ubuntu::app_launch::AppID::AppName::from_raw("application"), testing::_))
3615+ .WillOnce(testing::Return(true));
3616+ EXPECT_CALL(*mockstore,
3617+ hasAppId(ubuntu::app_launch::AppID{ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
3618+ ubuntu::app_launch::AppID::AppName::from_raw("application"),
3619+ ubuntu::app_launch::AppID::Version::from_raw("1.2.4")},
3620+ testing::_))
3621+ .WillOnce(testing::Return(true));
3622+
3623 /* Test with version specified, shouldn't even read the manifest */
3624 EXPECT_EQ("com.test.good_application_1.2.4",
3625 (std::string)ubuntu::app_launch::AppID::discover(registry, "com.test.good", "application", "1.2.4"));
3626
3627+ EXPECT_CALL(*mockstore, verifyPackage(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"), testing::_))
3628+ .WillOnce(testing::Return(true));
3629+ EXPECT_CALL(*mockstore, findAppname(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
3630+ ubuntu::app_launch::AppID::ApplicationWildcard::FIRST_LISTED, testing::_))
3631+ .WillOnce(testing::Return(ubuntu::app_launch::AppID::AppName::from_raw("application")));
3632+ EXPECT_CALL(*mockstore, findVersion(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
3633+ ubuntu::app_launch::AppID::AppName::from_raw("application"), testing::_))
3634+ .WillOnce(testing::Return(ubuntu::app_launch::AppID::Version::from_raw("1.2.3")));
3635+
3636 /* Test with out a version or app, should return the version in the manifest */
3637 EXPECT_EQ("com.test.good_application_1.2.3",
3638 (std::string)ubuntu::app_launch::AppID::discover(registry, "com.test.good", "first-listed-app",
3639 "current-user-version"));
3640
3641 /* Make sure we can select the app from a list correctly */
3642+ EXPECT_CALL(*mockstore,
3643+ verifyPackage(ubuntu::app_launch::AppID::Package::from_raw("com.test.multiple"), testing::_))
3644+ .WillOnce(testing::Return(true));
3645+ EXPECT_CALL(*mockstore, findAppname(ubuntu::app_launch::AppID::Package::from_raw("com.test.multiple"),
3646+ ubuntu::app_launch::AppID::ApplicationWildcard::FIRST_LISTED, testing::_))
3647+ .WillOnce(testing::Return(ubuntu::app_launch::AppID::AppName::from_raw("first")));
3648+ EXPECT_CALL(*mockstore, findVersion(ubuntu::app_launch::AppID::Package::from_raw("com.test.multiple"),
3649+ ubuntu::app_launch::AppID::AppName::from_raw("first"), testing::_))
3650+ .WillOnce(testing::Return(ubuntu::app_launch::AppID::Version::from_raw("1.2.3")));
3651 EXPECT_EQ("com.test.multiple_first_1.2.3",
3652 (std::string)ubuntu::app_launch::AppID::discover(
3653 registry, "com.test.multiple", ubuntu::app_launch::AppID::ApplicationWildcard::FIRST_LISTED));
3654+
3655+ EXPECT_CALL(*mockstore,
3656+ verifyPackage(ubuntu::app_launch::AppID::Package::from_raw("com.test.multiple"), testing::_))
3657+ .WillOnce(testing::Return(true));
3658+ EXPECT_CALL(*mockstore, findAppname(ubuntu::app_launch::AppID::Package::from_raw("com.test.multiple"),
3659+ ubuntu::app_launch::AppID::ApplicationWildcard::FIRST_LISTED, testing::_))
3660+ .WillOnce(testing::Return(ubuntu::app_launch::AppID::AppName::from_raw("first")));
3661+ EXPECT_CALL(*mockstore, findVersion(ubuntu::app_launch::AppID::Package::from_raw("com.test.multiple"),
3662+ ubuntu::app_launch::AppID::AppName::from_raw("first"), testing::_))
3663+ .WillOnce(testing::Return(ubuntu::app_launch::AppID::Version::from_raw("1.2.3")));
3664 EXPECT_EQ("com.test.multiple_first_1.2.3",
3665 (std::string)ubuntu::app_launch::AppID::discover(registry, "com.test.multiple"));
3666+
3667+ EXPECT_CALL(*mockstore,
3668+ verifyPackage(ubuntu::app_launch::AppID::Package::from_raw("com.test.multiple"), testing::_))
3669+ .WillOnce(testing::Return(true));
3670+ EXPECT_CALL(*mockstore, findAppname(ubuntu::app_launch::AppID::Package::from_raw("com.test.multiple"),
3671+ ubuntu::app_launch::AppID::ApplicationWildcard::LAST_LISTED, testing::_))
3672+ .WillOnce(testing::Return(ubuntu::app_launch::AppID::AppName::from_raw("fifth")));
3673+ EXPECT_CALL(*mockstore, findVersion(ubuntu::app_launch::AppID::Package::from_raw("com.test.multiple"),
3674+ ubuntu::app_launch::AppID::AppName::from_raw("fifth"), testing::_))
3675+ .WillOnce(testing::Return(ubuntu::app_launch::AppID::Version::from_raw("1.2.3")));
3676 EXPECT_EQ("com.test.multiple_fifth_1.2.3",
3677 (std::string)ubuntu::app_launch::AppID::discover(
3678 registry, "com.test.multiple", ubuntu::app_launch::AppID::ApplicationWildcard::LAST_LISTED));
3679+
3680+ EXPECT_CALL(*mockstore,
3681+ verifyPackage(ubuntu::app_launch::AppID::Package::from_raw("com.test.multiple"), testing::_))
3682+ .WillOnce(testing::Return(true));
3683+ EXPECT_CALL(*mockstore, findAppname(ubuntu::app_launch::AppID::Package::from_raw("com.test.multiple"),
3684+ ubuntu::app_launch::AppID::ApplicationWildcard::ONLY_LISTED, testing::_))
3685+ .WillOnce(testing::Return(ubuntu::app_launch::AppID::AppName::from_raw("")));
3686 EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover(
3687 registry, "com.test.multiple", ubuntu::app_launch::AppID::ApplicationWildcard::ONLY_LISTED));
3688+
3689+ EXPECT_CALL(*mockstore, verifyPackage(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"), testing::_))
3690+ .WillOnce(testing::Return(true));
3691+ EXPECT_CALL(*mockstore, findAppname(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
3692+ ubuntu::app_launch::AppID::ApplicationWildcard::ONLY_LISTED, testing::_))
3693+ .WillOnce(testing::Return(ubuntu::app_launch::AppID::AppName::from_raw("application")));
3694+ EXPECT_CALL(*mockstore, findVersion(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
3695+ ubuntu::app_launch::AppID::AppName::from_raw("application"), testing::_))
3696+ .WillOnce(testing::Return(ubuntu::app_launch::AppID::Version::from_raw("1.2.3")));
3697 EXPECT_EQ("com.test.good_application_1.2.3",
3698 (std::string)ubuntu::app_launch::AppID::discover(
3699 registry, "com.test.good", ubuntu::app_launch::AppID::ApplicationWildcard::ONLY_LISTED));
3700
3701 /* A bunch that should be NULL */
3702+ EXPECT_CALL(*mockstore,
3703+ verifyPackage(ubuntu::app_launch::AppID::Package::from_raw("com.test.no-hooks"), testing::_))
3704+ .WillOnce(testing::Return(false));
3705 EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover(registry, "com.test.no-hooks"));
3706+ EXPECT_CALL(*mockstore, verifyPackage(ubuntu::app_launch::AppID::Package::from_raw("com.test.no-json"), testing::_))
3707+ .WillOnce(testing::Return(false));
3708 EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover(registry, "com.test.no-json"));
3709+ EXPECT_CALL(*mockstore,
3710+ verifyPackage(ubuntu::app_launch::AppID::Package::from_raw("com.test.no-object"), testing::_))
3711+ .WillOnce(testing::Return(false));
3712 EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover(registry, "com.test.no-object"));
3713+ EXPECT_CALL(*mockstore,
3714+ verifyPackage(ubuntu::app_launch::AppID::Package::from_raw("com.test.no-version"), testing::_))
3715+ .WillOnce(testing::Return(false));
3716 EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover(registry, "com.test.no-version"));
3717+}
3718
3719+TEST_F(LibUAL, ApplicationIdLibertine)
3720+{
3721 /* Libertine tests */
3722 EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover(registry, "container-name"));
3723 EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover(registry, "container-name", "not-exist"));
3724@@ -492,9 +574,7 @@
3725 TEST_F(LibUAL, AppIdParse)
3726 {
3727 EXPECT_FALSE(ubuntu::app_launch::AppID::parse("com.ubuntu.test_test_123").empty());
3728- EXPECT_FALSE(ubuntu::app_launch::AppID::find(registry, "inkscape").empty());
3729 EXPECT_FALSE(ubuntu::app_launch::AppID::parse("chatter.robert-ancell_chatter_2").empty());
3730- EXPECT_FALSE(ubuntu::app_launch::AppID::find(registry, "chatter.robert-ancell_chatter").empty());
3731
3732 auto id = ubuntu::app_launch::AppID::parse("com.ubuntu.test_test_123");
3733
3734@@ -508,18 +588,12 @@
3735
3736 TEST_F(LibUAL, ApplicationList)
3737 {
3738-#ifdef ENABLE_SNAPPY
3739 SnapdMock snapd{LOCAL_SNAPD_TEST_SOCKET, {u8Package, interfaces, u8Package}};
3740 registry = std::make_shared<ubuntu::app_launch::Registry>();
3741-#endif
3742
3743 auto apps = ubuntu::app_launch::Registry::runningApps(registry);
3744
3745-#ifdef ENABLE_SNAPPY
3746- ASSERT_EQ(4, int(apps.size()));
3747-#else
3748- ASSERT_EQ(3, int(apps.size()));
3749-#endif
3750+ ASSERT_EQ(3u, apps.size());
3751
3752 apps.sort([](const std::shared_ptr<ubuntu::app_launch::Application>& a,
3753 const std::shared_ptr<ubuntu::app_launch::Application>& b) {
3754@@ -529,10 +603,8 @@
3755 return sa < sb;
3756 });
3757
3758- EXPECT_EQ("com.test.good_application_1.2.3", (std::string)apps.front()->appId());
3759-#ifdef ENABLE_SNAPPY
3760+ EXPECT_EQ("multiple", (std::string)apps.front()->appId());
3761 EXPECT_EQ("unity8-package_foo_x123", (std::string)apps.back()->appId());
3762-#endif
3763 }
3764
3765 TEST_F(LibUAL, StartingResponses)
3766@@ -559,17 +631,17 @@
3767
3768 /* Emit a signal */
3769 g_dbus_connection_emit_signal(
3770- session, NULL, /* destination */
3771- "/", /* path */
3772- "com.canonical.UbuntuAppLaunch", /* interface */
3773- "UnityStartingBroadcast", /* signal */
3774- g_variant_new("(ss)", "com.test.good_application_1.2.3", "goodinstance"), /* params, the same */
3775+ session, NULL, /* destination */
3776+ "/", /* path */
3777+ "com.canonical.UbuntuAppLaunch", /* interface */
3778+ "UnityStartingBroadcast", /* signal */
3779+ g_variant_new("(ss)", "container-name_test_0.0", "goodinstance"), /* params, the same */
3780 NULL);
3781
3782 /* Make sure we run our observer */
3783- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
3784- ubuntu::app_launch::AppID::AppName::from_raw("application"),
3785- ubuntu::app_launch::AppID::Version::from_raw("1.2.3")),
3786+ EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID(ubuntu::app_launch::AppID::Package::from_raw("container-name"),
3787+ ubuntu::app_launch::AppID::AppName::from_raw("test"),
3788+ ubuntu::app_launch::AppID::Version::from_raw("0.0")),
3789 manager->lastStartedApp);
3790
3791 /* Make sure we return */
3792@@ -581,119 +653,57 @@
3793
3794 TEST_F(LibUAL, AppIdTest)
3795 {
3796- auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
3797+ auto appid = ubuntu::app_launch::AppID::find(registry, "single");
3798 auto app = ubuntu::app_launch::Application::create(appid, registry);
3799 app->launch();
3800
3801- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
3802- this->manager->lastFocusedApp);
3803- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
3804- this->manager->lastResumedApp);
3805-}
3806-
3807-GDBusMessage* filter_func_good(GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data)
3808-{
3809- if (!incomming)
3810- {
3811- return message;
3812- }
3813-
3814- if (g_strcmp0(g_dbus_message_get_path(message), (gchar*)user_data) == 0)
3815- {
3816- GDBusMessage* reply = g_dbus_message_new_method_reply(message);
3817- g_dbus_connection_send_message(conn, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
3818- g_object_unref(message);
3819- return NULL;
3820- }
3821-
3822- return message;
3823+ EXPECT_EVENTUALLY_EQ(appid, this->manager->lastFocusedApp);
3824+ EXPECT_EVENTUALLY_EQ(appid, this->manager->lastResumedApp);
3825 }
3826
3827 TEST_F(LibUAL, UrlSendTest)
3828 {
3829- GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
3830- guint filter = g_dbus_connection_add_filter(session, filter_func_good,
3831- (gpointer) "/com_2etest_2egood_5fapplication_5f1_2e2_2e3", NULL);
3832-
3833- auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
3834- auto app = ubuntu::app_launch::Application::create(appid, registry);
3835- std::vector<ubuntu::app_launch::Application::URL> uris = {
3836- ubuntu::app_launch::Application::URL::from_raw("http://www.test.com")};
3837-
3838- app->launch(uris);
3839-
3840- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
3841- this->manager->lastFocusedApp);
3842- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
3843- this->manager->lastResumedApp);
3844-
3845- g_dbus_connection_remove_filter(session, filter);
3846-
3847- /* Send multiple resume responses to ensure we unsubscribe */
3848- /* Multiple to increase our chance of hitting a bad free in the middle,
3849- fun with async! */
3850- int i;
3851- for (i = 0; i < 5; i++)
3852- {
3853- g_dbus_connection_emit_signal(
3854- session, NULL, /* destination */
3855- "/", /* path */
3856- "com.canonical.UbuntuAppLaunch", /* interface */
3857- "UnityResumeResponse", /* signal */
3858- g_variant_new("(ss)", "com.test.good_application_1.2.3", "goodinstance"), /* params, the same */
3859- NULL);
3860-
3861- pause(50); /* Ensure all the events come through */
3862- }
3863-
3864- g_object_unref(session);
3865-}
3866-
3867-TEST_F(LibUAL, UrlSendNoObjectTest)
3868-{
3869- auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
3870- auto app = ubuntu::app_launch::Application::create(appid, registry);
3871- std::vector<ubuntu::app_launch::Application::URL> uris = {
3872- ubuntu::app_launch::Application::URL::from_raw("http://www.test.com")};
3873-
3874- app->launch(uris);
3875-
3876- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
3877- this->manager->lastFocusedApp);
3878- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
3879- this->manager->lastResumedApp);
3880+ auto appid = ubuntu::app_launch::AppID::find(registry, "foo");
3881+ auto app = ubuntu::app_launch::Application::create(appid, registry);
3882+ std::vector<ubuntu::app_launch::Application::URL> uris = {
3883+ ubuntu::app_launch::Application::URL::from_raw("http://www.test.com")};
3884+
3885+ app->launch(uris);
3886+
3887+ std::list<SystemdMock::TransientUnit> calls;
3888+ ASSERT_EVENTUALLY_FUNC_LT(0u, std::function<unsigned int(void)>([&]() {
3889+ calls = systemd->unitCalls();
3890+ return calls.size();
3891+ }));
3892+ EXPECT_EQ("http://www.test.com", *calls.begin()->execline.rbegin());
3893 }
3894
3895 TEST_F(LibUAL, UnityTimeoutTest)
3896 {
3897 this->resume_timeout = 100;
3898
3899- auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
3900+ auto appid = ubuntu::app_launch::AppID::find(registry, "single");
3901 auto app = ubuntu::app_launch::Application::create(appid, registry);
3902
3903 app->launch();
3904
3905- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
3906- this->manager->lastResumedApp);
3907- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
3908- this->manager->lastFocusedApp);
3909+ EXPECT_EVENTUALLY_EQ(appid, this->manager->lastResumedApp);
3910+ EXPECT_EVENTUALLY_EQ(appid, this->manager->lastFocusedApp);
3911 }
3912
3913 TEST_F(LibUAL, UnityTimeoutUriTest)
3914 {
3915 this->resume_timeout = 200;
3916
3917- auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
3918+ auto appid = ubuntu::app_launch::AppID::find(registry, "single");
3919 auto app = ubuntu::app_launch::Application::create(appid, registry);
3920 std::vector<ubuntu::app_launch::Application::URL> uris = {
3921 ubuntu::app_launch::Application::URL::from_raw("http://www.test.com")};
3922
3923 app->launch(uris);
3924
3925- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
3926- this->manager->lastFocusedApp);
3927- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
3928- this->manager->lastResumedApp);
3929+ EXPECT_EVENTUALLY_EQ(appid, this->manager->lastFocusedApp);
3930+ EXPECT_EVENTUALLY_EQ(appid, this->manager->lastResumedApp);
3931 }
3932
3933 GDBusMessage* filter_respawn(GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data)
3934@@ -714,7 +724,7 @@
3935
3936 guint start = g_get_monotonic_time();
3937
3938- auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
3939+ auto appid = ubuntu::app_launch::AppID::find(registry, "single");
3940 auto app = ubuntu::app_launch::Application::create(appid, registry);
3941 std::vector<ubuntu::app_launch::Application::URL> uris = {
3942 ubuntu::app_launch::Application::URL::from_raw("http://www.test.com")};
3943@@ -726,10 +736,8 @@
3944 g_debug("Start call time: %d ms", (end - start) / 1000);
3945 EXPECT_LT(end - start, guint(2000 * 1000));
3946
3947- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
3948- this->manager->lastFocusedApp);
3949- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
3950- this->manager->lastResumedApp);
3951+ EXPECT_EVENTUALLY_EQ(appid, this->manager->lastFocusedApp);
3952+ EXPECT_EVENTUALLY_EQ(appid, this->manager->lastResumedApp);
3953
3954 g_dbus_connection_remove_filter(session, filter);
3955 g_object_unref(session);
3956@@ -768,10 +776,12 @@
3957
3958 TEST_F(LibUAL, StartHelper)
3959 {
3960+ auto appid = ubuntu::app_launch::AppID::parse("com.test.multiple_first_1.2.3");
3961 auto untrusted = ubuntu::app_launch::Helper::Type::from_raw("untrusted-type");
3962
3963+ storeForHelper(appid);
3964+
3965 /* Basic make sure we can send the event */
3966- auto appid = ubuntu::app_launch::AppID::parse("com.test.multiple_first_1.2.3");
3967 auto helper = ubuntu::app_launch::Helper::create(untrusted, appid, registry);
3968
3969 auto inst = helper->launch();
3970@@ -782,7 +792,7 @@
3971 EXPECT_EQ(SystemdMock::instanceName(
3972 {"untrusted-type",
3973 "com.test.multiple_first_1.2.3",
3974- std::dynamic_pointer_cast<ubuntu::app_launch::jobs::instance::Base>(inst)->getInstanceId(),
3975+ std::dynamic_pointer_cast<ubuntu::app_launch::helper_impls::BaseInstance>(inst)->getInstanceId(),
3976 0,
3977 {}}),
3978 helperStart.begin()->name);
3979@@ -798,7 +808,7 @@
3980 EXPECT_EQ(SystemdMock::instanceName(
3981 {"untrusted-type",
3982 "com.test.multiple_first_1.2.3",
3983- std::dynamic_pointer_cast<ubuntu::app_launch::jobs::instance::Base>(inst2)->getInstanceId(),
3984+ std::dynamic_pointer_cast<ubuntu::app_launch::helper_impls::BaseInstance>(inst2)->getInstanceId(),
3985 0,
3986 {}}),
3987 helperStart2.begin()->name);
3988@@ -819,7 +829,7 @@
3989 EXPECT_EQ(SystemdMock::instanceName(
3990 {"untrusted-type",
3991 "com.test.multiple_first_1.2.3",
3992- std::dynamic_pointer_cast<ubuntu::app_launch::jobs::instance::Base>(inst3)->getInstanceId(),
3993+ std::dynamic_pointer_cast<ubuntu::app_launch::helper_impls::BaseInstance>(inst3)->getInstanceId(),
3994 0,
3995 {}}),
3996 helperStart3.begin()->name);
3997@@ -832,7 +842,7 @@
3998 TEST_F(LibUAL, StopHelper)
3999 {
4000 /* Multi helper */
4001- auto untrusted = ubuntu::app_launch::Helper::Type::from_raw("untrusted-type");
4002+ auto untrusted = ubuntu::app_launch::Helper::Type::from_raw("untrusted-helper");
4003
4004 auto appid = ubuntu::app_launch::AppID::parse("com.bar_foo_8432.13.1");
4005 auto helper = ubuntu::app_launch::Helper::create(untrusted, appid, registry);
4006@@ -849,7 +859,7 @@
4007
4008 ASSERT_EQ(1u, calls.size());
4009
4010- EXPECT_EQ(SystemdMock::instanceName({"untrusted-type", "com.bar_foo_8432.13.1", "24034582324132", 0, {}}),
4011+ EXPECT_EQ(SystemdMock::instanceName({"untrusted-helper", "com.bar_foo_8432.13.1", "24034582324132", 0, {}}),
4012 *calls.begin());
4013
4014 return;
4015@@ -862,7 +872,7 @@
4016
4017 EXPECT_EQ(0, int(notlist.size()));
4018
4019- auto goodhelper = ubuntu::app_launch::Helper::Type::from_raw("untrusted-type");
4020+ auto goodhelper = ubuntu::app_launch::Helper::Type::from_raw("untrusted-helper");
4021 auto goodlist = ubuntu::app_launch::Registry::runningHelpers(goodhelper, registry);
4022
4023 ASSERT_EQ(2, int(goodlist.size()));
4024@@ -888,49 +898,48 @@
4025 EXPECT_TRUE(goodlist.back()->instances()[0]->isRunning());
4026 }
4027
4028-typedef struct
4029-{
4030- int count;
4031- const gchar* appid;
4032- const gchar* type;
4033- const gchar* instance;
4034-} helper_observer_data_t;
4035-
4036-static void helper_observer_cb(const gchar* appid, const gchar* instance, const gchar* type, gpointer user_data)
4037-{
4038- helper_observer_data_t* data = (helper_observer_data_t*)user_data;
4039-
4040- if (g_strcmp0(data->appid, appid) == 0 && g_strcmp0(data->type, type) == 0 &&
4041- g_strcmp0(data->instance, instance) == 0)
4042- {
4043- data->count++;
4044- }
4045-}
4046-
4047 TEST_F(LibUAL, StartStopHelperObserver)
4048 {
4049- helper_observer_data_t start_data = {
4050- .count = 0, .appid = "com.foo_foo_1.2.3", .type = "my-type-is-scorpio", .instance = nullptr};
4051- helper_observer_data_t stop_data = {
4052- .count = 0, .appid = "com.bar_bar_44.32", .type = "my-type-is-libra", .instance = "1234"};
4053-
4054- ASSERT_TRUE(ubuntu_app_launch_observer_add_helper_started(helper_observer_cb, "my-type-is-scorpio", &start_data));
4055- ASSERT_TRUE(ubuntu_app_launch_observer_add_helper_stop(helper_observer_cb, "my-type-is-libra", &stop_data));
4056+ auto type = ubuntu::app_launch::Helper::Type::from_raw("my-type-is-scorpio");
4057+ auto appid = ubuntu::app_launch::AppID::parse("com.foo_foo_1.2.3");
4058+
4059+ storeForHelper(appid);
4060+
4061+ int start_count = 0;
4062+ int stop_count = 0;
4063+
4064+ ubuntu::app_launch::Registry::helperStarted(type, registry)
4065+ .connect([&](const std::shared_ptr<ubuntu::app_launch::Helper>& helper,
4066+ const std::shared_ptr<ubuntu::app_launch::Helper::Instance>& inst) {
4067+ if (helper->appId() != appid)
4068+ {
4069+ return;
4070+ }
4071+
4072+ start_count++;
4073+ });
4074+ ubuntu::app_launch::Registry::helperStopped(type, registry)
4075+ .connect([&](const std::shared_ptr<ubuntu::app_launch::Helper>& helper,
4076+ const std::shared_ptr<ubuntu::app_launch::Helper::Instance>& inst) {
4077+ if (helper->appId() != appid)
4078+ {
4079+ return;
4080+ }
4081+
4082+ stop_count++;
4083+ });
4084
4085 /* Basic start */
4086- systemd->managerEmitNew(SystemdMock::instanceName({"my-type-is-scorpio", "com.foo_foo_1.2.3", "", 0, {}}), "/");
4087+ systemd->managerEmitNew(SystemdMock::instanceName({"my-type-is-scorpio", "com.foo_foo_1.2.3", "1234", 0, {}}),
4088+ "/foo");
4089
4090- EXPECT_EVENTUALLY_EQ(1, start_data.count);
4091+ EXPECT_EVENTUALLY_EQ(1, start_count);
4092
4093 /* Basic stop */
4094- systemd->managerEmitRemoved(SystemdMock::instanceName({"my-type-is-scorpio", "com.foo_foo_1.2.3", "", 0, {}}), "/");
4095-
4096- EXPECT_EVENTUALLY_EQ(1, stop_data.count);
4097-
4098- /* Remove */
4099- ASSERT_TRUE(
4100- ubuntu_app_launch_observer_delete_helper_started(helper_observer_cb, "my-type-is-scorpio", &start_data));
4101- ASSERT_TRUE(ubuntu_app_launch_observer_delete_helper_stop(helper_observer_cb, "my-type-is-libra", &stop_data));
4102+ systemd->managerEmitRemoved(SystemdMock::instanceName({"my-type-is-scorpio", "com.foo_foo_1.2.3", "1234", 0, {}}),
4103+ "/foo");
4104+
4105+ EXPECT_EVENTUALLY_EQ(1, stop_count);
4106 }
4107
4108 // DISABLED: Skipping these tests to not block on bug #1584849
4109@@ -946,7 +955,10 @@
4110
4111 /* New Systemd Mock */
4112 dbus_test_service_remove_task(service, *systemd);
4113+ kill(dbus_test_process_get_pid(*systemd), SIGTERM);
4114+ EXPECT_EVENTUALLY_FUNC_EQ(DBUS_TEST_TASK_STATE_FINISHED, systemd->stateFunc());
4115 systemd.reset();
4116+
4117 auto systemd2 = std::make_shared<SystemdMock>(
4118 std::list<SystemdMock::Instance>{
4119 {"application-click", "com.test.good_application_1.2.3", {}, spew.pid(), {spew.pid()}}},
4120@@ -1032,6 +1044,7 @@
4121
4122 TEST_F(LibUAL, MultiPause)
4123 {
4124+ auto appid = ubuntu::app_launch::AppID::find(registry, "single");
4125 g_setenv("UBUNTU_APP_LAUNCH_OOM_PROC_PATH", CMAKE_BINARY_DIR "/libual-proc", 1);
4126
4127 /* Setup A TON OF spew */
4128@@ -1042,18 +1055,32 @@
4129
4130 /* New Systemd Mock */
4131 dbus_test_service_remove_task(service, *systemd);
4132+ kill(dbus_test_process_get_pid(*systemd), SIGTERM);
4133+ EXPECT_EVENTUALLY_FUNC_EQ(DBUS_TEST_TASK_STATE_FINISHED, systemd->stateFunc());
4134 systemd.reset();
4135- std::vector<pid_t> spewpids;
4136- std::transform(spews.begin(), spews.end(), spewpids.begin(), [](SpewMaster& spew) { return spew.pid(); });
4137+
4138+ std::vector<pid_t> spewpids{int(spews.size())};
4139+ for (const auto& spew : spews)
4140+ {
4141+ spewpids.push_back(spew.pid());
4142+ }
4143 auto systemd2 = std::make_shared<SystemdMock>(
4144- std::list<SystemdMock::Instance>{
4145- {"application-click", "com.test.good_application_1.2.3", {}, spews.begin()->pid(), spewpids}},
4146+ std::list<SystemdMock::Instance>{{"application-legacy", "single", {}, spews.begin()->pid(), spewpids}},
4147 CGROUP_DIR);
4148
4149+ /* Add mocks */
4150+ dbus_test_service_add_task(service, *systemd2);
4151+ dbus_test_service_add_task(service, *zgmock);
4152+ dbus_test_task_run(*systemd2);
4153+ dbus_test_task_run(*zgmock);
4154+
4155 /* Give things a chance to start */
4156 EXPECT_EVENTUALLY_FUNC_EQ(DBUS_TEST_TASK_STATE_RUNNING, systemd2->stateFunc());
4157 EXPECT_EVENTUALLY_FUNC_EQ(DBUS_TEST_TASK_STATE_RUNNING, zgmock->stateFunc());
4158
4159+ /* Resetup the registry with the new systemd */
4160+ registry = std::make_shared<ubuntu::app_launch::Registry>();
4161+
4162 /* Setup signal handling */
4163 guint paused_count = 0;
4164 guint resumed_count = 0;
4165@@ -1078,10 +1105,10 @@
4166 });
4167
4168 /* Get our app object */
4169- auto appid = ubuntu::app_launch::AppID::find(registry, "com.test.good_application_1.2.3");
4170 auto app = ubuntu::app_launch::Application::create(appid, registry);
4171
4172- ASSERT_EQ(1, int(app->instances().size()));
4173+ ASSERT_NE(nullptr, app);
4174+ ASSERT_EQ(1u, app->instances().size());
4175
4176 auto instance = app->instances()[0];
4177
4178@@ -1150,10 +1177,10 @@
4179 ASSERT_TRUE(g_file_set_contents(oomadjfile, "0", -1, NULL));
4180
4181 /* Get our app object */
4182- auto appid = ubuntu::app_launch::AppID::find(registry, "com.test.good_application_1.2.3");
4183+ auto appid = ubuntu::app_launch::AppID::find(registry, "single");
4184 auto app = ubuntu::app_launch::Application::create(appid, registry);
4185
4186- ASSERT_EQ(1, int(app->instances().size()));
4187+ ASSERT_EQ(1u, app->instances().size());
4188
4189 auto instance = app->instances()[0];
4190
4191@@ -1270,76 +1297,99 @@
4192 return;
4193 }
4194
4195-#if 0
4196-/* Need to change as helpers change to not use Upstart features */
4197+/* Hardcore socket stuff */
4198+#include <sys/socket.h>
4199+#include <sys/types.h>
4200+#include <sys/un.h>
4201+
4202 TEST_F(LibUAL, SetExec)
4203 {
4204- DbusTestDbusMockObject* obj =
4205- dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
4206-
4207- const char* exec = "lets exec this";
4208-
4209- g_setenv("UPSTART_JOB", "fubar", TRUE);
4210- g_unsetenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME");
4211- EXPECT_TRUE(ubuntu_app_launch_helper_set_exec(exec, NULL));
4212-
4213- guint len = 0;
4214- const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "SetEnv", &len, NULL);
4215- ASSERT_NE(nullptr, calls);
4216- ASSERT_EQ(1u, len);
4217-
4218- gchar* appexecstr = g_strdup_printf("APP_EXEC=%s", exec);
4219- GVariant* appexecenv = g_variant_get_child_value(calls[0].params, 1);
4220- EXPECT_STREQ(appexecstr, g_variant_get_string(appexecenv, nullptr));
4221- g_variant_unref(appexecenv);
4222- g_free(appexecstr);
4223-
4224- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4225-
4226- /* Now check for the demangler */
4227- g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME", g_dbus_connection_get_unique_name(bus), TRUE);
4228- EXPECT_TRUE(ubuntu_app_launch_helper_set_exec(exec, NULL));
4229-
4230- calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "SetEnv", &len, NULL);
4231- ASSERT_NE(nullptr, calls);
4232- ASSERT_EQ(1u, len);
4233-
4234- gchar* demangleexecstr = g_strdup_printf("APP_EXEC=%s %s", SOCKET_DEMANGLER_INSTALL, exec);
4235- appexecenv = g_variant_get_child_value(calls[0].params, 1);
4236- EXPECT_STREQ(demangleexecstr, g_variant_get_string(appexecenv, nullptr));
4237- g_variant_unref(appexecenv);
4238- g_free(demangleexecstr);
4239-
4240- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4241-
4242- /* Now check for the directory */
4243- g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME", g_dbus_connection_get_unique_name(bus), TRUE);
4244- EXPECT_TRUE(ubuntu_app_launch_helper_set_exec(exec, "/not/a/real/directory"));
4245-
4246- calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "SetEnv", &len, NULL);
4247- ASSERT_NE(nullptr, calls);
4248- EXPECT_EQ(2u, len);
4249-
4250- appexecenv = g_variant_get_child_value(calls[1].params, 1);
4251- EXPECT_STREQ("APP_DIR=/not/a/real/directory", g_variant_get_string(appexecenv, nullptr));
4252- g_variant_unref(appexecenv);
4253-
4254- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4255+ /* Create a socket */
4256+ class SmartSocket
4257+ {
4258+ public:
4259+ int fd;
4260+ SmartSocket()
4261+ : fd(socket(AF_UNIX, SOCK_STREAM, 0))
4262+ {
4263+ }
4264+ ~SmartSocket()
4265+ {
4266+ close(fd);
4267+ }
4268+ };
4269+ SmartSocket sock;
4270+ ASSERT_NE(0, sock.fd);
4271+
4272+ std::string socketname{"/ual-setexec-test-12445343"};
4273+
4274+ struct sockaddr_un socketaddr = {0};
4275+ socketaddr.sun_family = AF_UNIX;
4276+ strncpy(socketaddr.sun_path, socketname.c_str(), sizeof(socketaddr.sun_path) - 1);
4277+ socketaddr.sun_path[0] = 0;
4278+
4279+ ASSERT_EQ(0, bind(sock.fd, (const struct sockaddr*)&socketaddr, sizeof(struct sockaddr_un)));
4280+ listen(sock.fd, 1); /* 1 is the number of people who can connect */
4281+
4282+ setenv("UBUNTU_APP_LAUNCH_HELPER_EXECTOOL_SETEXEC_SOCKET", socketname.c_str(), 1);
4283+
4284+ std::promise<std::vector<std::string>> socketpromise;
4285+ std::thread socketreader([&]() {
4286+ std::vector<std::string> socketvals;
4287+
4288+ int readsocket = accept(sock.fd, NULL, NULL);
4289+
4290+ /* Keeping this similar to the helper-helper code as that's what
4291+ * we're running against. Not making it C++-style. */
4292+ char readbuf[2048] = {0};
4293+ int thisread = 0;
4294+ int amountread = 0;
4295+ while ((thisread = read(readsocket, readbuf + amountread, 2048 - amountread)) > 0)
4296+ {
4297+ amountread += thisread;
4298+
4299+ if (amountread == 2048)
4300+ {
4301+ try
4302+ {
4303+ throw std::runtime_error{"Read too many bytes from socket"};
4304+ }
4305+ catch (...)
4306+ {
4307+ socketpromise.set_exception(std::current_exception());
4308+ }
4309+ return;
4310+ }
4311+ }
4312+
4313+ close(readsocket);
4314+
4315+ /* Parse data */
4316+ if (amountread > 0)
4317+ {
4318+ char* startvar = readbuf;
4319+
4320+ do
4321+ {
4322+ socketvals.emplace_back(std::string(startvar));
4323+
4324+ startvar = startvar + strlen(startvar) + 1;
4325+ } while (startvar < readbuf + amountread);
4326+ }
4327+
4328+ /* Read socket */
4329+ socketpromise.set_value(socketvals);
4330+ });
4331+ socketreader.detach(); /* avoid thread cleanup code when we don't really care */
4332+
4333+ std::vector<std::string> execList{"Foo", "Bar", "Really really really long value", "Another value"};
4334+ ubuntu::app_launch::Helper::setExec(execList);
4335+
4336+ EXPECT_EQ(execList, socketpromise.get_future().get());
4337 }
4338-#endif
4339
4340 TEST_F(LibUAL, AppInfo)
4341 {
4342- g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE);
4343- g_setenv("TEST_CLICK_USER", "test-user", TRUE);
4344-
4345- /* Correct values from a click */
4346- auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.4");
4347- auto app = ubuntu::app_launch::Application::create(appid, registry);
4348-
4349- EXPECT_TRUE((bool)app->info());
4350- EXPECT_EQ("Application", app->info()->name().value());
4351-
4352 /* Correct values from a legacy */
4353 auto barid = ubuntu::app_launch::AppID::find(registry, "bar");
4354 EXPECT_THROW(ubuntu::app_launch::Application::create(barid, registry), std::runtime_error);
4355
4356=== modified file 'tests/libual-test.cc'
4357--- tests/libual-test.cc 2017-02-15 15:10:07 +0000
4358+++ tests/libual-test.cc 2017-03-21 03:26:40 +0000
4359@@ -20,6 +20,7 @@
4360 #include <fcntl.h>
4361 #include <future>
4362 #include <gio/gio.h>
4363+#include <glib/gstdio.h>
4364 #include <gtest/gtest.h>
4365 #include <libdbustest/dbus-test.h>
4366 #include <thread>
4367@@ -30,340 +31,164 @@
4368 #include "registry.h"
4369 #include "ubuntu-app-launch.h"
4370
4371+#include "eventually-fixture.h"
4372 #include "libertine-service.h"
4373-#include "eventually-fixture.h"
4374 #include "mir-mock.h"
4375+#include "snapd-mock.h"
4376+#include "systemd-mock.h"
4377+
4378+#define LOCAL_SNAPD_TEST_SOCKET (SNAPD_TEST_SOCKET "-libual-test")
4379+#define CGROUP_DIR (CMAKE_BINARY_DIR "/systemd-libual-cgroups")
4380
4381 class LibUAL : public EventuallyFixture
4382 {
4383- protected:
4384- DbusTestService * service = NULL;
4385- DbusTestDbusMock * mock = NULL;
4386- DbusTestDbusMock * cgmock = NULL;
4387- std::shared_ptr<LibertineService> libertine;
4388- GDBusConnection * bus = NULL;
4389- std::string last_focus_appid;
4390- std::string last_resume_appid;
4391- guint resume_timeout = 0;
4392-
4393- private:
4394- static void focus_cb (const gchar * appid, gpointer user_data) {
4395- g_debug("Focus Callback: %s", appid);
4396- LibUAL * _this = static_cast<LibUAL *>(user_data);
4397- _this->last_focus_appid = appid;
4398- }
4399-
4400- static void resume_cb (const gchar * appid, gpointer user_data) {
4401- g_debug("Resume Callback: %s", appid);
4402- LibUAL * _this = static_cast<LibUAL *>(user_data);
4403- _this->last_resume_appid = appid;
4404-
4405- if (_this->resume_timeout > 0) {
4406- _this->pause(_this->resume_timeout);
4407- }
4408- }
4409-
4410- protected:
4411- /* Useful debugging stuff, but not on by default. You really want to
4412- not get all this noise typically */
4413- void debugConnection() {
4414- if (true) return;
4415-
4416- DbusTestBustle * bustle = dbus_test_bustle_new("test.bustle");
4417- dbus_test_service_add_task(service, DBUS_TEST_TASK(bustle));
4418- g_object_unref(bustle);
4419-
4420- DbusTestProcess * monitor = dbus_test_process_new("dbus-monitor");
4421- dbus_test_service_add_task(service, DBUS_TEST_TASK(monitor));
4422- g_object_unref(monitor);
4423- }
4424-
4425- virtual void SetUp() {
4426- /* Click DB test mode */
4427- g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE);
4428- g_setenv("TEST_CLICK_USER", "test-user", TRUE);
4429-
4430- gchar * linkfarmpath = g_build_filename(CMAKE_SOURCE_DIR, "link-farm", NULL);
4431- g_setenv("UBUNTU_APP_LAUNCH_LINK_FARM", linkfarmpath, TRUE);
4432- g_free(linkfarmpath);
4433-
4434- g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);
4435- g_setenv("XDG_CACHE_HOME", CMAKE_SOURCE_DIR "/libertine-data", TRUE);
4436- g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE);
4437-
4438- g_setenv("UBUNTU_APP_LAUNCH_SNAPD_SOCKET", "/this/should/not/exist", TRUE);
4439- g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH", "/this/should/not/exist", TRUE);
4440-
4441- service = dbus_test_service_new(NULL);
4442-
4443- debugConnection();
4444-
4445- mock = dbus_test_dbus_mock_new("com.ubuntu.Upstart");
4446-
4447- DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
4448-
4449- dbus_test_dbus_mock_object_add_method(mock, obj,
4450- "EmitEvent",
4451- G_VARIANT_TYPE("(sasb)"),
4452- NULL,
4453- "",
4454- NULL);
4455-
4456- dbus_test_dbus_mock_object_add_method(mock, obj,
4457- "GetJobByName",
4458- G_VARIANT_TYPE("s"),
4459- G_VARIANT_TYPE("o"),
4460- "if args[0] == 'application-click':\n"
4461- " ret = dbus.ObjectPath('/com/test/application_click')\n"
4462- "elif args[0] == 'application-legacy':\n"
4463- " ret = dbus.ObjectPath('/com/test/application_legacy')\n"
4464- "elif args[0] == 'untrusted-helper':\n"
4465- " ret = dbus.ObjectPath('/com/test/untrusted/helper')\n",
4466- NULL);
4467-
4468- dbus_test_dbus_mock_object_add_method(mock, obj,
4469- "SetEnv",
4470- G_VARIANT_TYPE("(assb)"),
4471- NULL,
4472- "",
4473- NULL);
4474-
4475- /* Click App */
4476- DbusTestDbusMockObject * jobobj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
4477-
4478- dbus_test_dbus_mock_object_add_method(mock, jobobj,
4479- "Start",
4480- G_VARIANT_TYPE("(asb)"),
4481- NULL,
4482- "if 'APP_ID=com.test.good_application_1.2.3' in args[0]:"
4483- " raise dbus.exceptions.DBusException('Foo running', name='com.ubuntu.Upstart0_6.Error.AlreadyStarted')",
4484- NULL);
4485-
4486- dbus_test_dbus_mock_object_add_method(mock, jobobj,
4487- "Stop",
4488- G_VARIANT_TYPE("(asb)"),
4489- NULL,
4490- "",
4491- NULL);
4492-
4493- dbus_test_dbus_mock_object_add_method(mock, jobobj,
4494- "GetAllInstances",
4495- NULL,
4496- G_VARIANT_TYPE("ao"),
4497- "ret = [ dbus.ObjectPath('/com/test/app_instance') ]",
4498- NULL);
4499-
4500- dbus_test_dbus_mock_object_add_method(mock,
4501- jobobj,
4502- "GetInstanceByName",
4503- G_VARIANT_TYPE_STRING,
4504- G_VARIANT_TYPE("o"),
4505- "ret = dbus.ObjectPath('/com/test/app_instance')",
4506- NULL);
4507-
4508- DbusTestDbusMockObject * instobj = dbus_test_dbus_mock_get_object(mock, "/com/test/app_instance", "com.ubuntu.Upstart0_6.Instance", NULL);
4509- dbus_test_dbus_mock_object_add_property(mock, instobj,
4510- "name",
4511- G_VARIANT_TYPE_STRING,
4512- g_variant_new_string("com.test.good_application_1.2.3"),
4513- NULL);
4514- gchar * process_var = g_strdup_printf("[('main', %d)]", getpid());
4515- dbus_test_dbus_mock_object_add_property(mock, instobj,
4516- "processes",
4517- G_VARIANT_TYPE("a(si)"),
4518- g_variant_new_parsed(process_var),
4519- NULL);
4520- g_free(process_var);
4521-
4522- /* Legacy App */
4523- DbusTestDbusMockObject * ljobobj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);
4524-
4525- dbus_test_dbus_mock_object_add_method(mock, ljobobj,
4526- "Start",
4527- G_VARIANT_TYPE("(asb)"),
4528- NULL,
4529- "",
4530- NULL);
4531-
4532- dbus_test_dbus_mock_object_add_method(mock, ljobobj,
4533- "Stop",
4534- G_VARIANT_TYPE("(asb)"),
4535- NULL,
4536- "",
4537- NULL);
4538-
4539- dbus_test_dbus_mock_object_add_method(mock, ljobobj,
4540- "GetAllInstances",
4541- NULL,
4542- G_VARIANT_TYPE("ao"),
4543- "ret = [ dbus.ObjectPath('/com/test/legacy_app_instance'), dbus.ObjectPath('/com/test/legacy_app_instance2')]",
4544- NULL);
4545-
4546- dbus_test_dbus_mock_object_add_method(mock,
4547- ljobobj,
4548- "GetInstanceByName",
4549- G_VARIANT_TYPE_STRING,
4550- G_VARIANT_TYPE("o"),
4551- "if args[0] == 'multiple-2342345':\n"
4552- " ret = dbus.ObjectPath('/com/test/legacy_app_instance')\n"
4553- "elif args[0] == 'single-':\n"
4554- " ret = dbus.ObjectPath('/com/test/legacy_app_instance2')",
4555- NULL);
4556-
4557- DbusTestDbusMockObject * linstobj = dbus_test_dbus_mock_get_object(mock, "/com/test/legacy_app_instance", "com.ubuntu.Upstart0_6.Instance", NULL);
4558- dbus_test_dbus_mock_object_add_property(mock, linstobj,
4559- "name",
4560- G_VARIANT_TYPE_STRING,
4561- g_variant_new_string("multiple-2342345"),
4562- NULL);
4563- dbus_test_dbus_mock_object_add_property(mock, linstobj,
4564- "processes",
4565- G_VARIANT_TYPE("a(si)"),
4566- g_variant_new_parsed("[('main', 5678)]"),
4567- NULL);
4568-
4569- DbusTestDbusMockObject* linstobj2 = dbus_test_dbus_mock_get_object(mock, "/com/test/legacy_app_instance2",
4570- "com.ubuntu.Upstart0_6.Instance", NULL);
4571- dbus_test_dbus_mock_object_add_property(mock, linstobj2, "name", G_VARIANT_TYPE_STRING,
4572- g_variant_new_string("single-"), NULL);
4573- dbus_test_dbus_mock_object_add_property(mock, linstobj2, "processes", G_VARIANT_TYPE("a(si)"),
4574- g_variant_new_parsed("[('main', 5678)]"), NULL);
4575-
4576- /* Untrusted Helper */
4577- DbusTestDbusMockObject * uhelperobj = dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper", "com.ubuntu.Upstart0_6.Job", NULL);
4578-
4579- dbus_test_dbus_mock_object_add_method(mock, uhelperobj,
4580- "Start",
4581- G_VARIANT_TYPE("(asb)"),
4582- NULL,
4583- "",
4584- NULL);
4585-
4586- dbus_test_dbus_mock_object_add_method(mock, uhelperobj,
4587- "Stop",
4588- G_VARIANT_TYPE("(asb)"),
4589- NULL,
4590- "",
4591- NULL);
4592-
4593- dbus_test_dbus_mock_object_add_method(mock, uhelperobj,
4594- "GetAllInstances",
4595- NULL,
4596- G_VARIANT_TYPE("ao"),
4597- "ret = [ dbus.ObjectPath('/com/test/untrusted/helper/instance'), dbus.ObjectPath('/com/test/untrusted/helper/multi_instance') ]",
4598- NULL);
4599-
4600- DbusTestDbusMockObject * uhelperinstance = dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper/instance", "com.ubuntu.Upstart0_6.Instance", NULL);
4601- dbus_test_dbus_mock_object_add_property(mock, uhelperinstance,
4602- "name",
4603- G_VARIANT_TYPE_STRING,
4604- g_variant_new_string("untrusted-type::com.foo_bar_43.23.12"),
4605- NULL);
4606-
4607- DbusTestDbusMockObject * unhelpermulti = dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper/multi_instance", "com.ubuntu.Upstart0_6.Instance", NULL);
4608- dbus_test_dbus_mock_object_add_property(mock, unhelpermulti,
4609- "name",
4610- G_VARIANT_TYPE_STRING,
4611- g_variant_new_string("untrusted-type:24034582324132:com.bar_foo_8432.13.1"),
4612- NULL);
4613-
4614- /* Create the cgroup manager mock */
4615- cgmock = dbus_test_dbus_mock_new("org.test.cgmock");
4616- g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_NAME", "org.test.cgmock", TRUE);
4617-
4618- DbusTestDbusMockObject * cgobject = dbus_test_dbus_mock_get_object(cgmock, "/org/linuxcontainers/cgmanager", "org.linuxcontainers.cgmanager0_0", NULL);
4619- dbus_test_dbus_mock_object_add_method(cgmock, cgobject,
4620- "GetTasksRecursive",
4621- G_VARIANT_TYPE("(ss)"),
4622- G_VARIANT_TYPE("ai"),
4623- "ret = [100, 200, 300]",
4624- NULL);
4625-
4626- /* Put it together */
4627- dbus_test_service_add_task(service, DBUS_TEST_TASK(mock));
4628- dbus_test_service_add_task(service, DBUS_TEST_TASK(cgmock));
4629-
4630- /* Add in Libertine */
4631- libertine = std::make_shared<LibertineService>();
4632- dbus_test_service_add_task(service, *libertine);
4633- dbus_test_service_add_task(service, libertine->waitTask());
4634-
4635- dbus_test_service_start_tasks(service);
4636-
4637- bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
4638- g_dbus_connection_set_exit_on_close(bus, FALSE);
4639- g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus);
4640-
4641- /* Make sure we pretend the CG manager is just on our bus */
4642- g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_SESSION_BUS", "YES", TRUE);
4643-
4644- ASSERT_TRUE(ubuntu_app_launch_observer_add_app_focus(focus_cb, this));
4645- ASSERT_TRUE(ubuntu_app_launch_observer_add_app_resume(resume_cb, this));
4646- }
4647-
4648- virtual void TearDown() {
4649- ubuntu_app_launch_observer_delete_app_focus(focus_cb, this);
4650- ubuntu_app_launch_observer_delete_app_resume(resume_cb, this);
4651-
4652- ubuntu::app_launch::Registry::clearDefault();
4653-
4654- libertine.reset();
4655- g_clear_object(&mock);
4656- g_clear_object(&cgmock);
4657- g_clear_object(&service);
4658-
4659- g_object_unref(bus);
4660-
4661- ASSERT_EVENTUALLY_EQ(nullptr, bus);
4662- }
4663-
4664- GVariant * find_env (GVariant * env_array, const gchar * var) {
4665- unsigned int i;
4666- GVariant * retval = nullptr;
4667-
4668- for (i = 0; i < g_variant_n_children(env_array); i++) {
4669- GVariant * child = g_variant_get_child_value(env_array, i);
4670- const gchar * envvar = g_variant_get_string(child, nullptr);
4671-
4672- if (g_str_has_prefix(envvar, var)) {
4673- if (retval != nullptr) {
4674- g_warning("Found the env var more than once!");
4675- g_variant_unref(retval);
4676- return nullptr;
4677- }
4678-
4679- retval = child;
4680- } else {
4681- g_variant_unref(child);
4682- }
4683- }
4684-
4685- if (!retval) {
4686- gchar * envstr = g_variant_print(env_array, FALSE);
4687- g_warning("Unable to find '%s' in '%s'", var, envstr);
4688- g_free(envstr);
4689- }
4690-
4691- return retval;
4692- }
4693-
4694- bool check_env (GVariant * env_array, const gchar * var, const gchar * value) {
4695- bool found = false;
4696- GVariant * val = find_env(env_array, var);
4697- if (val == nullptr)
4698- return false;
4699-
4700- const gchar * envvar = g_variant_get_string(val, nullptr);
4701-
4702- gchar * combined = g_strdup_printf("%s=%s", var, value);
4703- if (g_strcmp0(envvar, combined) == 0) {
4704- found = true;
4705- }
4706-
4707- g_variant_unref(val);
4708-
4709- return found;
4710- }
4711+protected:
4712+ DbusTestService *service = NULL;
4713+ DbusTestDbusMock *mock = NULL;
4714+ DbusTestDbusMock *cgmock = NULL;
4715+ std::shared_ptr<LibertineService> libertine;
4716+ std::shared_ptr<SystemdMock> systemd;
4717+ GDBusConnection *bus = NULL;
4718+ std::string last_focus_appid;
4719+ std::string last_resume_appid;
4720+ guint resume_timeout = 0;
4721+
4722+private:
4723+ static void focus_cb(const gchar *appid, gpointer user_data)
4724+ {
4725+ g_debug("Focus Callback: %s", appid);
4726+ LibUAL *_this = static_cast<LibUAL *>(user_data);
4727+ _this->last_focus_appid = appid;
4728+ }
4729+
4730+ static void resume_cb(const gchar *appid, gpointer user_data)
4731+ {
4732+ g_debug("Resume Callback: %s", appid);
4733+ LibUAL *_this = static_cast<LibUAL *>(user_data);
4734+ _this->last_resume_appid = appid;
4735+
4736+ if (_this->resume_timeout > 0)
4737+ {
4738+ _this->pause(_this->resume_timeout);
4739+ }
4740+ }
4741+
4742+protected:
4743+ /* Useful debugging stuff, but not on by default. You really want to
4744+ not get all this noise typically */
4745+ void debugConnection()
4746+ {
4747+ if (true)
4748+ return;
4749+
4750+ DbusTestBustle *bustle = dbus_test_bustle_new("test.bustle");
4751+ dbus_test_service_add_task(service, DBUS_TEST_TASK(bustle));
4752+ g_object_unref(bustle);
4753+
4754+ DbusTestProcess *monitor = dbus_test_process_new("dbus-monitor");
4755+ dbus_test_service_add_task(service, DBUS_TEST_TASK(monitor));
4756+ g_object_unref(monitor);
4757+ }
4758+
4759+ virtual void SetUp()
4760+ {
4761+ g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);
4762+ g_setenv("XDG_CACHE_HOME", CMAKE_SOURCE_DIR "/libertine-data", TRUE);
4763+ g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE);
4764+
4765+ g_setenv("UBUNTU_APP_LAUNCH_SNAPD_SOCKET", LOCAL_SNAPD_TEST_SOCKET, TRUE);
4766+ g_setenv("UBUNTU_APP_LAUNCH_SNAP_BASEDIR", SNAP_BASEDIR, TRUE);
4767+ g_setenv("UBUNTU_APP_LAUNCH_DISABLE_SNAPD_TIMEOUT", "You betcha!", TRUE);
4768+
4769+ g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH", "/this/should/not/exist", TRUE);
4770+ g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_CGROUP_ROOT", CGROUP_DIR, TRUE);
4771+
4772+ g_unlink(LOCAL_SNAPD_TEST_SOCKET);
4773+
4774+ service = dbus_test_service_new(NULL);
4775+
4776+ debugConnection();
4777+
4778+ systemd = std::make_shared<SystemdMock>(
4779+ std::list<SystemdMock::Instance>{
4780+ {"application-snap", "unity8-package_foo_x123", {}, getpid(), {100, 200, 300}},
4781+ {"application-legacy", "multiple", "2342345", 5678, {100, 200, 300}},
4782+ {"application-legacy", "single", {}, getpid(), {getpid()}},
4783+ {"untrusted-helper", "com.foo_bar_43.23.12", {}, 1, {100, 200, 300}},
4784+ {"untrusted-helper", "com.bar_foo_8432.13.1", "24034582324132", 1, {100, 200, 300}}},
4785+ CGROUP_DIR);
4786+
4787+ /* Put it together */
4788+ dbus_test_service_add_task(service, *systemd);
4789+
4790+ /* Add in Libertine */
4791+ libertine = std::make_shared<LibertineService>();
4792+ dbus_test_service_add_task(service, *libertine);
4793+ dbus_test_service_add_task(service, libertine->waitTask());
4794+
4795+ dbus_test_service_start_tasks(service);
4796+
4797+ bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
4798+ g_dbus_connection_set_exit_on_close(bus, FALSE);
4799+ g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus);
4800+
4801+ ASSERT_TRUE(ubuntu_app_launch_observer_add_app_focus(focus_cb, this));
4802+ ASSERT_TRUE(ubuntu_app_launch_observer_add_app_resume(resume_cb, this));
4803+ }
4804+
4805+ virtual void TearDown()
4806+ {
4807+ ubuntu_app_launch_observer_delete_app_focus(focus_cb, this);
4808+ ubuntu_app_launch_observer_delete_app_resume(resume_cb, this);
4809+
4810+ ubuntu::app_launch::Registry::clearDefault();
4811+
4812+ systemd.reset();
4813+ libertine.reset();
4814+ g_clear_object(&service);
4815+
4816+ g_object_unref(bus);
4817+
4818+ ASSERT_EVENTUALLY_EQ(nullptr, bus);
4819+
4820+ g_unlink(LOCAL_SNAPD_TEST_SOCKET);
4821+ }
4822+
4823+ static std::string find_env(std::set<std::string> &envs, std::string var)
4824+ {
4825+ auto iter =
4826+ std::find_if(envs.begin(), envs.end(), [var](std::string value) { return split_env(value).first == var; });
4827+
4828+ if (iter == envs.end())
4829+ {
4830+ return {};
4831+ }
4832+ else
4833+ {
4834+ return *iter;
4835+ }
4836+ }
4837+
4838+ static std::pair<std::string, std::string> split_env(const std::string &env)
4839+ {
4840+ auto eq = std::find(env.begin(), env.end(), '=');
4841+ if (eq == env.end())
4842+ {
4843+ throw std::runtime_error{"Environment value is invalid: " + env};
4844+ }
4845+
4846+ return std::make_pair(std::string(env.begin(), eq), std::string(eq + 1, env.end()));
4847+ }
4848+
4849+ static bool check_env(std::set<std::string> &envs, const std::string &key, const std::string &value)
4850+ {
4851+ auto val = find_env(envs, key);
4852+ if (val.empty())
4853+ {
4854+ return false;
4855+ }
4856+ return split_env(val).second == value;
4857+ }
4858 };
4859
4860 #define TASK_STATE(task) \
4861@@ -372,1283 +197,823 @@
4862 [&task] { return dbus_test_task_get_state(DBUS_TEST_TASK(task)); } \
4863 }
4864
4865+/* Snapd mock data */
4866+static std::pair<std::string, std::string> interfaces{
4867+ "GET /v2/interfaces HTTP/1.1\r\nHost: snapd\r\nAccept: */*\r\n\r\n",
4868+ SnapdMock::httpJsonResponse(SnapdMock::snapdOkay(SnapdMock::interfacesJson(
4869+ {{"unity8", "unity8-package", {"foo", "single", "xmir", "noxmir"}}, {"mir", "unity8-package", {"foo"}}})))};
4870+static std::pair<std::string, std::string> u8Package{
4871+ "GET /v2/snaps/unity8-package HTTP/1.1\r\nHost: snapd\r\nAccept: */*\r\n\r\n",
4872+ SnapdMock::httpJsonResponse(SnapdMock::snapdOkay(SnapdMock::packageJson(
4873+ "unity8-package", "active", "app", "1.2.3.4", "x123", {"foo", "single", "xmir", "noxmir"})))};
4874+
4875 TEST_F(LibUAL, StartApplication)
4876 {
4877- DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
4878-
4879- /* Basic make sure we can send the event */
4880- ASSERT_TRUE(ubuntu_app_launch_start_application("com.test.multiple_first_1.2.3", NULL));
4881- EXPECT_EQ(1, dbus_test_dbus_mock_object_check_method_call(mock, obj, "Start", NULL, NULL));
4882-
4883- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4884-
4885- /* Now look at the details of the call */
4886- ASSERT_TRUE(ubuntu_app_launch_start_application("com.test.multiple_first_1.2.3", NULL));
4887-
4888- guint len = 0;
4889- const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4890- EXPECT_NE(nullptr, calls);
4891- EXPECT_EQ(1u, len);
4892-
4893- EXPECT_STREQ("Start", calls->name);
4894- EXPECT_EQ(2u, g_variant_n_children(calls->params));
4895-
4896- GVariant * block = g_variant_get_child_value(calls->params, 1);
4897- EXPECT_TRUE(g_variant_get_boolean(block));
4898- g_variant_unref(block);
4899-
4900- GVariant * env = g_variant_get_child_value(calls->params, 0);
4901- EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
4902- g_variant_unref(env);
4903-
4904- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4905-
4906- /* Let's pass some URLs */
4907- const gchar * urls[] = {
4908- "http://ubuntu.com/",
4909- "https://ubuntu.com/",
4910- "file:///home/phablet/test.txt",
4911- NULL
4912- };
4913- ASSERT_TRUE(ubuntu_app_launch_start_application("com.test.multiple_first_1.2.3", urls));
4914-
4915- len = 0;
4916- calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4917- EXPECT_NE(nullptr, calls);
4918- EXPECT_EQ(1u, len);
4919-
4920- env = g_variant_get_child_value(calls->params, 0);
4921- EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
4922- EXPECT_TRUE(check_env(env, "APP_URIS", "'http://ubuntu.com/' 'https://ubuntu.com/' 'file:///home/phablet/test.txt'"));
4923- g_variant_unref(env);
4924-
4925- return;
4926+ /* Basic make sure we can send the event */
4927+ ASSERT_TRUE(ubuntu_app_launch_start_application("single", NULL));
4928+
4929+ std::list<SystemdMock::TransientUnit> calls;
4930+ ASSERT_EVENTUALLY_FUNC_LT(0u, std::function<unsigned int(void)>([&]() {
4931+ calls = systemd->unitCalls();
4932+ return calls.size();
4933+ }));
4934+ EXPECT_EQ(SystemdMock::instanceName({"application-legacy", "single", {}, 0, {}}), calls.begin()->name);
4935+
4936+ systemd->managerClear();
4937+
4938+ /* Let's pass some URLs */
4939+ const gchar *urls[] = {"http://ubuntu.com/", "https://ubuntu.com/", "file:///home/phablet/test.txt", NULL};
4940+ ASSERT_TRUE(ubuntu_app_launch_start_application("foo", urls));
4941+
4942+ ASSERT_EVENTUALLY_FUNC_LT(0u, std::function<unsigned int(void)>([&]() {
4943+ calls = systemd->unitCalls();
4944+ return calls.size();
4945+ }));
4946+
4947+ EXPECT_EQ("file:///home/phablet/test.txt", *(calls.begin()->execline.rbegin()));
4948+ EXPECT_EQ("https://ubuntu.com/", *(++calls.begin()->execline.rbegin()));
4949+ EXPECT_EQ("http://ubuntu.com/", *(++(++calls.begin()->execline.rbegin())));
4950+
4951+ return;
4952 }
4953
4954 TEST_F(LibUAL, StartApplicationTest)
4955 {
4956- DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
4957-
4958- ASSERT_TRUE(ubuntu_app_launch_start_application_test("com.test.multiple_first_1.2.3", NULL));
4959-
4960- guint len = 0;
4961- const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4962- EXPECT_NE(nullptr, calls);
4963- EXPECT_EQ(1u, len);
4964-
4965- EXPECT_STREQ("Start", calls->name);
4966- EXPECT_EQ(2u, g_variant_n_children(calls->params));
4967-
4968- GVariant * block = g_variant_get_child_value(calls->params, 1);
4969- EXPECT_TRUE(g_variant_get_boolean(block));
4970- g_variant_unref(block);
4971-
4972- GVariant * env = g_variant_get_child_value(calls->params, 0);
4973- EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
4974- EXPECT_TRUE(check_env(env, "QT_LOAD_TESTABILITY", "1"));
4975- g_variant_unref(env);
4976+ ASSERT_TRUE(ubuntu_app_launch_start_application_test("foo", nullptr));
4977+
4978+ std::list<SystemdMock::TransientUnit> calls;
4979+ ASSERT_EVENTUALLY_FUNC_LT(0u, std::function<unsigned int(void)>([&]() {
4980+ calls = systemd->unitCalls();
4981+ return calls.size();
4982+ }));
4983+
4984+ EXPECT_TRUE(check_env(calls.begin()->environment, "QT_LOAD_TESTABILITY", "1"));
4985 }
4986
4987 TEST_F(LibUAL, StopApplication)
4988 {
4989- DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
4990-
4991- ASSERT_TRUE(ubuntu_app_launch_stop_application("com.test.good_application_1.2.3"));
4992-
4993- ASSERT_EQ(dbus_test_dbus_mock_object_check_method_call(mock, obj, "Stop", NULL, NULL), 1);
4994-
4995+ ASSERT_TRUE(ubuntu_app_launch_stop_application("single"));
4996+
4997+ std::list<std::string> calls;
4998+ ASSERT_EVENTUALLY_FUNC_LT(0u, std::function<unsigned int(void)>([&]() {
4999+ calls = systemd->stopCalls();
5000+ return calls.size();
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches