Merge lp:~ted/ubuntu-app-launch/app-store into lp:ubuntu-app-launch

Proposed by Ted Gould
Status: Merged
Approved by: Ted Gould
Approved revision: 306
Merged at revision: 301
Proposed branch: lp:~ted/ubuntu-app-launch/app-store
Merge into: lp:ubuntu-app-launch
Diff against target: 2748 lines (+1349/-876)
28 files modified
docs/Doxyfile (+2/-2)
docs/index.rst (+50/-0)
libubuntu-app-launch/CMakeLists.txt (+10/-0)
libubuntu-app-launch/app-store-base.cpp (+63/-0)
libubuntu-app-launch/app-store-base.h (+65/-0)
libubuntu-app-launch/app-store-click.cpp (+248/-0)
libubuntu-app-launch/app-store-click.h (+60/-0)
libubuntu-app-launch/app-store-legacy.cpp (+202/-0)
libubuntu-app-launch/app-store-legacy.h (+60/-0)
libubuntu-app-launch/app-store-libertine.cpp (+173/-0)
libubuntu-app-launch/app-store-libertine.h (+60/-0)
libubuntu-app-launch/app-store-snap.cpp (+231/-0)
libubuntu-app-launch/app-store-snap.h (+60/-0)
libubuntu-app-launch/application-impl-base.cpp (+0/-37)
libubuntu-app-launch/application-impl-base.h (+0/-2)
libubuntu-app-launch/application-impl-click.cpp (+6/-197)
libubuntu-app-launch/application-impl-click.h (+0/-17)
libubuntu-app-launch/application-impl-legacy.cpp (+0/-160)
libubuntu-app-launch/application-impl-legacy.h (+0/-17)
libubuntu-app-launch/application-impl-libertine.cpp (+0/-131)
libubuntu-app-launch/application-impl-libertine.h (+0/-17)
libubuntu-app-launch/application-impl-snap.cpp (+2/-177)
libubuntu-app-launch/application-impl-snap.h (+3/-17)
libubuntu-app-launch/application.cpp (+24/-79)
libubuntu-app-launch/registry-impl.cpp (+5/-3)
libubuntu-app-launch/registry-impl.h (+9/-0)
libubuntu-app-launch/registry.cpp (+4/-13)
tests/list-apps.cpp (+12/-7)
To merge this branch: bzr merge lp:~ted/ubuntu-app-launch/app-store
Reviewer Review Type Date Requested Status
Charles Kerr (community) Approve
unity-api-1-bot continuous-integration Needs Fixing
Review via email: mp+318290@code.launchpad.net

Commit message

Put all application specific static functions into a single AppStore object

Description of the change

This moves the growing collection of static functions that were starting to collect in the application implementations which were causing a whole set of problems. This creates an app store backend for each type, that exists throughout the lifecycle of the registry itself.

Here we end up fixing quite a few problems, and delete some really ugly code. We end up hiding almost all the implementations to any of the higher level code. And we have a possibility to inject an AppStore mock in for more precise testing.

I think that, if we didn't count copyright headers and #includes, this branch would actually reduce the amount of code as well.

To post a comment you must log in.
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

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

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) wrote :

This is a nice improvement! Moving away from the static methods is a good cleanup. Thanks for doing this.

Inline are more minor cleanup suggestions. Most of them are in moved code rather than new code. The new code LGTM

review: Approve
Revision history for this message
Ted Gould (ted) wrote :

