Merge lp:~diegosarmentero/unity-scope-click/open-after-install into lp:unity-scope-click

Proposed by Diego Sarmentero
Status: Merged
Merged at revision: 170
Proposed branch: lp:~diegosarmentero/unity-scope-click/open-after-install
Merge into: lp:unity-scope-click
Prerequisite: lp:~dobey/unity-scope-click/uninstall
Diff against target: 433 lines (+253/-9)
10 files modified
debian/control (+1/-0)
scope/click/CMakeLists.txt (+5/-1)
scope/click/index.cpp (+3/-3)
scope/click/interface.cpp (+104/-0)
scope/click/interface.h (+22/-0)
scope/click/scope.cpp (+33/-4)
scope/tests/CMakeLists.txt (+1/-0)
scope/tests/click_interface_tool/CMakeLists.txt (+14/-0)
scope/tests/click_interface_tool/click_interface_tool.cpp (+69/-0)
scope/tests/test_index.cpp (+1/-1)
To merge this branch: bzr merge lp:~diegosarmentero/unity-scope-click/open-after-install
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Ubuntu One hackers Pending
Review via email: mp+207836@code.launchpad.net

This proposal supersedes a proposal from 2014-02-23.

Commit message

Enable uninstall, fix launching apps right after installation.

To post a comment you must log in.
175. By Diego Sarmentero

remove commented code for testing

176. By Diego Sarmentero

avoid unnecesary repetitions in the loop

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:175
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~diegosarmentero/unity-scope-click/open-after-install/+merge/207836/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/unity-scope-click-ci/346/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-scope-click-trusty-amd64-ci/247
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-scope-click-trusty-armhf-ci/244
        deb: http://jenkins.qa.ubuntu.com/job/unity-scope-click-trusty-armhf-ci/244/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity-scope-click-ci/346/rebuild

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

FAILED: Continuous integration, rev:176
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~diegosarmentero/unity-scope-click/open-after-install/+merge/207836/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/unity-scope-click-ci/347/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-scope-click-trusty-amd64-ci/248
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-scope-click-trusty-armhf-ci/245
        deb: http://jenkins.qa.ubuntu.com/job/unity-scope-click-trusty-armhf-ci/245/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity-scope-click-ci/347/rebuild

review: Needs Fixing (continuous-integration)
177. By Diego Sarmentero

using url-dispatch to launch the new apps

178. By Diego Sarmentero

fix uninstall process

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:178
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~diegosarmentero/unity-scope-click/open-after-install/+merge/207836/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/unity-scope-click-ci/348/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-scope-click-trusty-amd64-ci/249
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-scope-click-trusty-armhf-ci/246
        deb: http://jenkins.qa.ubuntu.com/job/unity-scope-click-trusty-armhf-ci/246/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity-scope-click-ci/348/rebuild

review: Needs Fixing (continuous-integration)
179. By Diego Sarmentero

using liburl-dispatcher

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
180. By Diego Sarmentero

