Merge lp:~abreu-alexandre/webbrowser-app/fix-application-name-setup into lp:webbrowser-app

Proposed by Alexandre Abreu
Status: Merged
Approved by: Alexandre Abreu
Approved revision: 1459
Merged at revision: 1467
Proposed branch: lp:~abreu-alexandre/webbrowser-app/fix-application-name-setup
Merge into: lp:webbrowser-app
Diff against target: 316 lines (+110/-37)
10 files modified
src/app/browserapplication.cpp (+32/-24)
src/app/browserapplication.h (+1/-2)
src/app/config.h.in (+0/-1)
src/app/single-instance-manager.cpp (+39/-3)
src/app/single-instance-manager.h (+1/-1)
src/app/webbrowser/webbrowser-app.cpp (+1/-1)
src/app/webcontainer/webapp-container.cpp (+27/-1)
src/app/webcontainer/webapp-container.h (+1/-0)
tests/autopilot/webapp_container/tests/__init__.py (+4/-0)
tests/unittests/single-instance-manager/tst_SingleInstanceManagerTests.cpp (+4/-4)
To merge this branch: bzr merge lp:~abreu-alexandre/webbrowser-app/fix-application-name-setup
Reviewer Review Type Date Requested Status
system-apps-ci-bot continuous-integration Needs Fixing
Olivier Tilloy Approve
Review via email: mp+293658@code.launchpad.net

Commit message

Fix container/webbrowser app_id; Properly set applicationname based on package name and app name

Description of the change

Fix container/webbrowser app_id; Properly set applicationname based on package name and app name

To post a comment you must log in.
Revision history for this message
Olivier Tilloy (osomon) wrote :