On Tue, 2017-03-14 at 03:55 +0000, Charles Kerr wrote:
> Inline are more minor cleanup suggestions. Most of them are in moved
> code rather than new code. The new code LGTM
So I'm going to ignore a bunch of these because they're in code that
gets deleted real soon, and I'm lazy :-)
> > +/** Looks for an application by looking through the system and user
> > + application directories to find the desktop file.
> > +
> > + \param package Container name
> > + \param appname Application name to look for
> > + \param registry persistent connections to use
> > +*/
> > +bool Legacy::verifyAppname(const AppID::Package& package,
> > + const AppID::AppName& appname,
> > + const std::shared_ptr<Registry>& registry)
> > +{
> > + if (!verifyPackage(package, registry))
> > + {
> > + throw std::runtime_error{"Invalid Legacy package: " + std::string(package)};
> > + }
> > +
> > + auto desktop = std::string(appname) + ".desktop";
> > + auto evaldir = [&desktop](const gchar* dir) -> bool {
> >

>
>
> "-> bool" should be unnecessary; there's only one return point so g++ should be able to deduce the return type
>

Fixed r303. But you can't have this an the "return TRUE" below :-)
> > + if (evaldir(g_get_user_data_dir()))
> > + {
> > + return true;
> > + }
> > +
> > + const char* const* data_dirs = g_get_system_data_dirs();
> >

>
> auto&& data_dirs = g_get_system_data_dirs()
>

r304, cool, wouldn't have guessed that would have worked :-)

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

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

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) wrote :

>> auto&& data_dirs = g_get_system_data_dirs()

> r304, cool, wouldn't have guessed that would have worked :-)

Universal references were introducd in c++11 and we don't use them enough, myself included. It takes a bit of reading to understand what's going them, but the upside is that they're simple to write and generally Do The Right Thing. A much lower bar on esoteric features than, say, variadic templates :-)

First: http://thbecker.net/articles/rvalue_references/section_01.html

Then: https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers

Revision history for this message
Charles Kerr (charlesk) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'docs/Doxyfile'
2--- docs/Doxyfile 2016-04-07 16:01:30 +0000
3+++ docs/Doxyfile 2017-03-18 19:37:40 +0000
4@@ -796,7 +796,7 @@
5 # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
6 # *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
7
8-FILE_PATTERNS =
9+FILE_PATTERNS = *.cpp *.h *.cc
10
11 # The RECURSIVE tag can be used to specify whether or not subdirectories should
12 # be searched for input files as well.
13@@ -811,7 +811,7 @@
14 # Note that relative paths are relative to the directory from which doxygen is
15 # run.
16
17-EXCLUDE =
18+EXCLUDE = libubuntu-app-launch/ubuntu-app-launch.h libubuntu-app-launch/ubuntu-app-launch.cpp
19
20 # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
21 # directories that are symbolic links (a Unix file system feature) are excluded
22
23=== modified file 'docs/index.rst'
24--- docs/index.rst 2017-01-31 21:34:10 +0000
25+++ docs/index.rst 2017-03-18 19:37:40 +0000
26@@ -186,6 +186,56 @@
27 :private-members:
28 :undoc-members:
29
30+Application Storage Base
31+------------------------
32+
33+.. doxygenclass:: ubuntu::app_launch::app_store::Base
34+ :project: libubuntu-app-launch
35+ :members:
36+ :protected-members:
37+ :private-members:
38+ :undoc-members:
39+
40+Application Storage Click
41+-------------------------
42+
43+.. doxygenclass:: ubuntu::app_launch::app_store::Click
44+ :project: libubuntu-app-launch
45+ :members:
46+ :protected-members:
47+ :private-members:
48+ :undoc-members:
49+
50+Application Storage Legacy
51+--------------------------
52+
53+.. doxygenclass:: ubuntu::app_launch::app_store::Legacy
54+ :project: libubuntu-app-launch
55+ :members:
56+ :protected-members:
57+ :private-members:
58+ :undoc-members:
59+
60+Application Storage Libertine
61+-----------------------------
62+
63+.. doxygenclass:: ubuntu::app_launch::app_store::Libertine
64+ :project: libubuntu-app-launch
65+ :members:
66+ :protected-members:
67+ :private-members:
68+ :undoc-members:
69+
70+Application Storage Snap
71+------------------------
72+
73+.. doxygenclass:: ubuntu::app_launch::app_store::Snap
74+ :project: libubuntu-app-launch
75+ :members:
76+ :protected-members:
77+ :private-members:
78+ :undoc-members:
79+
80 Helper Implementation Click
81 ---------------------------
82
83
84=== modified file 'libubuntu-app-launch/CMakeLists.txt'
85--- libubuntu-app-launch/CMakeLists.txt 2017-02-15 15:09:51 +0000
86+++ libubuntu-app-launch/CMakeLists.txt 2017-03-18 19:37:40 +0000
87@@ -35,6 +35,16 @@
88
89 set(LAUNCHER_CPP_SOURCES
90 application.cpp
91+app-store-base.h
92+app-store-base.cpp
93+app-store-click.h
94+app-store-click.cpp
95+app-store-legacy.h
96+app-store-legacy.cpp
97+app-store-libertine.h
98+app-store-libertine.cpp
99+app-store-snap.h
100+app-store-snap.cpp
101 helper.cpp
102 registry.cpp
103 registry-impl.h
104
105=== added file 'libubuntu-app-launch/app-store-base.cpp'
106--- libubuntu-app-launch/app-store-base.cpp 1970-01-01 00:00:00 +0000
107+++ libubuntu-app-launch/app-store-base.cpp 2017-03-18 19:37:40 +0000
108@@ -0,0 +1,63 @@
109+/*
110+ * Copyright © 2017 Canonical Ltd.
111+ *
112+ * This program is free software: you can redistribute it and/or modify it
113+ * under the terms of the GNU General Public License version 3, as published
114+ * by the Free Software Foundation.
115+ *
116+ * This program is distributed in the hope that it will be useful, but
117+ * WITHOUT ANY WARRANTY; without even the implied warranties of
118+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
119+ * PURPOSE. See the GNU General Public License for more details.
120+ *
121+ * You should have received a copy of the GNU General Public License along
122+ * with this program. If not, see <http://www.gnu.org/licenses/>.
123+ *
124+ * Authors:
125+ * Ted Gould <ted.gould@canonical.com>
126+ */
127+
128+#include "app-store-base.h"
129+#include "app-store-click.h"
130+#include "app-store-legacy.h"
131+#include "app-store-libertine.h"
132+
133+#if ENABLE_SNAPPY
134+#include "app-store-snap.h"
135+#endif
136+
137+namespace ubuntu
138+{
139+namespace app_launch
140+{
141+namespace app_store
142+{
143+
144+Base::Base()
145+ : info_watcher::Base({})
146+{
147+}
148+
149+Base::~Base()
150+{
151+}
152+
153+std::list<std::shared_ptr<Base>> Base::allAppStores()
154+{
155+ return
156+ {
157+ std::make_shared<Click>() /* Click */
158+ ,
159+ std::make_shared<Legacy>() /* Legacy */
160+ ,
161+ std::make_shared<Libertine>() /* Libertine */
162+#if ENABLE_SNAPPY
163+ ,
164+ std::make_shared<Snap>() /* Snappy */
165+#endif
166+ };
167+}
168+
169+} // namespace app_store
170+} // namespace app_launch
171+} // namespace ubuntu
172
173=== added file 'libubuntu-app-launch/app-store-base.h'
174--- libubuntu-app-launch/app-store-base.h 1970-01-01 00:00:00 +0000
175+++ libubuntu-app-launch/app-store-base.h 2017-03-18 19:37:40 +0000
176@@ -0,0 +1,65 @@
177+/*
178+ * Copyright © 2017 Canonical Ltd.
179+ *
180+ * This program is free software: you can redistribute it and/or modify it
181+ * under the terms of the GNU General Public License version 3, as published
182+ * by the Free Software Foundation.
183+ *
184+ * This program is distributed in the hope that it will be useful, but
185+ * WITHOUT ANY WARRANTY; without even the implied warranties of
186+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
187+ * PURPOSE. See the GNU General Public License for more details.
188+ *
189+ * You should have received a copy of the GNU General Public License along
190+ * with this program. If not, see <http://www.gnu.org/licenses/>.
191+ *
192+ * Authors:
193+ * Ted Gould <ted.gould@canonical.com>
194+ */
195+
196+#pragma once
197+
198+#include "appid.h"
199+#include "application-impl-base.h"
200+#include "info-watcher.h"
201+#include "registry.h"
202+
203+namespace ubuntu
204+{
205+namespace app_launch
206+{
207+namespace app_store
208+{
209+
210+class Base : public info_watcher::Base
211+{
212+public:
213+ Base();
214+ virtual ~Base();
215+
216+ /* Discover tools */
217+ virtual bool verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry) = 0;
218+ virtual bool verifyAppname(const AppID::Package& package,
219+ const AppID::AppName& appname,
220+ const std::shared_ptr<Registry>& registry) = 0;
221+ virtual AppID::AppName findAppname(const AppID::Package& package,
222+ AppID::ApplicationWildcard card,
223+ const std::shared_ptr<Registry>& registry) = 0;
224+ virtual AppID::Version findVersion(const AppID::Package& package,
225+ const AppID::AppName& appname,
226+ const std::shared_ptr<Registry>& registry) = 0;
227+ virtual bool hasAppId(const AppID& appid, const std::shared_ptr<Registry>& registry) = 0;
228+
229+ /* Possible apps */
230+ virtual std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry) = 0;
231+
232+ /* Application Creation */
233+ virtual std::shared_ptr<app_impls::Base> create(const AppID& appid, const std::shared_ptr<Registry>& registry) = 0;
234+
235+ /* Static get all */
236+ static std::list<std::shared_ptr<Base>> allAppStores();
237+};
238+
239+} // namespace app_store
240+} // namespace app_launch
241+} // namespace ubuntu
242
243=== added file 'libubuntu-app-launch/app-store-click.cpp'
244--- libubuntu-app-launch/app-store-click.cpp 1970-01-01 00:00:00 +0000
245+++ libubuntu-app-launch/app-store-click.cpp 2017-03-18 19:37:40 +0000
246@@ -0,0 +1,248 @@
247+/*
248+ * Copyright © 2017 Canonical Ltd.
249+ *
250+ * This program is free software: you can redistribute it and/or modify it
251+ * under the terms of the GNU General Public License version 3, as published
252+ * by the Free Software Foundation.
253+ *
254+ * This program is distributed in the hope that it will be useful, but
255+ * WITHOUT ANY WARRANTY; without even the implied warranties of
256+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
257+ * PURPOSE. See the GNU General Public License for more details.
258+ *
259+ * You should have received a copy of the GNU General Public License along
260+ * with this program. If not, see <http://www.gnu.org/licenses/>.
261+ *
262+ * Authors:
263+ * Ted Gould <ted.gould@canonical.com>
264+ */
265+
266+#include "app-store-click.h"
267+#include "application-impl-click.h"
268+#include "registry-impl.h"
269+
270+#include <algorithm>
271+
272+namespace ubuntu
273+{
274+namespace app_launch
275+{
276+namespace app_store
277+{
278+
279+std::list<AppID::AppName> manifestApps(const std::shared_ptr<JsonObject>& manifest);
280+AppID::Version manifestVersion(const std::shared_ptr<JsonObject>& manifest);
281+
282+Click::Click()
283+{
284+}
285+
286+Click::~Click()
287+{
288+}
289+
290+/** Tries to get the Click manifest for a package. If it can successfully
291+ get the manifest returns true.
292+
293+ \param package Name of the package
294+ \param registry Persistent connections to use
295+*/
296+bool Click::verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry)
297+{
298+ return registry->impl->getClickManifest(package) != nullptr;
299+}
300+
301+/** Verifies the applicaiton name by getting the list of applications
302+ in the package manifest and seeing if the appname is in the list.
303+
304+ \param package Name of the package
305+ \param appname Name of the application
306+ \param registry Persistent connections to use
307+*/
308+bool Click::verifyAppname(const AppID::Package& package,
309+ const AppID::AppName& appname,
310+ const std::shared_ptr<Registry>& registry)
311+{
312+ auto manifest = registry->impl->getClickManifest(package);
313+ auto apps = manifestApps(manifest);
314+
315+ return std::find_if(apps.begin(), apps.end(), [&appname](const AppID::AppName& listApp) -> bool {
316+ return appname.value() == listApp.value();
317+ }) != apps.end();
318+}
319+
320+/** Finds an application name based on a wildcard search. Gets the list
321+ from the manifest, and then returns a value from that list.
322+
323+ \param package Name of the package
324+ \param card Wildcard to search as
325+ \param registry Persistent connections to use
326+*/
327+AppID::AppName Click::findAppname(const AppID::Package& package,
328+ AppID::ApplicationWildcard card,
329+ const std::shared_ptr<Registry>& registry)
330+{
331+ auto manifest = registry->impl->getClickManifest(package);
332+ auto apps = manifestApps(manifest);
333+
334+ if (apps.empty())
335+ {
336+ throw std::runtime_error("No apps in package '" + package.value() + "' to find");
337+ }
338+
339+ switch (card)
340+ {
341+ case AppID::ApplicationWildcard::FIRST_LISTED:
342+ return *apps.begin();
343+ case AppID::ApplicationWildcard::LAST_LISTED:
344+ return *apps.rbegin();
345+ case AppID::ApplicationWildcard::ONLY_LISTED:
346+ if (apps.size() != 1)
347+ {
348+ throw std::runtime_error("More than a single app in package '" + package.value() +
349+ "' when requested to find only app");
350+ }
351+ return *apps.begin();
352+ }
353+
354+ throw std::logic_error("Got a value of the app wildcard enum that can't exist");
355+}
356+
357+/** Find the version of a package that that is requested
358+
359+ \param package Name of the package
360+ \param appname Name of the application (not used)
361+ \param registry Persistent connections to use
362+*/
363+AppID::Version Click::findVersion(const AppID::Package& package,
364+ const AppID::AppName& appname,
365+ const std::shared_ptr<Registry>& registry)
366+{
367+ auto manifest = registry->impl->getClickManifest(package);
368+ return manifestVersion(manifest);
369+}
370+
371+/** Check to see if this AppID has a desktop file that is in our link
372+ farm built by Click. Click puts a symoblic link there for every
373+ valid AppID.
374+
375+ \param appid Application ID to check
376+ \param registry Persistent connections to use
377+*/
378+bool Click::hasAppId(const AppID& appid, const std::shared_ptr<Registry>& registry)
379+{
380+ std::string appiddesktop = std::string(appid) + ".desktop";
381+ gchar* click_link = nullptr;
382+ const gchar* link_farm_dir = g_getenv("UBUNTU_APP_LAUNCH_LINK_FARM");
383+ if (G_LIKELY(link_farm_dir == nullptr))
384+ {
385+ click_link =
386+ g_build_filename(g_get_user_cache_dir(), "ubuntu-app-launch", "desktop", appiddesktop.c_str(), NULL);
387+ }
388+ else
389+ {
390+ click_link = g_build_filename(link_farm_dir, appiddesktop.c_str(), NULL);
391+ }
392+
393+ bool click = g_file_test(click_link, G_FILE_TEST_EXISTS);
394+ g_free(click_link);
395+
396+ return click;
397+}
398+
399+std::list<std::shared_ptr<Application>> Click::list(const std::shared_ptr<Registry>& registry)
400+{
401+ std::list<std::shared_ptr<Application>> applist;
402+
403+ try
404+ {
405+ for (auto pkg : registry->impl->getClickPackages())
406+ {
407+ try
408+ {
409+ auto manifest = registry->impl->getClickManifest(pkg);
410+
411+ for (auto appname : manifestApps(manifest))
412+ {
413+ try
414+ {
415+ AppID appid{pkg, appname, manifestVersion(manifest)};
416+ auto app = std::make_shared<app_impls::Click>(appid, manifest, registry);
417+ applist.emplace_back(app);
418+ }
419+ catch (std::runtime_error& e)
420+ {
421+ g_debug("Unable to create Click for application '%s' in package '%s': %s",
422+ appname.value().c_str(), pkg.value().c_str(), e.what());
423+ }
424+ }
425+ }
426+ catch (std::runtime_error& e)
427+ {
428+ g_debug("Unable to get information to build Click app on package '%s': %s", pkg.value().c_str(),
429+ e.what());
430+ }
431+ }
432+ }
433+ catch (std::runtime_error& e)
434+ {
435+ g_debug("Unable to get packages from Click database: %s", e.what());
436+ }
437+
438+ return applist;
439+}
440+
441+std::shared_ptr<app_impls::Base> Click::create(const AppID& appid, const std::shared_ptr<Registry>& registry)
442+{
443+ return std::make_shared<app_impls::Click>(appid, registry);
444+}
445+
446+std::list<AppID::AppName> manifestApps(const std::shared_ptr<JsonObject>& manifest)
447+{
448+ JsonObject* hooks = nullptr;
449+ if (!json_object_has_member(manifest.get(), "hooks") ||
450+ (hooks = json_object_get_object_member(manifest.get(), "hooks")) == nullptr)
451+ {
452+ throw std::runtime_error("Manifest does not have a 'hooks' field: " + Registry::Impl::printJson(manifest));
453+ }
454+
455+ auto gapps = json_object_get_members(hooks);
456+ if (gapps == nullptr)
457+ {
458+ throw std::runtime_error("GLib JSON confusion, please talk to your library vendor");
459+ }
460+
461+ std::list<AppID::AppName> apps;
462+
463+ for (GList* item = gapps; item != nullptr; item = g_list_next(item))
464+ {
465+ auto appname = (const gchar*)item->data;
466+
467+ auto hooklist = json_object_get_object_member(hooks, appname);
468+
469+ if (json_object_has_member(hooklist, "desktop") == TRUE)
470+ {
471+ apps.emplace_back(AppID::AppName::from_raw(appname));
472+ }
473+ }
474+
475+ g_list_free(gapps);
476+ return apps;
477+}
478+
479+AppID::Version manifestVersion(const std::shared_ptr<JsonObject>& manifest)
480+{
481+ const gchar* cstr = nullptr;
482+ if (!json_object_has_member(manifest.get(), "version") ||
483+ (cstr = json_object_get_string_member(manifest.get(), "version")) == nullptr)
484+ {
485+ throw std::runtime_error("Unable to find version number in manifest: " + Registry::Impl::printJson(manifest));
486+ }
487+
488+ auto cppstr = AppID::Version::from_raw(cstr);
489+ return cppstr;
490+}
491+
492+} // namespace app_store
493+} // namespace app_launch
494+} // namespace ubuntu
495
496=== added file 'libubuntu-app-launch/app-store-click.h'
497--- libubuntu-app-launch/app-store-click.h 1970-01-01 00:00:00 +0000
498+++ libubuntu-app-launch/app-store-click.h 2017-03-18 19:37:40 +0000
499@@ -0,0 +1,60 @@
500+/*
501+ * Copyright © 2017 Canonical Ltd.
502+ *
503+ * This program is free software: you can redistribute it and/or modify it
504+ * under the terms of the GNU General Public License version 3, as published
505+ * by the Free Software Foundation.
506+ *
507+ * This program is distributed in the hope that it will be useful, but
508+ * WITHOUT ANY WARRANTY; without even the implied warranties of
509+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
510+ * PURPOSE. See the GNU General Public License for more details.
511+ *
512+ * You should have received a copy of the GNU General Public License along
513+ * with this program. If not, see <http://www.gnu.org/licenses/>.
514+ *
515+ * Authors:
516+ * Ted Gould <ted.gould@canonical.com>
517+ */
518+
519+#pragma once
520+
521+#include "app-store-base.h"
522+
523+namespace ubuntu
524+{
525+namespace app_launch
526+{
527+namespace app_store
528+{
529+
530+class Click : public Base
531+{
532+public:
533+ Click();
534+ virtual ~Click();
535+
536+ /* Discover tools */
537+ virtual bool verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry) override;
538+ virtual bool verifyAppname(const AppID::Package& package,
539+ const AppID::AppName& appname,
540+ const std::shared_ptr<Registry>& registry) override;
541+ virtual AppID::AppName findAppname(const AppID::Package& package,
542+ AppID::ApplicationWildcard card,
543+ const std::shared_ptr<Registry>& registry) override;
544+ virtual AppID::Version findVersion(const AppID::Package& package,
545+ const AppID::AppName& appname,
546+ const std::shared_ptr<Registry>& registry) override;
547+ virtual bool hasAppId(const AppID& appid, const std::shared_ptr<Registry>& registry) override;
548+
549+ /* Possible apps */
550+ virtual std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry) override;
551+
552+ /* Application Creation */
553+ virtual std::shared_ptr<app_impls::Base> create(const AppID& appid,
554+ const std::shared_ptr<Registry>& registry) override;
555+};
556+
557+} // namespace app_store
558+} // namespace app_launch
559+} // namespace ubuntu
560
561=== added file 'libubuntu-app-launch/app-store-legacy.cpp'
562--- libubuntu-app-launch/app-store-legacy.cpp 1970-01-01 00:00:00 +0000
563+++ libubuntu-app-launch/app-store-legacy.cpp 2017-03-18 19:37:40 +0000
564@@ -0,0 +1,202 @@
565+/*
566+ * Copyright © 2017 Canonical Ltd.
567+ *
568+ * This program is free software: you can redistribute it and/or modify it
569+ * under the terms of the GNU General Public License version 3, as published
570+ * by the Free Software Foundation.
571+ *
572+ * This program is distributed in the hope that it will be useful, but
573+ * WITHOUT ANY WARRANTY; without even the implied warranties of
574+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
575+ * PURPOSE. See the GNU General Public License for more details.
576+ *
577+ * You should have received a copy of the GNU General Public License along
578+ * with this program. If not, see <http://www.gnu.org/licenses/>.
579+ *
580+ * Authors:
581+ * Ted Gould <ted.gould@canonical.com>
582+ */
583+
584+#include "app-store-legacy.h"
585+#include "application-impl-legacy.h"
586+
587+#include <regex>
588+
589+namespace ubuntu
590+{
591+namespace app_launch
592+{
593+namespace app_store
594+{
595+
596+Legacy::Legacy()
597+{
598+}
599+
600+Legacy::~Legacy()
601+{
602+}
603+
604+/** Checks the AppID by ensuring the version and package are empty
605+ then looks for the application.
606+
607+ \param appid AppID to check
608+ \param registry persistent connections to use
609+*/
610+bool Legacy::hasAppId(const AppID& appid, const std::shared_ptr<Registry>& registry)
611+{
612+ try
613+ {
614+ if (!appid.version.value().empty())
615+ {
616+ return false;
617+ }
618+
619+ return verifyAppname(appid.package, appid.appname, registry);
620+ }
621+ catch (std::runtime_error& e)
622+ {
623+ return false;
624+ }
625+}
626+
627+/** Ensure the package is empty
628+
629+ \param package Container name
630+ \param registry persistent connections to use
631+*/
632+bool Legacy::verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry)
633+{
634+ return package.value().empty();
635+}
636+
637+/** Looks for an application by looking through the system and user
638+ application directories to find the desktop file.
639+
640+ \param package Container name
641+ \param appname Application name to look for
642+ \param registry persistent connections to use
643+*/
644+bool Legacy::verifyAppname(const AppID::Package& package,
645+ const AppID::AppName& appname,
646+ const std::shared_ptr<Registry>& registry)
647+{
648+ if (!verifyPackage(package, registry))
649+ {
650+ throw std::runtime_error{"Invalid Legacy package: " + std::string(package)};
651+ }
652+
653+ auto desktop = std::string(appname) + ".desktop";
654+ auto evaldir = [&desktop](const gchar* dir) {
655+ char* fulldir = g_build_filename(dir, "applications", desktop.c_str(), nullptr);
656+ gboolean found = g_file_test(fulldir, G_FILE_TEST_EXISTS);
657+ g_free(fulldir);
658+ return found == TRUE;
659+ };
660+
661+ if (evaldir(g_get_user_data_dir()))
662+ {
663+ return true;
664+ }
665+
666+ auto&& data_dirs = g_get_system_data_dirs();
667+ for (int i = 0; data_dirs[i] != nullptr; i++)
668+ {
669+ if (evaldir(data_dirs[i]))
670+ {
671+ return true;
672+ }
673+ }
674+
675+ return false;
676+}
677+
678+/** We don't really have a way to implement this for Legacy, any
679+ search wouldn't really make sense. We just throw an error.
680+
681+ \param package Container name
682+ \param card Application search paths
683+ \param registry persistent connections to use
684+*/
685+AppID::AppName Legacy::findAppname(const AppID::Package& package,
686+ AppID::ApplicationWildcard card,
687+ const std::shared_ptr<Registry>& registry)
688+{
689+ throw std::runtime_error("Legacy apps can't be discovered by package");
690+}
691+
692+/** Function to return an empty string
693+
694+ \param package Container name (unused)
695+ \param appname Application name (unused)
696+ \param registry persistent connections to use (unused)
697+*/
698+AppID::Version Legacy::findVersion(const AppID::Package& package,
699+ const AppID::AppName& appname,
700+ const std::shared_ptr<Registry>& registry)
701+{
702+ return AppID::Version::from_raw({});
703+}
704+
705+static const std::regex desktop_remover("^(.*)\\.desktop$");
706+
707+std::list<std::shared_ptr<Application>> Legacy::list(const std::shared_ptr<Registry>& registry)
708+{
709+ std::list<std::shared_ptr<Application>> list;
710+ GList* head = g_app_info_get_all();
711+ for (GList* item = head; item != nullptr; item = g_list_next(item))
712+ {
713+ GDesktopAppInfo* appinfo = G_DESKTOP_APP_INFO(item->data);
714+
715+ if (appinfo == nullptr)
716+ {
717+ continue;
718+ }
719+
720+ if (g_app_info_should_show(G_APP_INFO(appinfo)) == FALSE)
721+ {
722+ continue;
723+ }
724+
725+ auto desktopappid = std::string(g_app_info_get_id(G_APP_INFO(appinfo)));
726+ std::string appname;
727+ std::smatch match;
728+ if (std::regex_match(desktopappid, match, desktop_remover))
729+ {
730+ appname = match[1].str();
731+ }
732+ else
733+ {
734+ continue;
735+ }
736+
737+ /* Remove entries generated by the desktop hook in .local */
738+ if (g_desktop_app_info_has_key(appinfo, "X-Ubuntu-Application-ID"))
739+ {
740+ continue;
741+ }
742+
743+ try
744+ {
745+ auto app = std::make_shared<app_impls::Legacy>(AppID::AppName::from_raw(appname), registry);
746+ list.push_back(app);
747+ }
748+ catch (std::runtime_error& e)
749+ {
750+ g_debug("Unable to create application for legacy appname '%s': %s", appname.c_str(), e.what());
751+ }
752+ }
753+
754+ g_list_free_full(head, g_object_unref);
755+
756+ return list;
757+}
758+
759+std::shared_ptr<app_impls::Base> Legacy::create(const AppID& appid, const std::shared_ptr<Registry>& registry)
760+{
761+ return std::make_shared<app_impls::Legacy>(appid.appname, registry);
762+}
763+
764+} // namespace app_store
765+} // namespace app_launch
766+} // namespace ubuntu
767
768=== added file 'libubuntu-app-launch/app-store-legacy.h'
769--- libubuntu-app-launch/app-store-legacy.h 1970-01-01 00:00:00 +0000
770+++ libubuntu-app-launch/app-store-legacy.h 2017-03-18 19:37:40 +0000
771@@ -0,0 +1,60 @@
772+/*
773+ * Copyright © 2017 Canonical Ltd.
774+ *
775+ * This program is free software: you can redistribute it and/or modify it
776+ * under the terms of the GNU General Public License version 3, as published
777+ * by the Free Software Foundation.
778+ *
779+ * This program is distributed in the hope that it will be useful, but
780+ * WITHOUT ANY WARRANTY; without even the implied warranties of
781+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
782+ * PURPOSE. See the GNU General Public License for more details.
783+ *
784+ * You should have received a copy of the GNU General Public License along
785+ * with this program. If not, see <http://www.gnu.org/licenses/>.
786+ *
787+ * Authors:
788+ * Ted Gould <ted.gould@canonical.com>
789+ */
790+
791+#pragma once
792+
793+#include "app-store-base.h"
794+
795+namespace ubuntu
796+{
797+namespace app_launch
798+{
799+namespace app_store
800+{
801+
802+class Legacy : public Base
803+{
804+public:
805+ Legacy();
806+ virtual ~Legacy();
807+
808+ /* Discover tools */
809+ virtual bool verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry) override;
810+ virtual bool verifyAppname(const AppID::Package& package,
811+ const AppID::AppName& appname,
812+ const std::shared_ptr<Registry>& registry) override;
813+ virtual AppID::AppName findAppname(const AppID::Package& package,
814+ AppID::ApplicationWildcard card,
815+ const std::shared_ptr<Registry>& registry) override;
816+ virtual AppID::Version findVersion(const AppID::Package& package,
817+ const AppID::AppName& appname,
818+ const std::shared_ptr<Registry>& registry) override;
819+ virtual bool hasAppId(const AppID& appid, const std::shared_ptr<Registry>& registry) override;
820+
821+ /* Possible apps */
822+ virtual std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry) override;
823+
824+ /* Application Creation */
825+ virtual std::shared_ptr<app_impls::Base> create(const AppID& appid,
826+ const std::shared_ptr<Registry>& registry) override;
827+};
828+
829+} // namespace app_store
830+} // namespace app_launch
831+} // namespace ubuntu
832
833=== added file 'libubuntu-app-launch/app-store-libertine.cpp'
834--- libubuntu-app-launch/app-store-libertine.cpp 1970-01-01 00:00:00 +0000
835+++ libubuntu-app-launch/app-store-libertine.cpp 2017-03-18 19:37:40 +0000
836@@ -0,0 +1,173 @@
837+/*
838+ * Copyright © 2017 Canonical Ltd.
839+ *
840+ * This program is free software: you can redistribute it and/or modify it
841+ * under the terms of the GNU General Public License version 3, as published
842+ * by the Free Software Foundation.
843+ *
844+ * This program is distributed in the hope that it will be useful, but
845+ * WITHOUT ANY WARRANTY; without even the implied warranties of
846+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
847+ * PURPOSE. See the GNU General Public License for more details.
848+ *
849+ * You should have received a copy of the GNU General Public License along
850+ * with this program. If not, see <http://www.gnu.org/licenses/>.
851+ *
852+ * Authors:
853+ * Ted Gould <ted.gould@canonical.com>
854+ */
855+
856+#include "app-store-libertine.h"
857+#include "application-impl-libertine.h"
858+
859+#include "libertine.h"
860+
861+namespace ubuntu
862+{
863+namespace app_launch
864+{
865+namespace app_store
866+{
867+
868+Libertine::Libertine()
869+{
870+}
871+
872+Libertine::~Libertine()
873+{
874+}
875+
876+/** Checks the AppID by making sure the version is "0.0" and then
877+ calling verifyAppname() to check the rest.
878+
879+ \param appid AppID to check
880+ \param registry persistent connections to use
881+*/
882+bool Libertine::hasAppId(const AppID& appid, const std::shared_ptr<Registry>& registry)
883+{
884+ try
885+ {
886+ if (appid.version.value() != "0.0")
887+ {
888+ return false;
889+ }
890+
891+ return verifyAppname(appid.package, appid.appname, registry);
892+ }
893+ catch (std::runtime_error& e)
894+ {
895+ return false;
896+ }
897+}
898+
899+/** Verify a package name by getting the list of containers from
900+ liblibertine and ensuring it is in that list.
901+
902+ \param package Container name
903+ \param registry persistent connections to use
904+*/
905+bool Libertine::verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry)
906+{
907+ auto containers = std::shared_ptr<gchar*>(libertine_list_containers(), g_strfreev);
908+
909+ for (int i = 0; containers.get()[i] != nullptr; i++)
910+ {
911+ auto container = containers.get()[i];
912+ if (container == package.value())
913+ {
914+ return true;
915+ }
916+ }
917+
918+ return false;
919+}
920+
921+/** Gets the list of applications from the container using liblibertine
922+ and see if @appname is in that list.
923+
924+ \param package Container name
925+ \param appname Application name to look for
926+ \param registry persistent connections to use
927+*/
928+bool Libertine::verifyAppname(const AppID::Package& package,
929+ const AppID::AppName& appname,
930+ const std::shared_ptr<Registry>& registry)
931+{
932+ auto apps = std::shared_ptr<gchar*>(libertine_list_apps_for_container(package.value().c_str()), g_strfreev);
933+
934+ for (int i = 0; apps.get()[i] != nullptr; i++)
935+ {
936+ auto appid = AppID::parse(apps.get()[i]);
937+ if (appid.appname.value() == appname.value())
938+ {
939+ return true;
940+ }
941+ }
942+
943+ return false;
944+}
945+
946+/** We don't really have a way to implement this for Libertine, any
947+ search wouldn't really make sense. We just throw an error.
948+
949+ \param package Container name
950+ \param card Application search paths
951+ \param registry persistent connections to use
952+*/
953+AppID::AppName Libertine::findAppname(const AppID::Package& package,
954+ AppID::ApplicationWildcard card,
955+ const std::shared_ptr<Registry>& registry)
956+{
957+ throw std::runtime_error("Legacy apps can't be discovered by package");
958+}
959+
960+/** Function to return "0.0"
961+
962+ \param package Container name (unused)
963+ \param appname Application name (unused)
964+ \param registry persistent connections to use (unused)
965+*/
966+AppID::Version Libertine::findVersion(const AppID::Package& package,
967+ const AppID::AppName& appname,
968+ const std::shared_ptr<Registry>& registry)
969+{
970+ return AppID::Version::from_raw("0.0");
971+}
972+
973+std::list<std::shared_ptr<Application>> Libertine::list(const std::shared_ptr<Registry>& registry)
974+{
975+ std::list<std::shared_ptr<Application>> applist;
976+
977+ auto containers = std::shared_ptr<gchar*>(libertine_list_containers(), g_strfreev);
978+
979+ for (int i = 0; containers.get()[i] != nullptr; i++)
980+ {
981+ auto container = containers.get()[i];
982+ auto apps = std::shared_ptr<gchar*>(libertine_list_apps_for_container(container), g_strfreev);
983+
984+ for (int j = 0; apps.get()[j] != nullptr; j++)
985+ {
986+ try
987+ {
988+ auto appid = AppID::parse(apps.get()[j]);
989+ auto sapp = std::make_shared<app_impls::Libertine>(appid.package, appid.appname, registry);
990+ applist.emplace_back(sapp);
991+ }
992+ catch (std::runtime_error& e)
993+ {
994+ g_debug("Unable to create application for libertine appname '%s': %s", apps.get()[j], e.what());
995+ }
996+ }
997+ }
998+
999+ return applist;
1000+}
1001+
1002+std::shared_ptr<app_impls::Base> Libertine::create(const AppID& appid, const std::shared_ptr<Registry>& registry)
1003+{
1004+ return std::make_shared<app_impls::Libertine>(appid.package, appid.appname, registry);
1005+}
1006+
1007+} // namespace app_store
1008+} // namespace app_launch
1009+} // namespace ubuntu
1010
1011=== added file 'libubuntu-app-launch/app-store-libertine.h'
1012--- libubuntu-app-launch/app-store-libertine.h 1970-01-01 00:00:00 +0000
1013+++ libubuntu-app-launch/app-store-libertine.h 2017-03-18 19:37:40 +0000
1014@@ -0,0 +1,60 @@
1015+/*
1016+ * Copyright © 2017 Canonical Ltd.
1017+ *
1018+ * This program is free software: you can redistribute it and/or modify it
1019+ * under the terms of the GNU General Public License version 3, as published
1020+ * by the Free Software Foundation.
1021+ *
1022+ * This program is distributed in the hope that it will be useful, but
1023+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1024+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1025+ * PURPOSE. See the GNU General Public License for more details.
1026+ *
1027+ * You should have received a copy of the GNU General Public License along
1028+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1029+ *
1030+ * Authors:
1031+ * Ted Gould <ted.gould@canonical.com>
1032+ */
1033+
1034+#pragma once
1035+
1036+#include "app-store-base.h"
1037+
1038+namespace ubuntu
1039+{
1040+namespace app_launch
1041+{
1042+namespace app_store
1043+{
1044+
1045+class Libertine : public Base
1046+{
1047+public:
1048+ Libertine();
1049+ virtual ~Libertine();
1050+
1051+ /* Discover tools */
1052+ virtual bool verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry) override;
1053+ virtual bool verifyAppname(const AppID::Package& package,
1054+ const AppID::AppName& appname,
1055+ const std::shared_ptr<Registry>& registry) override;
1056+ virtual AppID::AppName findAppname(const AppID::Package& package,
1057+ AppID::ApplicationWildcard card,
1058+ const std::shared_ptr<Registry>& registry) override;
1059+ virtual AppID::Version findVersion(const AppID::Package& package,
1060+ const AppID::AppName& appname,
1061+ const std::shared_ptr<Registry>& registry) override;
1062+ virtual bool hasAppId(const AppID& appid, const std::shared_ptr<Registry>& registry) override;
1063+
1064+ /* Possible apps */
1065+ virtual std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry) override;
1066+
1067+ /* Application Creation */
1068+ virtual std::shared_ptr<app_impls::Base> create(const AppID& appid,
1069+ const std::shared_ptr<Registry>& registry) override;
1070+};
1071+
1072+} // namespace app_store
1073+} // namespace app_launch
1074+} // namespace ubuntu
1075
1076=== added file 'libubuntu-app-launch/app-store-snap.cpp'
1077--- libubuntu-app-launch/app-store-snap.cpp 1970-01-01 00:00:00 +0000
1078+++ libubuntu-app-launch/app-store-snap.cpp 2017-03-18 19:37:40 +0000
1079@@ -0,0 +1,231 @@
1080+/*
1081+ * Copyright © 2017 Canonical Ltd.
1082+ *
1083+ * This program is free software: you can redistribute it and/or modify it
1084+ * under the terms of the GNU General Public License version 3, as published
1085+ * by the Free Software Foundation.
1086+ *
1087+ * This program is distributed in the hope that it will be useful, but
1088+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1089+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1090+ * PURPOSE. See the GNU General Public License for more details.
1091+ *
1092+ * You should have received a copy of the GNU General Public License along
1093+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1094+ *
1095+ * Authors:
1096+ * Ted Gould <ted.gould@canonical.com>
1097+ */
1098+
1099+#include "app-store-snap.h"
1100+#include "application-impl-snap.h"
1101+#include "registry-impl.h"
1102+
1103+#include <regex>
1104+
1105+namespace ubuntu
1106+{
1107+namespace app_launch
1108+{
1109+namespace app_store
1110+{
1111+
1112+/************************
1113+ ** Interface Lists
1114+ ************************/
1115+
1116+/** All the interfaces that we run XMir for by default */
1117+const std::set<std::string> X11_INTERFACES{"unity7", "x11"};
1118+/** The interface to indicate direct Mir support */
1119+const std::string MIR_INTERFACE{"mir"};
1120+/** The interface to indicate Ubuntu lifecycle support */
1121+const std::string LIFECYCLE_INTERFACE{"unity8"};
1122+/** Snappy has more restrictive appnames than everyone else */
1123+const std::regex appnameRegex{"^[a-zA-Z0-9](?:-?[a-zA-Z0-9])*$"};
1124+
1125+Snap::Snap()
1126+{
1127+}
1128+
1129+Snap::~Snap()
1130+{
1131+}
1132+
1133+/** Checks if an AppID could be a snap. Note it doesn't look for a desktop
1134+ file just the package, app and version. This is done to make the lookup
1135+ quickly, as this function can be used to select which backend to use
1136+ and we want to reject quickly.
1137+
1138+ \param appid Application ID of the snap
1139+ \param registry Registry to use for persistent connections
1140+*/
1141+bool Snap::hasAppId(const AppID& appId, const std::shared_ptr<Registry>& registry)
1142+{
1143+ if (appId.package.value().empty() || appId.version.value().empty())
1144+ {
1145+ return false;
1146+ }
1147+
1148+ if (!std::regex_match(appId.appname.value(), appnameRegex))
1149+ {
1150+ return false;
1151+ }
1152+
1153+ auto pkginfo = registry->impl->snapdInfo.pkgInfo(appId.package);
1154+ return app_impls::Snap::checkPkgInfo(pkginfo, appId);
1155+}
1156+
1157+/** Look to see if a package is a valid Snap package name
1158+
1159+ \param package Package name
1160+ \param registry Registry to use for persistent connections
1161+*/
1162+bool Snap::verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry)
1163+{
1164+ try
1165+ {
1166+ auto pkgInfo = registry->impl->snapdInfo.pkgInfo(package);
1167+ return pkgInfo != nullptr;
1168+ }
1169+ catch (std::runtime_error& e)
1170+ {
1171+ return false;
1172+ }
1173+}
1174+
1175+/** Look to see if an appname is a valid for a Snap package
1176+
1177+ \param package Package name
1178+ \param appname Command name
1179+ \param registry Registry to use for persistent connections
1180+*/
1181+bool Snap::verifyAppname(const AppID::Package& package,
1182+ const AppID::AppName& appname,
1183+ const std::shared_ptr<Registry>& registry)
1184+{
1185+ if (!std::regex_match(appname.value(), appnameRegex))
1186+ {
1187+ return false;
1188+ }
1189+
1190+ auto pkgInfo = registry->impl->snapdInfo.pkgInfo(package);
1191+ return pkgInfo->appnames.find(appname) != pkgInfo->appnames.end();
1192+}
1193+
1194+/** Look for an application name on a Snap package based on a
1195+ wildcard type.
1196+
1197+ \param package Package name
1198+ \param card Wildcard to use for finding the appname
1199+ \param registry Registry to use for persistent connections
1200+*/
1201+AppID::AppName Snap::findAppname(const AppID::Package& package,
1202+ AppID::ApplicationWildcard card,
1203+ const std::shared_ptr<Registry>& registry)
1204+{
1205+ auto pkgInfo = registry->impl->snapdInfo.pkgInfo(package);
1206+
1207+ if (pkgInfo->appnames.empty())
1208+ {
1209+ throw std::runtime_error("No apps in package '" + package.value() + "' to find");
1210+ }
1211+
1212+ switch (card)
1213+ {
1214+ case AppID::ApplicationWildcard::FIRST_LISTED:
1215+ return AppID::AppName::from_raw(*pkgInfo->appnames.begin());
1216+ case AppID::ApplicationWildcard::LAST_LISTED:
1217+ return AppID::AppName::from_raw(*pkgInfo->appnames.rbegin());
1218+ case AppID::ApplicationWildcard::ONLY_LISTED:
1219+ if (pkgInfo->appnames.size() != 1)
1220+ {
1221+ throw std::runtime_error("More than a single app in package '" + package.value() +
1222+ "' when requested to find only app");
1223+ }
1224+ return AppID::AppName::from_raw(*pkgInfo->appnames.begin());
1225+ }
1226+
1227+ throw std::logic_error("Got a value of the app wildcard enum that can't exist");
1228+}
1229+
1230+/** Look for a version of a Snap package
1231+
1232+ \param package Package name
1233+ \param appname Not used for snaps
1234+ \param registry Registry to use for persistent connections
1235+*/
1236+AppID::Version Snap::findVersion(const AppID::Package& package,
1237+ const AppID::AppName& appname,
1238+ const std::shared_ptr<Registry>& registry)
1239+{
1240+ auto pkgInfo = registry->impl->snapdInfo.pkgInfo(package);
1241+ return AppID::Version::from_raw(pkgInfo->revision);
1242+}
1243+
1244+/** Operator to compare apps for our sets */
1245+struct appcompare
1246+{
1247+ bool operator()(const std::shared_ptr<Application>& a, const std::shared_ptr<Application>& b) const
1248+ {
1249+ return a->appId() < b->appId();
1250+ }
1251+};
1252+
1253+/** Lists all the Snappy apps that are using one of our supported interfaces.
1254+ Also makes sure they're valid.
1255+
1256+ \param registry Registry to use for persistent connections
1257+*/
1258+std::list<std::shared_ptr<Application>> Snap::list(const std::shared_ptr<Registry>& registry)
1259+{
1260+ std::set<std::shared_ptr<Application>, appcompare> apps;
1261+
1262+ auto lifecycleApps = registry->impl->snapdInfo.appsForInterface(LIFECYCLE_INTERFACE);
1263+
1264+ auto lifecycleForApp = [&](const AppID& appID) {
1265+ auto iterator = lifecycleApps.find(appID);
1266+ if (iterator == lifecycleApps.end())
1267+ {
1268+ return Application::Info::UbuntuLifecycle::from_raw(false);
1269+ }
1270+ else
1271+ {
1272+ return Application::Info::UbuntuLifecycle::from_raw(true);
1273+ }
1274+ };
1275+
1276+ auto addAppsForInterface = [&](const std::string& interface, app_info::Desktop::XMirEnable xMirEnable) {
1277+ for (const auto& id : registry->impl->snapdInfo.appsForInterface(interface))
1278+ {
1279+ auto interfaceInfo = std::make_tuple(xMirEnable, lifecycleForApp(id));
1280+ try
1281+ {
1282+ auto app = std::make_shared<app_impls::Snap>(id, registry, interfaceInfo);
1283+ apps.emplace(app);
1284+ }
1285+ catch (std::runtime_error& e)
1286+ {
1287+ g_debug("Unable to make Snap object for '%s': %s", std::string(id).c_str(), e.what());
1288+ }
1289+ }
1290+ };
1291+
1292+ addAppsForInterface(MIR_INTERFACE, app_info::Desktop::XMirEnable::from_raw(false));
1293+
1294+ /* If an app has both, this will get rejected */
1295+ for (const auto& interface : X11_INTERFACES)
1296+ {
1297+ addAppsForInterface(interface, app_info::Desktop::XMirEnable::from_raw(true));
1298+ }
1299+
1300+ return std::list<std::shared_ptr<Application>>(apps.begin(), apps.end());
1301+}
1302+
1303+std::shared_ptr<app_impls::Base> Snap::create(const AppID& appid, const std::shared_ptr<Registry>& registry)
1304+{
1305+ return std::make_shared<app_impls::Snap>(appid, registry);
1306+}
1307+
1308+} // namespace app_store
1309+} // namespace app_launch
1310+} // namespace ubuntu
1311
1312=== added file 'libubuntu-app-launch/app-store-snap.h'
1313--- libubuntu-app-launch/app-store-snap.h 1970-01-01 00:00:00 +0000
1314+++ libubuntu-app-launch/app-store-snap.h 2017-03-18 19:37:40 +0000
1315@@ -0,0 +1,60 @@
1316+/*
1317+ * Copyright © 2017 Canonical Ltd.
1318+ *
1319+ * This program is free software: you can redistribute it and/or modify it
1320+ * under the terms of the GNU General Public License version 3, as published
1321+ * by the Free Software Foundation.
1322+ *
1323+ * This program is distributed in the hope that it will be useful, but
1324+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1325+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1326+ * PURPOSE. See the GNU General Public License for more details.
1327+ *
1328+ * You should have received a copy of the GNU General Public License along
1329+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1330+ *
1331+ * Authors:
1332+ * Ted Gould <ted.gould@canonical.com>
1333+ */
1334+
1335+#pragma once
1336+
1337+#include "app-store-base.h"
1338+
1339+namespace ubuntu
1340+{
1341+namespace app_launch
1342+{
1343+namespace app_store
1344+{
1345+
1346+class Snap : public Base
1347+{
1348+public:
1349+ Snap();
1350+ virtual ~Snap();
1351+
1352+ /* Discover tools */
1353+ virtual bool verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry) override;
1354+ virtual bool verifyAppname(const AppID::Package& package,
1355+ const AppID::AppName& appname,
1356+ const std::shared_ptr<Registry>& registry) override;
1357+ virtual AppID::AppName findAppname(const AppID::Package& package,
1358+ AppID::ApplicationWildcard card,
1359+ const std::shared_ptr<Registry>& registry) override;
1360+ virtual AppID::Version findVersion(const AppID::Package& package,
1361+ const AppID::AppName& appname,
1362+ const std::shared_ptr<Registry>& registry) override;
1363+ virtual bool hasAppId(const AppID& appid, const std::shared_ptr<Registry>& registry) override;
1364+
1365+ /* Possible apps */
1366+ virtual std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry) override;
1367+
1368+ /* Application Creation */
1369+ virtual std::shared_ptr<app_impls::Base> create(const AppID& appid,
1370+ const std::shared_ptr<Registry>& registry) override;
1371+};
1372+
1373+} // namespace app_store
1374+} // namespace app_launch
1375+} // namespace ubuntu
1376
1377=== modified file 'libubuntu-app-launch/application-impl-base.cpp'
1378--- libubuntu-app-launch/application-impl-base.cpp 2017-02-15 15:09:51 +0000
1379+++ libubuntu-app-launch/application-impl-base.cpp 2017-03-18 19:37:40 +0000
1380@@ -24,10 +24,6 @@
1381 #include <numeric>
1382
1383 #include "application-impl-base.h"
1384-#include "application-impl-click.h"
1385-#include "application-impl-legacy.h"
1386-#include "application-impl-libertine.h"
1387-#include "application-impl-snap.h"
1388 #include "helpers.h"
1389 #include "registry-impl.h"
1390 #include "second-exec-core.h"
1391@@ -54,39 +50,6 @@
1392 g_debug("Application deconstruction: %p", static_cast<void*>(this));
1393 }
1394
1395-/* Put all the logic into a function so that we can deal have a simple
1396- function to deal with each subtype */
1397-template <typename T>
1398-void watcher_append_list(const std::shared_ptr<Registry>& reg, std::list<std::shared_ptr<info_watcher::Base>>& list)
1399-{
1400- auto watcher = T::createInfoWatcher(reg);
1401-
1402- if (watcher)
1403- {
1404- list.push_back(watcher);
1405- }
1406-}
1407-
1408-/* This little template makes it so that we can take a list, but
1409- then break it down to calls to the base function. */
1410-template <typename T, typename T2, typename... TArgs>
1411-void watcher_append_list(const std::shared_ptr<Registry>& reg, std::list<std::shared_ptr<info_watcher::Base>>& list)
1412-{
1413- watcher_append_list<T>(reg, list);
1414- watcher_append_list<T2, TArgs...>(reg, list);
1415-}
1416-
1417-/** Builds an info watcher from each subclass and returns the list of
1418- them to the registry */
1419-std::list<std::shared_ptr<info_watcher::Base>> Base::createInfoWatchers(const std::shared_ptr<Registry>& reg)
1420-{
1421- std::list<std::shared_ptr<info_watcher::Base>> retval;
1422-
1423- watcher_append_list<app_impls::Click, app_impls::Legacy, app_impls::Libertine, app_impls::Snap>(reg, retval);
1424-
1425- return retval;
1426-}
1427-
1428 bool Base::hasInstances()
1429 {
1430 return !instances().empty();
1431
1432=== modified file 'libubuntu-app-launch/application-impl-base.h'
1433--- libubuntu-app-launch/application-impl-base.h 2017-02-15 15:09:51 +0000
1434+++ libubuntu-app-launch/application-impl-base.h 2017-03-18 19:37:40 +0000
1435@@ -50,8 +50,6 @@
1436 virtual std::shared_ptr<Application::Instance> findInstance(const std::string& instanceid) = 0;
1437 std::shared_ptr<Application::Instance> findInstance(const pid_t& pid);
1438
1439- static std::list<std::shared_ptr<info_watcher::Base>> createInfoWatchers(const std::shared_ptr<Registry>& reg);
1440-
1441 protected:
1442 /** Pointer to the registry so we can ask it for things */
1443 std::shared_ptr<Registry> _registry;
1444
1445=== modified file 'libubuntu-app-launch/application-impl-click.cpp'
1446--- libubuntu-app-launch/application-impl-click.cpp 2017-02-15 15:09:51 +0000
1447+++ libubuntu-app-launch/application-impl-click.cpp 2017-03-18 19:37:40 +0000
1448@@ -30,8 +30,6 @@
1449 namespace app_impls
1450 {
1451
1452-AppID::Version manifestVersion(const std::shared_ptr<JsonObject>& manifest);
1453-std::list<AppID::AppName> manifestApps(const std::shared_ptr<JsonObject>& manifest);
1454 std::pair<std::shared_ptr<GKeyFile>, std::string> manifestAppDesktop(const std::shared_ptr<JsonObject>& manifest,
1455 const std::string& package,
1456 const std::string& app,
1457@@ -60,115 +58,6 @@
1458 return _appid;
1459 }
1460
1461-/** Check to see if this AppID has a desktop file that is in our link
1462- farm built by Click. Click puts a symoblic link there for every
1463- valid AppID.
1464-
1465- \param appid Application ID to check
1466- \param registry Persistent connections to use
1467-*/
1468-bool Click::hasAppId(const AppID& appid, const std::shared_ptr<Registry>& registry)
1469-{
1470- std::string appiddesktop = std::string(appid) + ".desktop";
1471- gchar* click_link = nullptr;
1472- const gchar* link_farm_dir = g_getenv("UBUNTU_APP_LAUNCH_LINK_FARM");
1473- if (G_LIKELY(link_farm_dir == nullptr))
1474- {
1475- click_link =
1476- g_build_filename(g_get_user_cache_dir(), "ubuntu-app-launch", "desktop", appiddesktop.c_str(), NULL);
1477- }
1478- else
1479- {
1480- click_link = g_build_filename(link_farm_dir, appiddesktop.c_str(), NULL);
1481- }
1482-
1483- bool click = g_file_test(click_link, G_FILE_TEST_EXISTS);
1484- g_free(click_link);
1485-
1486- return click;
1487-}
1488-
1489-/** Tries to get the Click manifest for a package. If it can successfully
1490- get the manifest returns true.
1491-
1492- \param package Name of the package
1493- \param registry Persistent connections to use
1494-*/
1495-bool Click::verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry)
1496-{
1497- return registry->impl->getClickManifest(package) != nullptr;
1498-}
1499-
1500-/** Verifies the applicaiton name by getting the list of applications
1501- in the package manifest and seeing if the appname is in the list.
1502-
1503- \param package Name of the package
1504- \param appname Name of the application
1505- \param registry Persistent connections to use
1506-*/
1507-bool Click::verifyAppname(const AppID::Package& package,
1508- const AppID::AppName& appname,
1509- const std::shared_ptr<Registry>& registry)
1510-{
1511- auto manifest = registry->impl->getClickManifest(package);
1512- auto apps = manifestApps(manifest);
1513-
1514- return std::find_if(apps.begin(), apps.end(), [&appname](const AppID::AppName& listApp) -> bool {
1515- return appname.value() == listApp.value();
1516- }) != apps.end();
1517-}
1518-
1519-/** Finds an application name based on a wildcard search. Gets the list
1520- from the manifest, and then returns a value from that list.
1521-
1522- \param package Name of the package
1523- \param card Wildcard to search as
1524- \param registry Persistent connections to use
1525-*/
1526-AppID::AppName Click::findAppname(const AppID::Package& package,
1527- AppID::ApplicationWildcard card,
1528- const std::shared_ptr<Registry>& registry)
1529-{
1530- auto manifest = registry->impl->getClickManifest(package);
1531- auto apps = manifestApps(manifest);
1532-
1533- if (apps.empty())
1534- {
1535- throw std::runtime_error("No apps in package '" + package.value() + "' to find");
1536- }
1537-
1538- switch (card)
1539- {
1540- case AppID::ApplicationWildcard::FIRST_LISTED:
1541- return *apps.begin();
1542- case AppID::ApplicationWildcard::LAST_LISTED:
1543- return *apps.rbegin();
1544- case AppID::ApplicationWildcard::ONLY_LISTED:
1545- if (apps.size() != 1)
1546- {
1547- throw std::runtime_error("More than a single app in package '" + package.value() +
1548- "' when requested to find only app");
1549- }
1550- return *apps.begin();
1551- }
1552-
1553- throw std::logic_error("Got a value of the app wildcard enum that can't exist");
1554-}
1555-
1556-/** Find the version of a package that that is requested
1557-
1558- \param package Name of the package
1559- \param appname Name of the application (not used)
1560- \param registry Persistent connections to use
1561-*/
1562-AppID::Version Click::findVersion(const AppID::Package& package,
1563- const AppID::AppName& appname,
1564- const std::shared_ptr<Registry>& registry)
1565-{
1566- auto manifest = registry->impl->getClickManifest(package);
1567- return manifestVersion(manifest);
1568-}
1569-
1570 std::shared_ptr<Application::Info> Click::info()
1571 {
1572 if (!_info)
1573@@ -193,39 +82,6 @@
1574 return cppstr;
1575 }
1576
1577-std::list<AppID::AppName> manifestApps(const std::shared_ptr<JsonObject>& manifest)
1578-{
1579- JsonObject* hooks = nullptr;
1580- if (!json_object_has_member(manifest.get(), "hooks") ||
1581- (hooks = json_object_get_object_member(manifest.get(), "hooks")) == nullptr)
1582- {
1583- throw std::runtime_error("Manifest does not have a 'hooks' field: " + Registry::Impl::printJson(manifest));
1584- }
1585-
1586- auto gapps = json_object_get_members(hooks);
1587- if (gapps == nullptr)
1588- {
1589- throw std::runtime_error("GLib JSON confusion, please talk to your library vendor");
1590- }
1591-
1592- std::list<AppID::AppName> apps;
1593-
1594- for (GList* item = gapps; item != nullptr; item = g_list_next(item))
1595- {
1596- auto appname = (const gchar*)item->data;
1597-
1598- auto hooklist = json_object_get_object_member(hooks, appname);
1599-
1600- if (json_object_has_member(hooklist, "desktop") == TRUE)
1601- {
1602- apps.emplace_back(AppID::AppName::from_raw(appname));
1603- }
1604- }
1605-
1606- g_list_free(gapps);
1607- return apps;
1608-}
1609-
1610 std::pair<std::shared_ptr<GKeyFile>, std::string> manifestAppDesktop(const std::shared_ptr<JsonObject>& manifest,
1611 const std::string& package,
1612 const std::string& app,
1613@@ -240,8 +96,8 @@
1614 if (!json_object_has_member(manifest.get(), "hooks") ||
1615 (hooks = json_object_get_object_member(manifest.get(), "hooks")) == nullptr)
1616 {
1617- throw std::runtime_error("Manifest for application '" + app + "' does not have a 'hooks' field: " +
1618- Registry::Impl::printJson(manifest));
1619+ throw std::runtime_error("Manifest for application '" + app +
1620+ "' does not have a 'hooks' field: " + Registry::Impl::printJson(manifest));
1621 }
1622
1623 auto gapps = json_object_get_members(hooks);
1624@@ -258,14 +114,14 @@
1625 if (!json_object_has_member(hooks, app.c_str()) ||
1626 (hooklist = json_object_get_object_member(hooks, app.c_str())) == nullptr)
1627 {
1628- throw std::runtime_error("Manifest for does not have an application '" + app + "': " +
1629- Registry::Impl::printJson(manifest));
1630+ throw std::runtime_error("Manifest for does not have an application '" + app +
1631+ "': " + Registry::Impl::printJson(manifest));
1632 }
1633
1634 auto desktoppath = json_object_get_string_member(hooklist, "desktop");
1635 if (desktoppath == nullptr)
1636- throw std::runtime_error("Manifest for application '" + app + "' does not have a 'desktop' hook: " +
1637- Registry::Impl::printJson(manifest));
1638+ throw std::runtime_error("Manifest for application '" + app +
1639+ "' does not have a 'desktop' hook: " + Registry::Impl::printJson(manifest));
1640
1641 auto path = std::shared_ptr<gchar>(g_build_filename(clickDir.c_str(), desktoppath, nullptr), g_free);
1642
1643@@ -281,48 +137,6 @@
1644 return std::make_pair(keyfile, std::string(path.get()));
1645 }
1646
1647-std::list<std::shared_ptr<Application>> Click::list(const std::shared_ptr<Registry>& registry)
1648-{
1649- std::list<std::shared_ptr<Application>> applist;
1650-
1651- try
1652- {
1653- for (auto pkg : registry->impl->getClickPackages())
1654- {
1655- try
1656- {
1657- auto manifest = registry->impl->getClickManifest(pkg);
1658-
1659- for (auto appname : manifestApps(manifest))
1660- {
1661- try
1662- {
1663- AppID appid{pkg, appname, manifestVersion(manifest)};
1664- auto app = std::make_shared<Click>(appid, manifest, registry);
1665- applist.emplace_back(app);
1666- }
1667- catch (std::runtime_error& e)
1668- {
1669- g_debug("Unable to create Click for application '%s' in package '%s': %s",
1670- appname.value().c_str(), pkg.value().c_str(), e.what());
1671- }
1672- }
1673- }
1674- catch (std::runtime_error& e)
1675- {
1676- g_debug("Unable to get information to build Click app on package '%s': %s", pkg.value().c_str(),
1677- e.what());
1678- }
1679- }
1680- }
1681- catch (std::runtime_error& e)
1682- {
1683- g_debug("Unable to get packages from Click database: %s", e.what());
1684- }
1685-
1686- return applist;
1687-}
1688-
1689 std::vector<std::shared_ptr<Application::Instance>> Click::instances()
1690 {
1691 auto vbase = _registry->impl->jobs->instances(appId(), "application-click");
1692@@ -370,11 +184,6 @@
1693 return _registry->impl->jobs->existing(appId(), "application-click", instanceid, std::vector<Application::URL>{});
1694 }
1695
1696-std::shared_ptr<info_watcher::Base> Click::createInfoWatcher(const std::shared_ptr<Registry>& reg)
1697-{
1698- return {};
1699-}
1700-
1701 } // namespace app_impls
1702 } // namespace app_launch
1703 } // namespace ubuntu
1704
1705=== modified file 'libubuntu-app-launch/application-impl-click.h'
1706--- libubuntu-app-launch/application-impl-click.h 2017-02-15 15:09:51 +0000
1707+++ libubuntu-app-launch/application-impl-click.h 2017-03-18 19:37:40 +0000
1708@@ -52,8 +52,6 @@
1709 Click(const AppID& appid, const std::shared_ptr<Registry>& registry);
1710 Click(const AppID& appid, const std::shared_ptr<JsonObject>& manifest, const std::shared_ptr<Registry>& registry);
1711
1712- static std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry);
1713-
1714 AppID appId() override;
1715
1716 std::shared_ptr<Info> info() override;
1717@@ -63,23 +61,8 @@
1718 std::shared_ptr<Instance> launch(const std::vector<Application::URL>& urls = {}) override;
1719 std::shared_ptr<Instance> launchTest(const std::vector<Application::URL>& urls = {}) override;
1720
1721- static bool hasAppId(const AppID& appId, const std::shared_ptr<Registry>& registry);
1722-
1723- static bool verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry);
1724- static bool verifyAppname(const AppID::Package& package,
1725- const AppID::AppName& appname,
1726- const std::shared_ptr<Registry>& registry);
1727- static AppID::AppName findAppname(const AppID::Package& package,
1728- AppID::ApplicationWildcard card,
1729- const std::shared_ptr<Registry>& registry);
1730- static AppID::Version findVersion(const AppID::Package& package,
1731- const AppID::AppName& appname,
1732- const std::shared_ptr<Registry>& registry);
1733-
1734 virtual std::shared_ptr<Application::Instance> findInstance(const std::string& instanceid) override;
1735
1736- static std::shared_ptr<info_watcher::Base> createInfoWatcher(const std::shared_ptr<Registry>& reg);
1737-
1738 private:
1739 AppID _appid;
1740
1741
1742=== modified file 'libubuntu-app-launch/application-impl-legacy.cpp'
1743--- libubuntu-app-launch/application-impl-legacy.cpp 2017-03-07 15:02:05 +0000
1744+++ libubuntu-app-launch/application-impl-legacy.cpp 2017-03-18 19:37:40 +0000
1745@@ -131,161 +131,6 @@
1746 return appinfo_;
1747 }
1748
1749-/** Checks the AppID by ensuring the version and package are empty
1750- then looks for the application.
1751-
1752- \param appid AppID to check
1753- \param registry persistent connections to use
1754-*/
1755-bool Legacy::hasAppId(const AppID& appid, const std::shared_ptr<Registry>& registry)
1756-{
1757- try
1758- {
1759- if (!appid.version.value().empty())
1760- {
1761- return false;
1762- }
1763-
1764- return verifyAppname(appid.package, appid.appname, registry);
1765- }
1766- catch (std::runtime_error& e)
1767- {
1768- return false;
1769- }
1770-}
1771-
1772-/** Ensure the package is empty
1773-
1774- \param package Container name
1775- \param registry persistent connections to use
1776-*/
1777-bool Legacy::verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry)
1778-{
1779- return package.value().empty();
1780-}
1781-
1782-/** Looks for an application by looking through the system and user
1783- application directories to find the desktop file.
1784-
1785- \param package Container name
1786- \param appname Application name to look for
1787- \param registry persistent connections to use
1788-*/
1789-bool Legacy::verifyAppname(const AppID::Package& package,
1790- const AppID::AppName& appname,
1791- const std::shared_ptr<Registry>& registry)
1792-{
1793- if (!verifyPackage(package, registry))
1794- {
1795- throw std::runtime_error{"Invalid Legacy package: " + std::string(package)};
1796- }
1797-
1798- auto desktop = std::string(appname) + ".desktop";
1799- auto evaldir = [&desktop](const gchar* dir) -> bool {
1800- char* fulldir = g_build_filename(dir, "applications", desktop.c_str(), nullptr);
1801- gboolean found = g_file_test(fulldir, G_FILE_TEST_EXISTS);
1802- g_free(fulldir);
1803- return found == TRUE;
1804- };
1805-
1806- if (evaldir(g_get_user_data_dir()))
1807- {
1808- return true;
1809- }
1810-
1811- const char* const* data_dirs = g_get_system_data_dirs();
1812- for (int i = 0; data_dirs[i] != nullptr; i++)
1813- {
1814- if (evaldir(data_dirs[i]))
1815- {
1816- return true;
1817- }
1818- }
1819-
1820- return false;
1821-}
1822-
1823-/** We don't really have a way to implement this for Legacy, any
1824- search wouldn't really make sense. We just throw an error.
1825-
1826- \param package Container name
1827- \param card Application search paths
1828- \param registry persistent connections to use
1829-*/
1830-AppID::AppName Legacy::findAppname(const AppID::Package& package,
1831- AppID::ApplicationWildcard card,
1832- const std::shared_ptr<Registry>& registry)
1833-{
1834- throw std::runtime_error("Legacy apps can't be discovered by package");
1835-}
1836-
1837-/** Function to return an empty string
1838-
1839- \param package Container name (unused)
1840- \param appname Application name (unused)
1841- \param registry persistent connections to use (unused)
1842-*/
1843-AppID::Version Legacy::findVersion(const AppID::Package& package,
1844- const AppID::AppName& appname,
1845- const std::shared_ptr<Registry>& registry)
1846-{
1847- return AppID::Version::from_raw({});
1848-}
1849-
1850-static const std::regex desktop_remover("^(.*)\\.desktop$");
1851-
1852-std::list<std::shared_ptr<Application>> Legacy::list(const std::shared_ptr<Registry>& registry)
1853-{
1854- std::list<std::shared_ptr<Application>> list;
1855- GList* head = g_app_info_get_all();
1856- for (GList* item = head; item != nullptr; item = g_list_next(item))
1857- {
1858- GDesktopAppInfo* appinfo = G_DESKTOP_APP_INFO(item->data);
1859-
1860- if (appinfo == nullptr)
1861- {
1862- continue;
1863- }
1864-
1865- if (g_app_info_should_show(G_APP_INFO(appinfo)) == FALSE)
1866- {
1867- continue;
1868- }
1869-
1870- auto desktopappid = std::string(g_app_info_get_id(G_APP_INFO(appinfo)));
1871- std::string appname;
1872- std::smatch match;
1873- if (std::regex_match(desktopappid, match, desktop_remover))
1874- {
1875- appname = match[1].str();
1876- }
1877- else
1878- {
1879- continue;
1880- }
1881-
1882- /* Remove entries generated by the desktop hook in .local */
1883- if (g_desktop_app_info_has_key(appinfo, "X-Ubuntu-Application-ID"))
1884- {
1885- continue;
1886- }
1887-
1888- try
1889- {
1890- auto app = std::make_shared<Legacy>(AppID::AppName::from_raw(appname), registry);
1891- list.push_back(app);
1892- }
1893- catch (std::runtime_error& e)
1894- {
1895- g_debug("Unable to create application for legacy appname '%s': %s", appname.c_str(), e.what());
1896- }
1897- }
1898-
1899- g_list_free_full(head, g_object_unref);
1900-
1901- return list;
1902-}
1903-
1904 std::vector<std::shared_ptr<Application::Instance>> Legacy::instances()
1905 {
1906 auto vbase = _registry->impl->jobs->instances(appId(), "application-legacy");
1907@@ -400,11 +245,6 @@
1908 return _registry->impl->jobs->existing(appId(), "application-legacy", instanceid, std::vector<Application::URL>{});
1909 }
1910
1911-std::shared_ptr<info_watcher::Base> Legacy::createInfoWatcher(const std::shared_ptr<Registry>& reg)
1912-{
1913- return {};
1914-}
1915-
1916 } // namespace app_impls
1917 } // namespace app_launch
1918 } // namespace ubuntu
1919
1920=== modified file 'libubuntu-app-launch/application-impl-legacy.h'
1921--- libubuntu-app-launch/application-impl-legacy.h 2017-02-15 15:09:51 +0000
1922+++ libubuntu-app-launch/application-impl-legacy.h 2017-03-18 19:37:40 +0000
1923@@ -57,30 +57,13 @@
1924
1925 std::shared_ptr<Info> info() override;
1926
1927- static std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry);
1928-
1929 std::vector<std::shared_ptr<Instance>> instances() override;
1930
1931 std::shared_ptr<Instance> launch(const std::vector<Application::URL>& urls = {}) override;
1932 std::shared_ptr<Instance> launchTest(const std::vector<Application::URL>& urls = {}) override;
1933
1934- static bool hasAppId(const AppID& appId, const std::shared_ptr<Registry>& registry);
1935-
1936- static bool verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry);
1937- static bool verifyAppname(const AppID::Package& package,
1938- const AppID::AppName& appname,
1939- const std::shared_ptr<Registry>& registry);
1940- static AppID::AppName findAppname(const AppID::Package& package,
1941- AppID::ApplicationWildcard card,
1942- const std::shared_ptr<Registry>& registry);
1943- static AppID::Version findVersion(const AppID::Package& package,
1944- const AppID::AppName& appname,
1945- const std::shared_ptr<Registry>& registry);
1946-
1947 virtual std::shared_ptr<Application::Instance> findInstance(const std::string& instanceid) override;
1948
1949- static std::shared_ptr<info_watcher::Base> createInfoWatcher(const std::shared_ptr<Registry>& reg);
1950-
1951 private:
1952 AppID::AppName _appname;
1953 std::string _basedir;
1954
1955=== modified file 'libubuntu-app-launch/application-impl-libertine.cpp'
1956--- libubuntu-app-launch/application-impl-libertine.cpp 2017-02-15 15:09:51 +0000
1957+++ libubuntu-app-launch/application-impl-libertine.cpp 2017-03-18 19:37:40 +0000
1958@@ -143,132 +143,6 @@
1959 return {};
1960 }
1961
1962-/** Checks the AppID by making sure the version is "0.0" and then
1963- calling verifyAppname() to check the rest.
1964-
1965- \param appid AppID to check
1966- \param registry persistent connections to use
1967-*/
1968-bool Libertine::hasAppId(const AppID& appid, const std::shared_ptr<Registry>& registry)
1969-{
1970- try
1971- {
1972- if (appid.version.value() != "0.0")
1973- {
1974- return false;
1975- }
1976-
1977- return verifyAppname(appid.package, appid.appname, registry);
1978- }
1979- catch (std::runtime_error& e)
1980- {
1981- return false;
1982- }
1983-}
1984-
1985-/** Verify a package name by getting the list of containers from
1986- liblibertine and ensuring it is in that list.
1987-
1988- \param package Container name
1989- \param registry persistent connections to use
1990-*/
1991-bool Libertine::verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry)
1992-{
1993- auto containers = std::shared_ptr<gchar*>(libertine_list_containers(), g_strfreev);
1994-
1995- for (int i = 0; containers.get()[i] != nullptr; i++)
1996- {
1997- auto container = containers.get()[i];
1998- if (container == package.value())
1999- {
2000- return true;
2001- }
2002- }
2003-
2004- return false;
2005-}
2006-
2007-/** Gets the list of applications from the container using liblibertine
2008- and see if @appname is in that list.
2009-
2010- \param package Container name
2011- \param appname Application name to look for
2012- \param registry persistent connections to use
2013-*/
2014-bool Libertine::verifyAppname(const AppID::Package& package,
2015- const AppID::AppName& appname,
2016- const std::shared_ptr<Registry>& registry)
2017-{
2018- auto apps = std::shared_ptr<gchar*>(libertine_list_apps_for_container(package.value().c_str()), g_strfreev);
2019-
2020- for (int i = 0; apps.get()[i] != nullptr; i++)
2021- {
2022- auto appid = AppID::parse(apps.get()[i]);
2023- if (appid.appname.value() == appname.value())
2024- {
2025- return true;
2026- }
2027- }
2028-
2029- return false;
2030-}
2031-
2032-/** We don't really have a way to implement this for Libertine, any
2033- search wouldn't really make sense. We just throw an error.
2034-
2035- \param package Container name
2036- \param card Application search paths
2037- \param registry persistent connections to use
2038-*/
2039-AppID::AppName Libertine::findAppname(const AppID::Package& package,
2040- AppID::ApplicationWildcard card,
2041- const std::shared_ptr<Registry>& registry)
2042-{
2043- throw std::runtime_error("Legacy apps can't be discovered by package");
2044-}
2045-
2046-/** Function to return "0.0"
2047-
2048- \param package Container name (unused)
2049- \param appname Application name (unused)
2050- \param registry persistent connections to use (unused)
2051-*/
2052-AppID::Version Libertine::findVersion(const AppID::Package& package,
2053- const AppID::AppName& appname,
2054- const std::shared_ptr<Registry>& registry)
2055-{
2056- return AppID::Version::from_raw("0.0");
2057-}
2058-
2059-std::list<std::shared_ptr<Application>> Libertine::list(const std::shared_ptr<Registry>& registry)
2060-{
2061- std::list<std::shared_ptr<Application>> applist;
2062-
2063- auto containers = std::shared_ptr<gchar*>(libertine_list_containers(), g_strfreev);
2064-
2065- for (int i = 0; containers.get()[i] != nullptr; i++)
2066- {
2067- auto container = containers.get()[i];
2068- auto apps = std::shared_ptr<gchar*>(libertine_list_apps_for_container(container), g_strfreev);
2069-
2070- for (int j = 0; apps.get()[j] != nullptr; j++)
2071- {
2072- try
2073- {
2074- auto appid = AppID::parse(apps.get()[j]);
2075- auto sapp = std::make_shared<Libertine>(appid.package, appid.appname, registry);
2076- applist.emplace_back(sapp);
2077- }
2078- catch (std::runtime_error& e)
2079- {
2080- g_debug("Unable to create application for libertine appname '%s': %s", apps.get()[j], e.what());
2081- }
2082- }
2083- }
2084-
2085- return applist;
2086-}
2087-
2088 std::shared_ptr<Application::Info> Libertine::info()
2089 {
2090 return appinfo_;
2091@@ -337,11 +211,6 @@
2092 return _registry->impl->jobs->existing(appId(), "application-legacy", instanceid, std::vector<Application::URL>{});
2093 }
2094
2095-std::shared_ptr<info_watcher::Base> Libertine::createInfoWatcher(const std::shared_ptr<Registry>& reg)
2096-{
2097- return {};
2098-}
2099-
2100 } // namespace app_impls
2101 } // namespace app_launch
2102 } // namespace ubuntu
2103
2104=== modified file 'libubuntu-app-launch/application-impl-libertine.h'
2105--- libubuntu-app-launch/application-impl-libertine.h 2017-02-15 15:09:51 +0000
2106+++ libubuntu-app-launch/application-impl-libertine.h 2017-03-18 19:37:40 +0000
2107@@ -54,8 +54,6 @@
2108 const AppID::AppName& appname,
2109 const std::shared_ptr<Registry>& registry);
2110
2111- static std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry);
2112-
2113 AppID appId() override
2114 {
2115 return {_container, _appname, AppID::Version::from_raw("0.0")};
2116@@ -68,23 +66,8 @@
2117 std::shared_ptr<Instance> launch(const std::vector<Application::URL>& urls = {}) override;
2118 std::shared_ptr<Instance> launchTest(const std::vector<Application::URL>& urls = {}) override;
2119
2120- static bool hasAppId(const AppID& appId, const std::shared_ptr<Registry>& registry);
2121-
2122- static bool verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry);
2123- static bool verifyAppname(const AppID::Package& package,
2124- const AppID::AppName& appname,
2125- const std::shared_ptr<Registry>& registry);
2126- static AppID::AppName findAppname(const AppID::Package& package,
2127- AppID::ApplicationWildcard card,
2128- const std::shared_ptr<Registry>& registry);
2129- static AppID::Version findVersion(const AppID::Package& package,
2130- const AppID::AppName& appname,
2131- const std::shared_ptr<Registry>& registry);
2132-
2133 virtual std::shared_ptr<Application::Instance> findInstance(const std::string& instanceid) override;
2134
2135- static std::shared_ptr<info_watcher::Base> createInfoWatcher(const std::shared_ptr<Registry>& reg);
2136-
2137 private:
2138 AppID::Package _container;
2139 AppID::AppName _appname;
2140
2141=== modified file 'libubuntu-app-launch/application-impl-snap.cpp'
2142--- libubuntu-app-launch/application-impl-snap.cpp 2017-03-09 15:40:03 +0000
2143+++ libubuntu-app-launch/application-impl-snap.cpp 2017-03-18 19:37:40 +0000
2144@@ -58,7 +58,7 @@
2145 public:
2146 SnapInfo(const AppID& appid,
2147 const std::shared_ptr<Registry>& registry,
2148- const Snap::InterfaceInfo &interfaceInfo,
2149+ const Snap::InterfaceInfo& interfaceInfo,
2150 const std::string& snapDir)
2151 : Desktop(appid,
2152 [appid, snapDir]() -> std::shared_ptr<GKeyFile> {
2153@@ -181,7 +181,7 @@
2154 \param registry Registry to use for persistent connections
2155 \param interfaceInfo Metadata gleaned from the snap's interfaces
2156 */
2157-Snap::Snap(const AppID& appid, const std::shared_ptr<Registry>& registry, const InterfaceInfo &interfaceInfo)
2158+Snap::Snap(const AppID& appid, const std::shared_ptr<Registry>& registry, const InterfaceInfo& interfaceInfo)
2159 : Base(registry)
2160 , appid_(appid)
2161 {
2162@@ -212,65 +212,6 @@
2163 {
2164 }
2165
2166-/** Operator to compare apps for our sets */
2167-struct appcompare
2168-{
2169- bool operator()(const std::shared_ptr<Application>& a, const std::shared_ptr<Application>& b) const
2170- {
2171- return a->appId() < b->appId();
2172- }
2173-};
2174-
2175-/** Lists all the Snappy apps that are using one of our supported interfaces.
2176- Also makes sure they're valid.
2177-
2178- \param registry Registry to use for persistent connections
2179-*/
2180-std::list<std::shared_ptr<Application>> Snap::list(const std::shared_ptr<Registry>& registry)
2181-{
2182- std::set<std::shared_ptr<Application>, appcompare> apps;
2183-
2184- auto lifecycleApps = registry->impl->snapdInfo.appsForInterface(LIFECYCLE_INTERFACE);
2185-
2186- auto lifecycleForApp = [&](const AppID &appID) {
2187- auto iterator = lifecycleApps.find(appID);
2188- if (iterator == lifecycleApps.end())
2189- {
2190- return Application::Info::UbuntuLifecycle::from_raw(false);
2191- }
2192- else
2193- {
2194- return Application::Info::UbuntuLifecycle::from_raw(true);
2195- }
2196- };
2197-
2198- auto addAppsForInterface = [&](const std::string& interface, app_info::Desktop::XMirEnable xMirEnable) {
2199- for (const auto& id : registry->impl->snapdInfo.appsForInterface(interface))
2200- {
2201- auto interfaceInfo = std::make_tuple(xMirEnable, lifecycleForApp(id));
2202- try
2203- {
2204- auto app = std::make_shared<Snap>(id, registry, interfaceInfo);
2205- apps.emplace(app);
2206- }
2207- catch (std::runtime_error& e)
2208- {
2209- g_debug("Unable to make Snap object for '%s': %s", std::string(id).c_str(), e.what());
2210- }
2211- }
2212- };
2213-
2214- addAppsForInterface(MIR_INTERFACE, app_info::Desktop::XMirEnable::from_raw(false));
2215-
2216- /* If an app has both, this will get rejected */
2217- for (const auto& interface : X11_INTERFACES)
2218- {
2219- addAppsForInterface(interface, app_info::Desktop::XMirEnable::from_raw(true));
2220- }
2221-
2222- return std::list<std::shared_ptr<Application>>(apps.begin(), apps.end());
2223-}
2224-
2225 /** Returns the stored AppID */
2226 AppID Snap::appId()
2227 {
2228@@ -326,117 +267,6 @@
2229 pkginfo->appnames.find(appid.appname) != pkginfo->appnames.end();
2230 }
2231
2232-/** Checks if an AppID could be a snap. Note it doesn't look for a desktop
2233- file just the package, app and version. This is done to make the lookup
2234- quickly, as this function can be used to select which backend to use
2235- and we want to reject quickly.
2236-
2237- \param appid Application ID of the snap
2238- \param registry Registry to use for persistent connections
2239-*/
2240-bool Snap::hasAppId(const AppID& appId, const std::shared_ptr<Registry>& registry)
2241-{
2242- if (appId.package.value().empty() || appId.version.value().empty())
2243- {
2244- return false;
2245- }
2246-
2247- if (!std::regex_match(appId.appname.value(), appnameRegex))
2248- {
2249- return false;
2250- }
2251-
2252- auto pkginfo = registry->impl->snapdInfo.pkgInfo(appId.package);
2253- return checkPkgInfo(pkginfo, appId);
2254-}
2255-
2256-/** Look to see if a package is a valid Snap package name
2257-
2258- \param package Package name
2259- \param registry Registry to use for persistent connections
2260-*/
2261-bool Snap::verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry)
2262-{
2263- try
2264- {
2265- auto pkgInfo = registry->impl->snapdInfo.pkgInfo(package);
2266- return pkgInfo != nullptr;
2267- }
2268- catch (std::runtime_error& e)
2269- {
2270- return false;
2271- }
2272-}
2273-
2274-/** Look to see if an appname is a valid for a Snap package
2275-
2276- \param package Package name
2277- \param appname Command name
2278- \param registry Registry to use for persistent connections
2279-*/
2280-bool Snap::verifyAppname(const AppID::Package& package,
2281- const AppID::AppName& appname,
2282- const std::shared_ptr<Registry>& registry)
2283-{
2284- if (!std::regex_match(appname.value(), appnameRegex))
2285- {
2286- return false;
2287- }
2288-
2289- auto pkgInfo = registry->impl->snapdInfo.pkgInfo(package);
2290- return pkgInfo->appnames.find(appname) != pkgInfo->appnames.end();
2291-}
2292-
2293-/** Look for an application name on a Snap package based on a
2294- wildcard type.
2295-
2296- \param package Package name
2297- \param card Wildcard to use for finding the appname
2298- \param registry Registry to use for persistent connections
2299-*/
2300-AppID::AppName Snap::findAppname(const AppID::Package& package,
2301- AppID::ApplicationWildcard card,
2302- const std::shared_ptr<Registry>& registry)
2303-{
2304- auto pkgInfo = registry->impl->snapdInfo.pkgInfo(package);
2305-
2306- if (pkgInfo->appnames.empty())
2307- {
2308- throw std::runtime_error("No apps in package '" + package.value() + "' to find");
2309- }
2310-
2311- switch (card)
2312- {
2313- case AppID::ApplicationWildcard::FIRST_LISTED:
2314- return AppID::AppName::from_raw(*pkgInfo->appnames.begin());
2315- case AppID::ApplicationWildcard::LAST_LISTED:
2316- return AppID::AppName::from_raw(*pkgInfo->appnames.rbegin());
2317- case AppID::ApplicationWildcard::ONLY_LISTED:
2318- if (pkgInfo->appnames.size() != 1)
2319- {
2320- throw std::runtime_error("More than a single app in package '" + package.value() +
2321- "' when requested to find only app");
2322- }
2323- return AppID::AppName::from_raw(*pkgInfo->appnames.begin());
2324- }
2325-
2326- throw std::logic_error("Got a value of the app wildcard enum that can't exist");
2327-}
2328-
2329-/** Look for a version of a Snap package
2330-
2331- \param package Package name
2332- \param appname Not used for snaps
2333- \param registry Registry to use for persistent connections
2334-*/
2335-AppID::Version Snap::findVersion(const AppID::Package& package,
2336- const AppID::AppName& appname,
2337- const std::shared_ptr<Registry>& registry)
2338-{
2339- auto pkgInfo = registry->impl->snapdInfo.pkgInfo(package);
2340- return AppID::Version::from_raw(pkgInfo->revision);
2341-}
2342-
2343 /** Returns a reference to the info for the snap */
2344 std::shared_ptr<Application::Info> Snap::info()
2345 {
2346@@ -512,11 +342,6 @@
2347 return _registry->impl->jobs->existing(appId(), "application-snap", instanceid, std::vector<Application::URL>{});
2348 }
2349
2350-std::shared_ptr<info_watcher::Base> Snap::createInfoWatcher(const std::shared_ptr<Registry>& reg)
2351-{
2352- return {};
2353-}
2354-
2355 } // namespace app_impls
2356 } // namespace app_launch
2357 } // namespace ubuntu
2358
2359=== modified file 'libubuntu-app-launch/application-impl-snap.h'
2360--- libubuntu-app-launch/application-impl-snap.h 2017-03-09 15:40:03 +0000
2361+++ libubuntu-app-launch/application-impl-snap.h 2017-03-18 19:37:40 +0000
2362@@ -51,7 +51,7 @@
2363 typedef std::tuple<app_info::Desktop::XMirEnable, Application::Info::UbuntuLifecycle> InterfaceInfo;
2364
2365 Snap(const AppID& appid, const std::shared_ptr<Registry>& registry);
2366- Snap(const AppID& appid, const std::shared_ptr<Registry>& registry, const InterfaceInfo &interfaceInfo);
2367+ Snap(const AppID& appid, const std::shared_ptr<Registry>& registry, const InterfaceInfo& interfaceInfo);
2368
2369 static std::list<std::shared_ptr<Application>> list(const std::shared_ptr<Registry>& registry);
2370
2371@@ -64,22 +64,10 @@
2372 std::shared_ptr<Instance> launch(const std::vector<Application::URL>& urls = {}) override;
2373 std::shared_ptr<Instance> launchTest(const std::vector<Application::URL>& urls = {}) override;
2374
2375- static bool hasAppId(const AppID& appId, const std::shared_ptr<Registry>& registry);
2376-
2377- static bool verifyPackage(const AppID::Package& package, const std::shared_ptr<Registry>& registry);
2378- static bool verifyAppname(const AppID::Package& package,
2379- const AppID::AppName& appname,
2380- const std::shared_ptr<Registry>& registry);
2381- static AppID::AppName findAppname(const AppID::Package& package,
2382- AppID::ApplicationWildcard card,
2383- const std::shared_ptr<Registry>& registry);
2384- static AppID::Version findVersion(const AppID::Package& package,
2385- const AppID::AppName& appname,
2386- const std::shared_ptr<Registry>& registry);
2387-
2388 virtual std::shared_ptr<Application::Instance> findInstance(const std::string& instanceid) override;
2389
2390- static std::shared_ptr<info_watcher::Base> createInfoWatcher(const std::shared_ptr<Registry>& reg);
2391+ static InterfaceInfo findInterfaceInfo(const AppID& appid, const std::shared_ptr<Registry>& registry);
2392+ static bool checkPkgInfo(const std::shared_ptr<snapd::Info::PkgInfo>& pkginfo, const AppID& appid);
2393
2394 private:
2395 /** AppID of the Snap. Should be the name of the snap package.
2396@@ -92,8 +80,6 @@
2397 std::shared_ptr<snapd::Info::PkgInfo> pkgInfo_;
2398
2399 std::list<std::pair<std::string, std::string>> launchEnv();
2400- static InterfaceInfo findInterfaceInfo(const AppID& appid, const std::shared_ptr<Registry>& registry);
2401- static bool checkPkgInfo(const std::shared_ptr<snapd::Info::PkgInfo>& pkginfo, const AppID& appid);
2402 };
2403
2404 } // namespace app_impls
2405
2406=== modified file 'libubuntu-app-launch/application.cpp'
2407--- libubuntu-app-launch/application.cpp 2017-02-09 03:23:40 +0000
2408+++ libubuntu-app-launch/application.cpp 2017-03-18 19:37:40 +0000
2409@@ -21,12 +21,6 @@
2410 #include "ubuntu-app-launch.h"
2411 }
2412
2413-#include "application-impl-click.h"
2414-#include "application-impl-legacy.h"
2415-#include "application-impl-libertine.h"
2416-#ifdef ENABLE_SNAPPY
2417-#include "application-impl-snap.h"
2418-#endif
2419 #include "application.h"
2420 #include "info-watcher.h"
2421 #include "jobs-base.h"
2422@@ -59,28 +53,15 @@
2423 registry->impl->jobs = jobs::manager::Base::determineFactory(registry);
2424 }
2425
2426- if (app_impls::Click::hasAppId(appid, registry))
2427- {
2428- return std::make_shared<app_impls::Click>(appid, registry);
2429- }
2430-#ifdef ENABLE_SNAPPY
2431- else if (app_impls::Snap::hasAppId(appid, registry))
2432- {
2433- return std::make_shared<app_impls::Snap>(appid, registry);
2434- }
2435-#endif
2436- else if (app_impls::Libertine::hasAppId(appid, registry))
2437- {
2438- return std::make_shared<app_impls::Libertine>(appid.package, appid.appname, registry);
2439- }
2440- else if (app_impls::Legacy::hasAppId(appid, registry))
2441- {
2442- return std::make_shared<app_impls::Legacy>(appid.appname, registry);
2443- }
2444- else
2445- {
2446- throw std::runtime_error("Invalid app ID: " + std::string(appid));
2447- }
2448+ for (const auto& appStore : registry->impl->appStores())
2449+ {
2450+ if (appStore->hasAppId(appid, registry))
2451+ {
2452+ return appStore->create(appid, registry);
2453+ }
2454+ }
2455+
2456+ throw std::runtime_error("Invalid app ID: " + std::string(appid));
2457 }
2458
2459 AppID::AppID()
2460@@ -195,42 +176,6 @@
2461 return package.value().empty() && appname.value().empty() && version.value().empty();
2462 }
2463
2464-/** Basically we're making our own VTable of static functions. Static
2465- functions don't go in the normal VTables, so we can't use our class
2466- inheritance here to help. So we're just packing these puppies into
2467- a data structure and iterating over it. */
2468-struct DiscoverTools
2469-{
2470- std::function<bool(const AppID::Package& package, const std::shared_ptr<Registry>& registry)> verifyPackage;
2471- std::function<bool(
2472- const AppID::Package& package, const AppID::AppName& appname, const std::shared_ptr<Registry>& registry)>
2473- verifyAppname;
2474- std::function<AppID::AppName(
2475- const AppID::Package& package, AppID::ApplicationWildcard card, const std::shared_ptr<Registry>& registry)>
2476- findAppname;
2477- std::function<AppID::Version(
2478- const AppID::Package& package, const AppID::AppName& appname, const std::shared_ptr<Registry>& registry)>
2479- findVersion;
2480- std::function<bool(const AppID& appid, const std::shared_ptr<Registry>& registry)> hasAppId;
2481-};
2482-
2483-/** The tools in order that they should be used */
2484-static const std::vector<DiscoverTools> discoverTools{
2485- /* Click */
2486- {app_impls::Click::verifyPackage, app_impls::Click::verifyAppname, app_impls::Click::findAppname,
2487- app_impls::Click::findVersion, app_impls::Click::hasAppId},
2488-#ifdef ENABLE_SNAPPY
2489- /* Snap */
2490- {app_impls::Snap::verifyPackage, app_impls::Snap::verifyAppname, app_impls::Snap::findAppname,
2491- app_impls::Snap::findVersion, app_impls::Snap::hasAppId},
2492-#endif
2493- /* Libertine */
2494- {app_impls::Libertine::verifyPackage, app_impls::Libertine::verifyAppname, app_impls::Libertine::findAppname,
2495- app_impls::Libertine::findVersion, app_impls::Libertine::hasAppId},
2496- /* Legacy */
2497- {app_impls::Legacy::verifyPackage, app_impls::Legacy::verifyAppname, app_impls::Legacy::findAppname,
2498- app_impls::Legacy::findVersion, app_impls::Legacy::hasAppId}};
2499-
2500 AppID AppID::discover(const std::shared_ptr<Registry>& registry,
2501 const std::string& package,
2502 const std::string& appname,
2503@@ -238,31 +183,31 @@
2504 {
2505 auto pkg = AppID::Package::from_raw(package);
2506
2507- for (const auto& tools : discoverTools)
2508+ for (const auto& appStore : registry->impl->appStores())
2509 {
2510 /* Figure out which type we have */
2511 try
2512 {
2513- if (tools.verifyPackage(pkg, registry))
2514+ if (appStore->verifyPackage(pkg, registry))
2515 {
2516 auto app = AppID::AppName::from_raw({});
2517
2518 if (appname.empty() || appname == "first-listed-app")
2519 {
2520- app = tools.findAppname(pkg, ApplicationWildcard::FIRST_LISTED, registry);
2521+ app = appStore->findAppname(pkg, ApplicationWildcard::FIRST_LISTED, registry);
2522 }
2523 else if (appname == "last-listed-app")
2524 {
2525- app = tools.findAppname(pkg, ApplicationWildcard::LAST_LISTED, registry);
2526+ app = appStore->findAppname(pkg, ApplicationWildcard::LAST_LISTED, registry);
2527 }
2528 else if (appname == "only-listed-app")
2529 {
2530- app = tools.findAppname(pkg, ApplicationWildcard::ONLY_LISTED, registry);
2531+ app = appStore->findAppname(pkg, ApplicationWildcard::ONLY_LISTED, registry);
2532 }
2533 else
2534 {
2535 app = AppID::AppName::from_raw(appname);
2536- if (!tools.verifyAppname(pkg, app, registry))
2537+ if (!appStore->verifyAppname(pkg, app, registry))
2538 {
2539 throw std::runtime_error("App name passed in is not valid for this package type");
2540 }
2541@@ -271,12 +216,12 @@
2542 auto ver = AppID::Version::from_raw({});
2543 if (version.empty() || version == "current-user-version")
2544 {
2545- ver = tools.findVersion(pkg, app, registry);
2546+ ver = appStore->findVersion(pkg, app, registry);
2547 }
2548 else
2549 {
2550 ver = AppID::Version::from_raw(version);
2551- if (!tools.hasAppId({pkg, app, ver}, registry))
2552+ if (!appStore->hasAppId({pkg, app, ver}, registry))
2553 {
2554 throw std::runtime_error("Invalid version passed for this package type");
2555 }
2556@@ -301,14 +246,14 @@
2557 {
2558 auto pkg = AppID::Package::from_raw(package);
2559
2560- for (const auto& tools : discoverTools)
2561+ for (const auto& appStore : registry->impl->appStores())
2562 {
2563 try
2564 {
2565- if (tools.verifyPackage(pkg, registry))
2566+ if (appStore->verifyPackage(pkg, registry))
2567 {
2568- auto app = tools.findAppname(pkg, appwildcard, registry);
2569- auto ver = tools.findVersion(pkg, app, registry);
2570+ auto app = appStore->findAppname(pkg, appwildcard, registry);
2571+ auto ver = appStore->findVersion(pkg, app, registry);
2572 return AppID{pkg, app, ver};
2573 }
2574 }
2575@@ -330,13 +275,13 @@
2576 auto pkg = AppID::Package::from_raw(package);
2577 auto app = AppID::AppName::from_raw(appname);
2578
2579- for (const auto& tools : discoverTools)
2580+ for (const auto& appStore : registry->impl->appStores())
2581 {
2582 try
2583 {
2584- if (tools.verifyPackage(pkg, registry) && tools.verifyAppname(pkg, app, registry))
2585+ if (appStore->verifyPackage(pkg, registry) && appStore->verifyAppname(pkg, app, registry))
2586 {
2587- auto ver = tools.findVersion(pkg, app, registry);
2588+ auto ver = appStore->findVersion(pkg, app, registry);
2589 return AppID{pkg, app, ver};
2590 }
2591 }
2592
2593=== modified file 'libubuntu-app-launch/registry-impl.cpp'
2594--- libubuntu-app-launch/registry-impl.cpp 2017-02-10 16:50:40 +0000
2595+++ libubuntu-app-launch/registry-impl.cpp 2017-03-18 19:37:40 +0000
2596@@ -43,6 +43,7 @@
2597 })
2598 , _registry{registry}
2599 , _iconFinders()
2600+ , _appStores(app_store::Base::allAppStores())
2601 {
2602 auto cancel = thread.getCancellable();
2603 _dbus = thread.executeOnThread<std::shared_ptr<GDBusConnection>>([cancel]() {
2604@@ -311,14 +312,15 @@
2605 std::call_once(flag_appInfoUpdated, [this, reg] {
2606 g_debug("App Info Updated Signal Initialized");
2607
2608- auto apps = app_impls::Base::createInfoWatchers(reg);
2609+ std::list<std::shared_ptr<info_watcher::Base>> apps{_appStores.begin(), _appStores.end()};
2610 apps.push_back(Registry::Impl::getZgWatcher(reg));
2611
2612 for (const auto& app : apps)
2613 {
2614 infoWatchers_.emplace_back(
2615- std::make_pair(app, app->infoChanged().connect(
2616- [this](const std::shared_ptr<Application>& app) { sig_appInfoUpdated(app); })));
2617+ std::make_pair(app, app->infoChanged().connect([this](const std::shared_ptr<Application>& app) {
2618+ sig_appInfoUpdated(app);
2619+ })));
2620 }
2621 });
2622 return sig_appInfoUpdated;
2623
2624=== modified file 'libubuntu-app-launch/registry-impl.h'
2625--- libubuntu-app-launch/registry-impl.h 2017-02-10 16:50:40 +0000
2626+++ libubuntu-app-launch/registry-impl.h 2017-03-18 19:37:40 +0000
2627@@ -17,6 +17,7 @@
2628 * Ted Gould <ted.gould@canonical.com>
2629 */
2630
2631+#include "app-store-base.h"
2632 #include "glib-thread.h"
2633 #include "info-watcher-zg.h"
2634 #include "jobs-base.h"
2635@@ -99,6 +100,11 @@
2636
2637 core::Signal<const std::shared_ptr<Application>&>& appInfoUpdated(const std::shared_ptr<Registry>& reg);
2638
2639+ std::list<std::shared_ptr<app_store::Base>> appStores()
2640+ {
2641+ return _appStores;
2642+ }
2643+
2644 private:
2645 Registry* _registry; /**< The Registry that we're spawned from */
2646
2647@@ -117,6 +123,9 @@
2648 /** Path to the OOM Helper */
2649 std::string oomHelper_;
2650
2651+ /** Application stores */
2652+ std::list<std::shared_ptr<app_store::Base>> _appStores;
2653+
2654 /** Signal for application info changing */
2655 core::Signal<const std::shared_ptr<Application>&> sig_appInfoUpdated;
2656 /** Flag to see if we've initialized the info watcher list */
2657
2658=== modified file 'libubuntu-app-launch/registry.cpp'
2659--- libubuntu-app-launch/registry.cpp 2017-02-15 15:09:51 +0000
2660+++ libubuntu-app-launch/registry.cpp 2017-03-18 19:37:40 +0000
2661@@ -24,13 +24,6 @@
2662 #include "registry-impl.h"
2663 #include "registry.h"
2664
2665-#include "application-impl-click.h"
2666-#include "application-impl-legacy.h"
2667-#include "application-impl-libertine.h"
2668-#ifdef ENABLE_SNAPPY
2669-#include "application-impl-snap.h"
2670-#endif
2671-
2672 #include "helper-impl-click.h"
2673
2674 namespace ubuntu
2675@@ -61,12 +54,10 @@
2676 {
2677 std::list<std::shared_ptr<Application>> list;
2678
2679- list.splice(list.begin(), app_impls::Click::list(connection));
2680- list.splice(list.begin(), app_impls::Legacy::list(connection));
2681- list.splice(list.begin(), app_impls::Libertine::list(connection));
2682-#ifdef ENABLE_SNAPPY
2683- list.splice(list.begin(), app_impls::Snap::list(connection));
2684-#endif
2685+ for (const auto& appStore : connection->impl->appStores())
2686+ {
2687+ list.splice(list.begin(), appStore->list(connection));
2688+ }
2689
2690 return list;
2691 }
2692
2693=== modified file 'tests/list-apps.cpp'
2694--- tests/list-apps.cpp 2017-03-09 15:40:03 +0000
2695+++ tests/list-apps.cpp 2017-03-18 19:37:40 +0000
2696@@ -25,9 +25,10 @@
2697 #include "eventually-fixture.h"
2698 #include "libertine-service.h"
2699
2700-#include "application-impl-click.h"
2701-#include "application-impl-legacy.h"
2702-#include "application-impl-libertine.h"
2703+#include "app-store-click.h"
2704+#include "app-store-legacy.h"
2705+#include "app-store-libertine.h"
2706+#include "app-store-snap.h"
2707 #include "application-impl-snap.h"
2708 #include "application.h"
2709 #include "registry.h"
2710@@ -155,7 +156,8 @@
2711 TEST_F(ListApps, ListClick)
2712 {
2713 auto registry = std::make_shared<ubuntu::app_launch::Registry>();
2714- auto apps = ubuntu::app_launch::app_impls::Click::list(registry);
2715+ ubuntu::app_launch::app_store::Click store;
2716+ auto apps = store.list(registry);
2717
2718 printApps(apps);
2719
2720@@ -182,7 +184,8 @@
2721 TEST_F(ListApps, ListLegacy)
2722 {
2723 auto registry = std::make_shared<ubuntu::app_launch::Registry>();
2724- auto apps = ubuntu::app_launch::app_impls::Legacy::list(registry);
2725+ ubuntu::app_launch::app_store::Legacy store;
2726+ auto apps = store.list(registry);
2727
2728 printApps(apps);
2729
2730@@ -196,7 +199,8 @@
2731 TEST_F(ListApps, ListLibertine)
2732 {
2733 auto registry = std::make_shared<ubuntu::app_launch::Registry>();
2734- auto apps = ubuntu::app_launch::app_impls::Libertine::list(registry);
2735+ ubuntu::app_launch::app_store::Libertine store;
2736+ auto apps = store.list(registry);
2737
2738 printApps(apps);
2739
2740@@ -239,7 +243,8 @@
2741 interfaces, x11Package, x11Package, x11Package}}; /* x11 check */
2742 auto registry = std::make_shared<ubuntu::app_launch::Registry>();
2743
2744- auto apps = ubuntu::app_launch::app_impls::Snap::list(registry);
2745+ ubuntu::app_launch::app_store::Snap store;
2746+ auto apps = store.list(registry);
2747
2748 printApps(apps);
2749

Subscribers

People subscribed via source and target branches