typo in uninstall fixed

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2014-02-18 15:34:14 +0000
3+++ debian/control 2014-02-23 22:50:47 +0000
4@@ -20,6 +20,7 @@
5 libubuntuoneauth-2.0-dev,
6 libunity-dev (>= 7.0.0),
7 libunity-scopes-dev (>= 0.3.1),
8+ liburl-dispatcher1-dev,
9 pkg-config,
10 python (>= 2.7),
11 valac,
12
13=== modified file 'scope/click/CMakeLists.txt'
14--- scope/click/CMakeLists.txt 2014-02-17 08:45:26 +0000
15+++ scope/click/CMakeLists.txt 2014-02-23 22:50:47 +0000
16@@ -1,6 +1,7 @@
17 SET (CMAKE_INCLUDE_CURRENT_DIR ON)
18 SET (CMAKE_AUTOMOC ON)
19 find_package (Qt5Core REQUIRED)
20+pkg_check_modules(LIBURL_DISPATCHER REQUIRED url-dispatcher-1)
21
22 add_library(${SCOPE_LIB_UNVERSIONED} SHARED
23 download-manager.cpp
24@@ -21,14 +22,17 @@
25 configure_file(config.h.in config.h)
26
27 include_directories (${CMAKE_BINARY_DIR}/scope)
28+include_directories(${LIBURL_DISPATCHER_INCLUDE_DIRS})
29+link_directories(${LIBURL_DISPATCHER_LIBRARY_DIRS})
30
31-qt5_use_modules (${SCOPE_LIB_UNVERSIONED} Network)
32+qt5_use_modules (${SCOPE_LIB_UNVERSIONED} Network Gui)
33
34 target_link_libraries (${SCOPE_LIB_UNVERSIONED}
35 ${UNITY_SCOPES_LDFLAGS}
36 ${UBUNTUONE_LDFLAGS}
37 ${UBUNTU_DOWNLOAD_MANAGER_CLIENT_LDFLAGS}
38 ${UBUNTU_DOWNLOAD_MANAGER_COMMON_LDFLAGS}
39+ ${LIBURL_DISPATCHER_LIBRARIES}
40 )
41
42 install(
43
44=== modified file 'scope/click/index.cpp'
45--- scope/click/index.cpp 2014-02-23 22:50:47 +0000
46+++ scope/click/index.cpp 2014-02-23 22:50:47 +0000
47@@ -75,7 +75,7 @@
48 void PackageManager::uninstall(const Package& package,
49 std::function<void(int, std::string)> callback)
50 {
51- std::string package_id = package.name + ";" + package.version + ";all;local;click";
52+ std::string package_id = package.name + ";" + package.version + ";all;local:click";
53 std::string command = "pkcon -p remove " + package_id;
54 execute_uninstall_command(command, callback);
55 }
56@@ -89,7 +89,7 @@
57 typedef void(QProcess::*QProcessError)(QProcess::ProcessError);
58 QObject::connect(process.data(),
59 static_cast<QProcessFinished>(&QProcess::finished),
60- [&](int code, QProcess::ExitStatus status) {
61+ [process, callback](int code, QProcess::ExitStatus status) {
62 Q_UNUSED(status);
63 qDebug() << "command finished with exit code:" << code;
64 callback(code, process.data()->readAllStandardError().data());
65@@ -99,7 +99,7 @@
66 } );
67 QObject::connect(process.data(),
68 static_cast<QProcessError>(&QProcess::error),
69- [&](QProcess::ProcessError error) {
70+ [process, callback](QProcess::ProcessError error) {
71 qCritical() << "error running command:" << error;
72 callback(-255 + error, process.data()->readAllStandardError().data());
73 } );
74
75=== modified file 'scope/click/interface.cpp'
76--- scope/click/interface.cpp 2014-02-23 22:50:47 +0000
77+++ scope/click/interface.cpp 2014-02-23 22:50:47 +0000
78@@ -29,6 +29,7 @@
79
80 #include <QDebug>
81 #include <QDir>
82+#include <QProcess>
83 #include <QStandardPaths>
84 #include <QTimer>
85
86@@ -36,6 +37,11 @@
87 #include <sys/stat.h>
88 #include <map>
89
90+#include <boost/property_tree/ptree.hpp>
91+#include <boost/property_tree/json_parser.hpp>
92+#include <boost/property_tree/exceptions.hpp>
93+#include <boost/foreach.hpp>
94+
95 #include <unity/UnityExceptions.h>
96 #include <unity/util/IniParser.h>
97
98@@ -231,4 +237,102 @@
99 }
100 }
101
102+
103+ManifestList manifest_list_from_json(const std::string& json)
104+{
105+ using namespace boost::property_tree;
106+
107+ std::istringstream is(json);
108+
109+ ptree pt;
110+ read_json(is, pt);
111+
112+ ManifestList manifests;
113+
114+ BOOST_FOREACH(ptree::value_type &v, pt)
115+ {
116+ assert(v.first.empty()); // array elements have no names
117+ auto node = v.second;
118+ std::string name = node.get<std::string>("name");
119+ std::string version = node.get<std::string>("version");
120+ std::string first_app_name;
121+
122+ BOOST_FOREACH(ptree::value_type &sv, node.get_child("hooks"))
123+ {
124+ // FIXME: "primary app" for a package is not defined, we just
125+ // use first one here:
126+ first_app_name = sv.first;
127+ break;
128+ }
129+ qDebug() << "adding manifest: " << name.c_str() << version.c_str() << first_app_name.c_str();
130+
131+ manifests.push_back(Manifest(name, version, first_app_name));
132+ }
133+
134+ return manifests;
135+}
136+
137+void Interface::get_manifests(std::function<void(ManifestList, ManifestError)> callback)
138+{
139+ QSharedPointer<QProcess> process(new QProcess());
140+ typedef void(QProcess::*QProcessFinished)(int, QProcess::ExitStatus);
141+ typedef void(QProcess::*QProcessError)(QProcess::ProcessError);
142+ QObject::connect(process.data(),
143+ static_cast<QProcessFinished>(&QProcess::finished),
144+ [callback, process](int code, QProcess::ExitStatus /*status*/) {
145+ qDebug() << "manifest command finished with exit code:" << code;
146+ try {
147+ auto data = process.data()->readAllStandardOutput().data();
148+ ManifestList manifests = manifest_list_from_json(data);
149+ qDebug() << "calling back ";
150+ callback(manifests, ManifestError::NoError);
151+ }
152+ catch ( ... ) {
153+ callback(ManifestList(), ManifestError::ParseError);
154+ }
155+ } );
156+
157+ QObject::connect(process.data(),
158+ static_cast<QProcessError>(&QProcess::error),
159+ [callback, process](QProcess::ProcessError error) {
160+ qCritical() << "error running command:" << error;
161+ callback(ManifestList(), ManifestError::CallError);
162+ } );
163+
164+ std::string command = "click list --manifest";
165+ qDebug() << "Running command:" << command.c_str();
166+ process->start(command.c_str());
167+}
168+
169+void Interface::get_dotdesktop_filename(const std::string &app_id,
170+ std::function<void(std::string, ManifestError)> callback)
171+{
172+ get_manifests([app_id, callback] (ManifestList manifests, ManifestError error) {
173+ qDebug() << "in get_dotdesktop_filename callback";
174+
175+ if (error != ManifestError::NoError){
176+ callback(std::string("Internal Error"), error);
177+ return;
178+ }
179+ bool found = false;
180+ qDebug() << "in get_dotdesktop_filename callback";
181+
182+
183+ for (auto manifest : manifests) {
184+ if (manifest.name != app_id) continue;
185+ found = true;
186+ std::string ddstr = manifest.name + "_" + manifest.first_app_name + "_" + manifest.version + ".desktop";
187+ callback(ddstr, ManifestError::NoError);
188+ break;
189+ }
190+ if (!found) {
191+ qCritical() << "Warning: no manifest found for " << app_id.c_str();
192+ callback(std::string("Not found"), ManifestError::CallError);
193+ }
194+ });
195+}
196+
197+
198+
199+
200 } // namespace click
201
202=== modified file 'scope/click/interface.h'
203--- scope/click/interface.h 2014-02-17 19:12:56 +0000
204+++ scope/click/interface.h 2014-02-23 22:50:47 +0000
205@@ -46,6 +46,25 @@
206 // Hash map of desktop files that are not yet click packages
207 const std::unordered_set<std::string>& nonClickDesktopFiles();
208
209+struct Manifest
210+{
211+ Manifest() = default;
212+ Manifest(std::string name, std::string version, std::string first_app_name) :
213+ name(name), version(version), first_app_name(first_app_name)
214+ {
215+ }
216+ virtual ~Manifest() = default;
217+
218+ std::string name;
219+ std::string version;
220+ std::string first_app_name;
221+};
222+
223+enum class ManifestError {NoError, CallError, ParseError};
224+typedef std::list<Manifest> ManifestList;
225+
226+ManifestList manifest_list_from_json(const std::string& json);
227+
228 class Interface
229 {
230 public:
231@@ -61,6 +80,9 @@
232
233 static bool is_icon_identifier(const std::string &icon_id);
234 static std::string add_theme_scheme(const std::string &filename);
235+ static void get_manifests(std::function<void(ManifestList, ManifestError)> callback);
236+ static void get_dotdesktop_filename(const std::string &app_id,
237+ std::function<void(std::string filename, ManifestError)> callback);
238 private:
239 QSharedPointer<KeyFileLocator> keyFileLocator;
240 };
241
242=== modified file 'scope/click/scope.cpp'
243--- scope/click/scope.cpp 2014-02-23 22:50:47 +0000
244+++ scope/click/scope.cpp 2014-02-23 22:50:47 +0000
245@@ -33,8 +33,22 @@
246 #include "preview.h"
247 #include "webclient.h"
248 #include "network_access_manager.h"
249+#include "key_file_locator.h"
250+#include "interface.h"
251
252 #include <QSharedPointer>
253+#include <url-dispatcher.h>
254+
255+namespace
256+{
257+click::Interface& clickInterfaceInstance()
258+{
259+ static QSharedPointer<click::KeyFileLocator> keyFileLocator(new click::KeyFileLocator());
260+ static click::Interface iface(keyFileLocator);
261+
262+ return iface;
263+}
264+}
265
266 class ScopeActivation : public unity::scopes::ActivationBase
267 {
268@@ -105,7 +119,7 @@
269 if(metadict.count(click::Preview::Actions::DOWNLOAD_FAILED) != 0) {
270 return scopes::QueryBase::UPtr{new ErrorPreview(std::string("Download or install failed. Please try again."),
271 index, result)};
272- } else if (metadict.count(click::Preview::Actions::DOWNLOAD_COMPLETED) != 0 &&
273+ } else if (metadict.count(click::Preview::Actions::DOWNLOAD_COMPLETED) != 0 ||
274 metadict.count(click::Preview::Actions::CLOSE_PREVIEW) != 0) {
275 Preview* prev = new Preview(result.uri(), index, result);
276 prev->setPreview(click::Preview::Type::INSTALLED);
277@@ -131,13 +145,29 @@
278 return previewResult;
279 }
280
281-unity::scopes::ActivationBase::UPtr click::Scope::perform_action(unity::scopes::Result const& /*result*/, unity::scopes::ActionMetadata const& metadata, std::string const& /* widget_id */, std::string const& action_id)
282+unity::scopes::ActivationBase::UPtr click::Scope::perform_action(unity::scopes::Result const& result, unity::scopes::ActionMetadata const& metadata, std::string const& /* widget_id */, std::string const& action_id)
283 {
284 auto activation = new ScopeActivation();
285 qDebug() << "perform_action called with action_id" << QString().fromStdString(action_id);
286
287 if (action_id == click::Preview::Actions::OPEN_CLICK) {
288- activation->setStatus(unity::scopes::ActivationResponse::Status::NotHandled);
289+ QString app_url = QString::fromStdString(result.uri());
290+ if (!app_url.startsWith("application:///")) {
291+ qt::core::world::enter_with_task([this, result] (qt::core::world::Environment& /*env*/)
292+ {
293+ clickInterfaceInstance().get_dotdesktop_filename(result["name"].get_string(),
294+ [] (std::string val, click::ManifestError error){
295+ if (error == click::ManifestError::NoError) {
296+ std::string uri = "application:///" + val;
297+ url_dispatch_send(uri.c_str() , NULL, NULL);
298+ }
299+ }
300+ );
301+ });
302+ activation->setStatus(unity::scopes::ActivationResponse::Status::HideDash);
303+ } else {
304+ activation->setStatus(unity::scopes::ActivationResponse::Status::NotHandled);
305+ }
306 } else if (action_id == click::Preview::Actions::INSTALL_CLICK) {
307 std::string download_url = metadata.scope_data().get_dict()["download_url"].get_string();
308 qDebug() << "the download url is: " << QString::fromStdString(download_url);
309@@ -149,7 +179,6 @@
310 } else if (action_id == click::Preview::Actions::DOWNLOAD_FAILED) {
311 activation->setHint(click::Preview::Actions::DOWNLOAD_FAILED, unity::scopes::Variant(true));
312 activation->setStatus(unity::scopes::ActivationResponse::Status::ShowPreview);
313-
314 } else if (action_id == click::Preview::Actions::DOWNLOAD_COMPLETED) {
315 activation->setHint(click::Preview::Actions::DOWNLOAD_COMPLETED, unity::scopes::Variant(true));
316 activation->setStatus(unity::scopes::ActivationResponse::Status::ShowPreview);
317
318=== modified file 'scope/tests/CMakeLists.txt'
319--- scope/tests/CMakeLists.txt 2014-02-17 08:45:26 +0000
320+++ scope/tests/CMakeLists.txt 2014-02-23 22:50:47 +0000
321@@ -58,3 +58,4 @@
322
323 add_subdirectory(integration)
324 add_subdirectory(download_manager_tool)
325+add_subdirectory(click_interface_tool)
326\ No newline at end of file
327
328=== added directory 'scope/tests/click_interface_tool'
329=== added file 'scope/tests/click_interface_tool/CMakeLists.txt'
330--- scope/tests/click_interface_tool/CMakeLists.txt 1970-01-01 00:00:00 +0000
331+++ scope/tests/click_interface_tool/CMakeLists.txt 2014-02-23 22:50:47 +0000
332@@ -0,0 +1,14 @@
333+set(CLICK_INTERFACE_TOOL_TARGET click_interface_tool)
334+
335+include_directories (
336+ ${CMAKE_SOURCE_DIR}/scope/click
337+ ${CMAKE_BINARY_DIR}/scope/click
338+)
339+
340+add_executable (${CLICK_INTERFACE_TOOL_TARGET}
341+ click_interface_tool.cpp
342+)
343+
344+target_link_libraries (${CLICK_INTERFACE_TOOL_TARGET}
345+ ${SCOPE_LIB_UNVERSIONED}
346+)
347
348=== added file 'scope/tests/click_interface_tool/click_interface_tool.cpp'
349--- scope/tests/click_interface_tool/click_interface_tool.cpp 1970-01-01 00:00:00 +0000
350+++ scope/tests/click_interface_tool/click_interface_tool.cpp 2014-02-23 22:50:47 +0000
351@@ -0,0 +1,69 @@
352+/*
353+ * Copyright (C) 2014 Canonical Ltd.
354+ *
355+ * This program is free software: you can redistribute it and/or modify it
356+ * under the terms of the GNU General Public License version 3, as published
357+ * by the Free Software Foundation.
358+ *
359+ * This program is distributed in the hope that it will be useful, but
360+ * WITHOUT ANY WARRANTY; without even the implied warranties of
361+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
362+ * PURPOSE. See the GNU General Public License for more details.
363+ *
364+ * You should have received a copy of the GNU General Public License along
365+ * with this program. If not, see <http://www.gnu.org/licenses/>.
366+ *
367+ * In addition, as a special exception, the copyright holders give
368+ * permission to link the code of portions of this program with the
369+ * OpenSSL library under certain conditions as described in each
370+ * individual source file, and distribute linked combinations
371+ * including the two.
372+ * You must obey the GNU General Public License in all respects
373+ * for all of the code used other than OpenSSL. If you modify
374+ * file(s) with this exception, you may extend this exception to your
375+ * version of the file(s), but you are not obligated to do so. If you
376+ * do not wish to do so, delete this exception statement from your
377+ * version. If you delete this exception statement from all source
378+ * files in the program, then also delete it here.
379+ */
380+
381+#include <QCoreApplication>
382+#include <QDebug>
383+#include <QString>
384+#include <QTimer>
385+#include <QTextStream>
386+
387+#include <iostream>
388+
389+#include <interface.h>
390+#include <key_file_locator.h>
391+
392+int main(int argc, char *argv[])
393+{
394+
395+ QCoreApplication a(argc, argv);
396+ QSharedPointer<click::KeyFileLocator> keyFileLocator(new click::KeyFileLocator());
397+ click::Interface ci(keyFileLocator);
398+
399+
400+ QTimer timer;
401+ timer.setSingleShot(true);
402+
403+ QObject::connect(&timer, &QTimer::timeout, [&]() {
404+ ci.get_dotdesktop_filename(std::string(argv[1]),
405+ [&a] (std::string val, click::ManifestError error){
406+ if (error == click::ManifestError::NoError) {
407+ std::cout << " Success, got dotdesktop:" << val << std::endl;
408+ } else {
409+ std::cout << " Error:" << val << std::endl;
410+ }
411+ a.quit();
412+ });
413+ } );
414+
415+ timer.start(0);
416+
417+ qInstallMessageHandler(0);
418+ return a.exec();
419+}
420+
421
422=== modified file 'scope/tests/test_index.cpp'
423--- scope/tests/test_index.cpp 2014-02-23 22:50:47 +0000
424+++ scope/tests/test_index.cpp 2014-02-23 22:50:47 +0000
425@@ -283,7 +283,7 @@
426 "/tmp/foo.png",
427 "", "0.1.5"
428 };
429- std::string expected = "pkcon -p remove org.example.testapp;0.1.5;all;local;click";
430+ std::string expected = "pkcon -p remove org.example.testapp;0.1.5;all;local:click";
431 EXPECT_CALL(*this, execute_uninstall_command(expected, _)).Times(1);
432 uninstall(package, [](int, std::string) {});
433 }

Subscribers

People subscribed via source and target branches