The proposed solution only partially addresses the problem: when launching two instances of the webapp container on desktop (without an explicit app id), the second instance will open a new tab/overlay in the first instance (bug #1577806), because all webapps will have their app id set to the default value "webapp-container".

What we really need is to ensure that the app *always* has a reasonably unique app id, even when it was not explicitly set (typically, on a unity7 desktop). I propose using an encoded version of the initial URL when no app id can be inferred.

For example, if the webapp container was invoked like that on desktop:

    webapp-container https://ubuntu.slack.com/

We could urlencode the URL and set the app id to "https%3A%2F%2Fubuntu.slack.com%2F". Or, because we need to be careful about the length of the path where the single instance socket lives (see https://bazaar.launchpad.net/~phablet-team/webbrowser-app/trunk/view/head:/src/app/single-instance-manager.cpp#L71), we might want to use a short hash of that value.

I assume that for click packages that ship several desktop files, we want to consider those as separate apps, and thus not have them share where they write data (cookies, cache, etc…). In that case we want to make sure that the dataLocation and cacheLocation are unique for each app within a package. Is that guaranteed by setting the application name to appIdParts.first() ? (on a related note, a comment to document the exact structure of APP_ID under unity8/UAL would be useful for future reference)

It looks to me like SingleInstanceManager::getProfilePath() should in fact be moved to BrowserApplication::initialize(), because this affects all the code that reads/writes data, not just the single instance manager.

And since all the logic to infer the app id is specific to the webapp container (the app id for the browser will always be "webbrowser-app"), it should be moved to src/app/webcontainer/webapp-container.cpp. The second parameter to BrowserApplication::initialize() would then become "appId" instead of "defaultAppId".

Finally, one style nit: given that the default app id for the browser is referred to in only one place, it doesn’t need to be declared as a const variable in the unnamed namespace.

review: Needs Fixing
Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

> The proposed solution only partially addresses the problem: when launching two
> instances of the webapp container on desktop (without an explicit app id), the
> second instance will open a new tab/overlay in the first instance (bug
> #1577806), because all webapps will have their app id set to the default value
> "webapp-container".
>
> What we really need is to ensure that the app *always* has a reasonably unique
> app id, even when it was not explicitly set (typically, on a unity7 desktop).
> I propose using an encoded version of the initial URL when no app id can be
> inferred.
>
> For example, if the webapp container was invoked like that on desktop:
>
> webapp-container https://ubuntu.slack.com/
>
> We could urlencode the URL and set the app id to
> "https%3A%2F%2Fubuntu.slack.com%2F". Or, because we need to be careful about
> the length of the path where the single instance socket lives (see
> https://bazaar.launchpad.net/~phablet-team/webbrowser-
> app/trunk/view/head:/src/app/single-instance-manager.cpp#L71), we might want
> to use a short hash of that value.

I thought about that problem too and chose to handle things that way for specific reasons
(that you might not agree on :) ),

- on desktop and until we have convergence the de facto way of doing things was to use
the --app-id command line parameter, this was both a way to ensure that the user did
acknowledge and control the exact app id. I am not sure we want to add another mechanism
for that,

- encoding the url is not a good way to auto determine the APP_ID since it also breaks
as soon 2 webapps share the same homepage. it also breaks if at runtime a webapp does not
define a homepage in the command line as it is the case with a few,

>
> I assume that for click packages that ship several desktop files, we want to
> consider those as separate apps, and thus not have them share where they write
> data (cookies, cache, etc…). In that case we want to make sure that the
> dataLocation and cacheLocation are unique for each app within a package. Is
> that guaranteed by setting the application name to appIdParts.first() ? (on a
> related note, a comment to document the exact structure of APP_ID under
> unity8/UAL would be useful for future reference)
>
> It looks to me like SingleInstanceManager::getProfilePath() should in fact be
> moved to BrowserApplication::initialize(), because this affects all the code
> that reads/writes data, not just the single instance manager.
>
> And since all the logic to infer the app id is specific to the webapp
> container (the app id for the browser will always be "webbrowser-app"), it
> should be moved to src/app/webcontainer/webapp-container.cpp. The second
> parameter to BrowserApplication::initialize() would then become "appId"
> instead of "defaultAppId".

well actually no, my view of things (and it is reflected by the way I did this)
is that when you have a single click, you want to implicitly share those
between the apps. It is based on some use cases that required that semantics,

Revision history for this message
Olivier Tilloy (osomon) wrote :

> on desktop and until we have convergence the de facto way of doing
> things was to use the --app-id command line parameter, this was both a
> way to ensure that the user did acknowledge and control the exact app
> id. I am not sure we want to add another mechanism for that,

Fair enough. Can we add a big fat warning printed on the console when the app id is not set, to warn of the consequences, and explain how to set the app id (--app-id command-line parameter or APP_ID env var)?
I’m even thinking that we may want to bail out if no app id is set, to prevent various apps from sharing their data under the generic "webapp-container" profile. Not sure whether that’s very developer-friendly though.

> when you have a single click, you want to implicitly share those
> between the apps. It is based on some use cases that required that
> semantics,

OK. Can that be explicitly documented in the code with a comment?
And my previous suggestion of documenting the exact structure of APP_ID under unity8/UAL is still valid, I’d rather not have to do some investigation work next time I look at that code again.

> And since all the logic to infer the app id is specific to the webapp
> container (the app id for the browser will always be
> "webbrowser-app"), it should be moved to
> src/app/webcontainer/webapp-container.cpp. The second parameter to
> BrowserApplication::initialize() would then become "appId" instead of
> "defaultAppId".

This still holds true.

1455. By Alexandre Abreu

Add comments; factor code for app_id retrieval

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

updated

Revision history for this message
Olivier Tilloy (osomon) wrote :

Can you add a Q_ASSERT(!appId.isEmpty()) to the beginning of BrowserApplication::initialize()?
Passing an empty app id would lead to undefined behaviour I think.
That would also render the check for appIdParts.isEmpty() in SingleInstanceManager::getProfilePathFromAppId() useless.

In single-instance-manager.cpp, the additional include of <QDebug> is useless, it’s already included earlier on.
The additional include of <QtCore/QCoreApplication> also appears unused. Can you please remove it?

> https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1555542
Can you shorten that link to https://launchpad.net/bugs/1555542 ?

> appIdParts.mid(1, 1)[0]
Isn’t that equivalent to appIdParts[1] ?

> return profilePath
> + QDir::separator()
> + appDesktopName;
That could go on one single line.

It doesn’t look like getProfilePathFromAppId() needs to be a static member of SingleInstanceManager, it could simply be a function inside an unnamed namespace.

There’s a meaningless additional blank line in webbrowser-app.cpp, can it be reverted?

In tst_SingleInstanceManagerTests.cpp, the second parameter to run() should not be an empty string, this is unexpected. Can you use an non-empty string token?

Have you considered my suggestion of completely bailing out if no app id is explicitly set for the webapp container? I don’t think it makes sense to have apps that run in a "generic" container anyway, does it?

review: Needs Fixing
Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

> Can you add a Q_ASSERT(!appId.isEmpty()) to the beginning of
> BrowserApplication::initialize()?

I added an explicit check since it should be something that is guaranteed
at runtime whatever is the build type imo,

> Passing an empty app id would lead to undefined behaviour I think.
> That would also render the check for appIdParts.isEmpty() in
> SingleInstanceManager::getProfilePathFromAppId() useless.

done

> In single-instance-manager.cpp, the additional include of <QDebug> is useless,
> it’s already included earlier on.
> The additional include of <QtCore/QCoreApplication> also appears unused. Can
> you please remove it?

done

> > https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1555542
> Can you shorten that link to https://launchpad.net/bugs/1555542 ?

done

> > appIdParts.mid(1, 1)[0]
> Isn’t that equivalent to appIdParts[1] ?

totally :) done

> > return profilePath
> > + QDir::separator()
> > + appDesktopName;
> That could go on one single line.

done

> It doesn’t look like getProfilePathFromAppId() needs to be a static member of
> SingleInstanceManager, it could simply be a function inside an unnamed
> namespace.

totally done,

> There’s a meaningless additional blank line in webbrowser-app.cpp, can it be
> reverted?

done

> In tst_SingleInstanceManagerTests.cpp, the second parameter to run() should
> not be an empty string, this is unexpected. Can you use an non-empty string
> token?

agree, done

> Have you considered my suggestion of completely bailing out if no app id is
> explicitly set for the webapp container? I don’t think it makes sense to have
> apps that run in a "generic" container anyway, does it?

yes, I initially found it a bit drastic to bail out right away ... but after thinking
about it I think that it'll cause less confusion,

done

1456. By Alexandre Abreu

Tweaks

1457. By Alexandre Abreu

Fail early when no app id is found

Revision history for this message
Olivier Tilloy (osomon) wrote :

In WebappContainer::initialize(), if the app id is empty, the error message is ambiguous:

  « The application may not function properly and display some undesired behaviors.»

Considering that we are bailing out in that case, the application will not function at all :)

Can you update the message?

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

Minor nit: in webbrowser-app.cpp, it would be better to pass the second argument to BrowserApplication::initialize() as QStringLiteral("webbrowser-app").

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

> In WebappContainer::initialize(), if the app id is empty, the error message is
> ambiguous:
>
> « The application may not function properly and display some undesired
> behaviors.»
>
> Considering that we are bailing out in that case, the application will not
> function at all :)
>
> Can you update the message?

sorry, definitely, yes, done

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

> Minor nit: in webbrowser-app.cpp, it would be better to pass the second
> argument to BrowserApplication::initialize() as QStringLiteral("webbrowser-
> app").

done

1458. By Alexandre Abreu

Update bail out message when no app id is set; nit

Revision history for this message
Olivier Tilloy (osomon) wrote :

In the implementation of BrowserApplication::initialize(), there doesn’t seem to be a good reason for moving the calls to QCoreApplication::setApplicationName() and QCoreApplication::setOrganizationDomain(), can you revert that change? Because of that change a comment ("Ensure that application-specific data is written where it ought to.") is out of context.

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

  « // Take the app_name into account when creating the »

That comment appears to be incomplete.

review: Needs Fixing
Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote :

FAILED: Continuous integration, rev:1458
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/486/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build/488
    FAILURE: https://jenkins.canonical.com/system-apps/job/test-0-autopkgtest/label=phone-armhf,release=vivid+overlay,testname=default/42/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-0-fetch/488
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-1-sourcepkg/release=vivid+overlay/487
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-1-sourcepkg/release=xenial/487
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/494
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/494/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial/494
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial/494/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/494
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/494/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial/494
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial/494/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/494
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/494/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial/494
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial/494/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/486/rebuild

review: Needs Fixing (continuous-integration)
1459. By Alexandre Abreu

fix comment; revert setappname call sites

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

> In the implementation of BrowserApplication::initialize(), there doesn’t seem
> to be a good reason for moving the calls to
> QCoreApplication::setApplicationName() and
> QCoreApplication::setOrganizationDomain(), can you revert that change? Because
> of that change a comment ("Ensure that application-specific data is written
> where it ought to.") is out of context.

yes, a leftover, thank you done,

Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

> « // Take the app_name into account when creating the »
>
> That comment appears to be incomplete.

done

Revision history for this message
Olivier Tilloy (osomon) wrote :

LGTM now, thanks. I have tested on desktop but not on touch devices, so this will need to be tested from a silo to validate that the behaviour is as expected.

review: Approve
Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote :

FAILED: Continuous integration, rev:1459
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/495/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build/497
    FAILURE: https://jenkins.canonical.com/system-apps/job/test-0-autopkgtest/label=phone-armhf,release=vivid+overlay,testname=default/44/console
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-0-fetch/497
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-1-sourcepkg/release=vivid+overlay/489
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-1-sourcepkg/release=xenial/489
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/496
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=vivid+overlay/496/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial/496
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=amd64,release=xenial/496/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/496
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=vivid+overlay/496/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial/496
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=armhf,release=xenial/496/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/496
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=vivid+overlay/496/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial/496
        deb: https://jenkins.canonical.com/system-apps/job/build-2-binpkg/arch=i386,release=xenial/496/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/system-apps/job/lp-webbrowser-app-ci/495/rebuild

review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/app/browserapplication.cpp'
2--- src/app/browserapplication.cpp 2016-04-12 19:59:00 +0000
3+++ src/app/browserapplication.cpp 2016-05-10 14:22:12 +0000
4@@ -95,16 +95,6 @@
5 return host;
6 }
7
8-QString BrowserApplication::appId() const
9-{
10- Q_FOREACH(const QString& argument, m_arguments) {
11- if (argument.startsWith("--app-id=")) {
12- return argument.split("--app-id=")[1];
13- }
14- }
15- return QString();
16-}
17-
18 #define MAKE_SINGLETON_FACTORY(type) \
19 static QObject* type##_singleton_factory(QQmlEngine* engine, QJSEngine* scriptEngine) { \
20 Q_UNUSED(engine); \
21@@ -115,36 +105,54 @@
22 MAKE_SINGLETON_FACTORY(MemInfo)
23 MAKE_SINGLETON_FACTORY(MimeDatabase)
24
25-
26-bool BrowserApplication::initialize(const QString& qmlFileSubPath)
27+bool BrowserApplication::initialize(const QString& qmlFileSubPath
28+ , const QString& appId)
29 {
30 Q_ASSERT(m_window == 0);
31
32+ if (appId.isEmpty()) {
33+ qCritical() << "Cannot initialize the runtime environment: "
34+ "no application id detected.";
35+ return false;
36+ }
37+
38 if (m_arguments.contains("--help") || m_arguments.contains("-h")) {
39 printUsage();
40 return false;
41 }
42
43- // Handle legacy platforms (i.e. current desktop versions, where
44- // applications are not started by the Ubuntu ApplicationManager).
45- if (qgetenv("APP_ID").isEmpty()) {
46- QString id = appId();
47- if (id.isEmpty()) {
48- id = QStringLiteral(APP_ID);
49- }
50- qputenv("APP_ID", id.toUtf8());
51- }
52 // Ensure that application-specific data is written where it ought to.
53- QStringList appIdParts =
54- QString::fromUtf8(qgetenv("APP_ID")).split('_');
55+ QStringList appIdParts = appId.split('_');
56+
57 QCoreApplication::setApplicationName(appIdParts.first());
58 QCoreApplication::setOrganizationDomain(QCoreApplication::applicationName());
59+
60 // Get also the the first two components of the app ID: <package>_<app>,
61 // which is needed by Online Accounts.
62 QString unversionedAppId = QStringList(appIdParts.mid(0, 2)).join('_');
63
64 // Ensure only one instance of the app is running.
65- if (m_singleton.run(m_arguments)) {
66+ // For webapps using the container as a launcher, the predicate that
67+ // is used to determine if this running instance is a duplicate of
68+ // a running one, is based on the current APP_ID.
69+ // The app id is formed as: <package name>_<app name>_<version>
70+
71+ // Where the <package name> is specified in the the manifest.json as
72+ // "appName" and is specific for the whole click package.
73+
74+ // The <app name> portion is based on the desktop file name and is a short
75+ // app name. This name is meaningful when more than one desktop file is
76+ // found in a given click package.
77+
78+ // IMPORTANT:
79+ // 1. When a click application contains more than one desktop file
80+ // the bundle is considered a single app from the point of view of the
81+ // cache and resource file locations. THOSE FILES ARE THEN SHARED between
82+ // the instances.
83+ // 2. To make sure that if more than one desktop file is found in a click package,
84+ // those apps are not considered the same instance, the instance existance predicate
85+ // is based on the <package name> AND the <app name> detailed above.
86+ if (m_singleton.run(m_arguments, appId)) {
87 connect(&m_singleton, SIGNAL(newInstanceLaunched(const QStringList&)),
88 SLOT(onNewInstanceLaunched(const QStringList&)));
89 } else {
90
91=== modified file 'src/app/browserapplication.h'
92--- src/app/browserapplication.h 2016-01-15 09:29:22 +0000
93+++ src/app/browserapplication.h 2016-05-10 14:22:12 +0000
94@@ -45,7 +45,7 @@
95 BrowserApplication(int& argc, char** argv);
96 ~BrowserApplication();
97
98- bool initialize(const QString& qmlFileSubPath);
99+ bool initialize(const QString& qmlFileSubPath, const QString& appId);
100 int run();
101
102 protected:
103@@ -63,7 +63,6 @@
104 void onNewInstanceLaunched(const QStringList& arguments) const;
105
106 private:
107- QString appId() const;
108 QString inspectorPort() const;
109 QString inspectorHost() const;
110
111
112=== modified file 'src/app/config.h.in'
113--- src/app/config.h.in 2015-05-14 05:57:01 +0000
114+++ src/app/config.h.in 2016-05-10 14:22:12 +0000
115@@ -23,7 +23,6 @@
116 #include <QtCore/QDir>
117 #include <QtCore/QString>
118
119-#define APP_ID "webbrowser-app"
120 #define REMOTE_INSPECTOR_PORT 9221
121
122 inline bool isRunningInstalled()
123
124=== modified file 'src/app/single-instance-manager.cpp'
125--- src/app/single-instance-manager.cpp 2016-04-08 13:49:25 +0000
126+++ src/app/single-instance-manager.cpp 2016-05-10 14:22:12 +0000
127@@ -33,12 +33,48 @@
128 #include "single-instance-manager.h"
129
130 namespace {
131+
132 const int kWaitForRunningInstanceToRespondMs = 1000;
133 const int kWaitForRunningInstanceToAckMs = 1000;
134 const int kDataStreamVersion = QDataStream::Qt_5_0;
135 const QString kHeaderToken = QStringLiteral("MESSAGE");
136 const QString kAckToken = QStringLiteral("ACK");
137-}
138+
139+QString getProfilePathFromAppId(const QString& appId)
140+{
141+ QString profilePath =
142+ QStandardPaths::writableLocation(QStandardPaths::DataLocation);
143+
144+ QStringList appIdParts = appId.split('_', QString::SkipEmptyParts);
145+
146+ QString appDesktopName;
147+
148+ // We try to get the "short app name" to try to uniquely identify
149+ // the single instance profile path.
150+
151+ // In cases where you have a single click with multiple apps in it,
152+ // the "app name" as defined in the click manifest.json file will be
153+ // a proper way to distinguish a unique instance, it needs to take
154+ // the desktop name into account.
155+
156+ // At the moment there is no clean way to get those click app name
157+ // paths, see:
158+ // https://launchpad.net/bugs/1555542
159+
160+ if (appIdParts.size() >= 3) {
161+ // Assume that we have a APP_ID that corresponds to:
162+ // <manifest app name>_<desktop app name>_<version>
163+ appDesktopName = appIdParts[1];
164+ } else {
165+ // We either run on desktop or as the webbrowser
166+ appDesktopName = appIdParts.first();
167+ }
168+
169+ return profilePath + QDir::separator() + appDesktopName;
170+}
171+
172+}
173+
174
175 SingleInstanceManager::SingleInstanceManager(QObject* parent)
176 : QObject(parent)
177@@ -54,13 +90,13 @@
178 return false;
179 }
180
181-bool SingleInstanceManager::run(const QStringList& arguments)
182+bool SingleInstanceManager::run(const QStringList& arguments, const QString& appId)
183 {
184 if (m_server.isListening()) {
185 return false;
186 }
187
188- QDir profile(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
189+ QDir profile(getProfilePathFromAppId(appId));
190 if (!profile.exists()) {
191 if (!QDir::root().mkpath(profile.absolutePath())) {
192 qCritical() << "Failed to create profile directory,"
193
194=== modified file 'src/app/single-instance-manager.h'
195--- src/app/single-instance-manager.h 2016-01-15 10:06:31 +0000
196+++ src/app/single-instance-manager.h 2016-05-10 14:22:12 +0000
197@@ -33,7 +33,7 @@
198 public:
199 SingleInstanceManager(QObject* parent=nullptr);
200
201- bool run(const QStringList& arguments);
202+ bool run(const QStringList& arguments, const QString& appId);
203
204 Q_SIGNALS:
205 void newInstanceLaunched(const QStringList& arguments) const;
206
207=== modified file 'src/app/webbrowser/webbrowser-app.cpp'
208--- src/app/webbrowser/webbrowser-app.cpp 2016-02-05 15:20:10 +0000
209+++ src/app/webbrowser/webbrowser-app.cpp 2016-05-10 14:22:12 +0000
210@@ -76,7 +76,7 @@
211 qmlRegisterSingletonType<DownloadsModel>(uri, 0, 1, "DownloadsModel", DownloadsModel_singleton_factory);
212 qmlRegisterType<TextSearchFilterModel>(uri, 0, 1, "TextSearchFilterModel");
213
214- if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml")) {
215+ if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml", QStringLiteral("webbrowser-app"))) {
216 QStringList searchEnginesSearchPaths;
217 searchEnginesSearchPaths << QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/searchengines";
218 searchEnginesSearchPaths << UbuntuBrowserDirectory() + "/webbrowser/searchengines";
219
220=== modified file 'src/app/webcontainer/webapp-container.cpp'
221--- src/app/webcontainer/webapp-container.cpp 2016-04-25 17:35:53 +0000
222+++ src/app/webcontainer/webapp-container.cpp 2016-05-10 14:22:12 +0000
223@@ -92,12 +92,38 @@
224 {
225 }
226
227+QString WebappContainer::appId() const
228+{
229+ Q_FOREACH(const QString& argument, m_arguments) {
230+ if (argument.startsWith("--app-id=")) {
231+ return argument.split("--app-id=")[1];
232+ }
233+ }
234+ return QString();
235+}
236
237 bool WebappContainer::initialize()
238 {
239 earlyEnvironment();
240
241- if (BrowserApplication::initialize("webcontainer/webapp-container.qml")) {
242+ if (qgetenv("APP_ID").isEmpty()) {
243+ QString id = appId();
244+ if (id.isEmpty()) {
245+ qCritical() << "The application has been launched with no "
246+ "explicit or system provided app id. "
247+ "An application id can be set by using the --app-id "
248+ "command line parameter and setting it to a unique "
249+ "application specific value or using the APP_ID environment "
250+ "variable.";
251+ return false;
252+ }
253+ qputenv("APP_ID", id.toUtf8());
254+ }
255+
256+ if (BrowserApplication::initialize(
257+ "webcontainer/webapp-container.qml",
258+ QString::fromUtf8(qgetenv("APP_ID")))) {
259+
260 parseCommandLine();
261 parseExtraConfiguration();
262
263
264=== modified file 'src/app/webcontainer/webapp-container.h'
265--- src/app/webcontainer/webapp-container.h 2016-02-27 21:45:57 +0000
266+++ src/app/webcontainer/webapp-container.h 2016-05-10 14:22:12 +0000
267@@ -54,6 +54,7 @@
268 bool shouldNotValidateCommandLineUrls() const;
269 bool isValidLocalIntentFilterFile(const QString& filename) const;
270 void setupLocalSchemeFilterIfAny(QQmlContext* context, const QString& webappSearchPath);
271+ QString appId() const;
272
273 private:
274 QString m_webappName;
275
276=== modified file 'tests/autopilot/webapp_container/tests/__init__.py'
277--- tests/autopilot/webapp_container/tests/__init__.py 2016-01-22 10:19:34 +0000
278+++ tests/autopilot/webapp_container/tests/__init__.py 2016-05-10 14:22:12 +0000
279@@ -57,6 +57,10 @@
280 args.append(
281 '--desktop_file_hint=/usr/share/applications/'
282 'webbrowser-app.desktop')
283+
284+ if next(filter(lambda e: e.startswith('--appid'), args), None) is None:
285+ args.append('--app-id=running.test')
286+
287 if envvars:
288 for envvar_key in envvars:
289 self.useFixture(fixtures.EnvironmentVariable(
290
291=== modified file 'tests/unittests/single-instance-manager/tst_SingleInstanceManagerTests.cpp'
292--- tests/unittests/single-instance-manager/tst_SingleInstanceManagerTests.cpp 2016-01-18 14:45:12 +0000
293+++ tests/unittests/single-instance-manager/tst_SingleInstanceManagerTests.cpp 2016-05-10 14:22:12 +0000
294@@ -50,18 +50,18 @@
295
296 void test_cannot_run_twice_same_instance()
297 {
298- QVERIFY(singleton->run(QStringList()));
299- QVERIFY(!singleton->run(QStringList()));
300+ QVERIFY(singleton->run(QStringList(), "appid"));
301+ QVERIFY(!singleton->run(QStringList(), "appid"));
302 QVERIFY(newInstanceSpy->isEmpty());
303 }
304
305 void test_arguments_passed_to_already_running_instance()
306 {
307- QVERIFY(singleton->run(QStringList()));
308+ QVERIFY(singleton->run(QStringList(), "appid"));
309 SingleInstanceManager other;
310 QStringList args;
311 args << QStringLiteral("foo") << QStringLiteral("bar") << QStringLiteral("baz");
312- QVERIFY(!other.run(args));
313+ QVERIFY(!other.run(args, "appid"));
314 newInstanceSpy->wait();
315 QCOMPARE(newInstanceSpy->first().at(0).toStringList(), args);
316 }

Subscribers

People subscribed via source and target branches

to status/vote changes: