Merge lp:~mhr3/unity-scopes-api/always-join-threads into lp:unity-scopes-api

Proposed by Michal Hruby
Status: Superseded
Proposed branch: lp:~mhr3/unity-scopes-api/always-join-threads
Merge into: lp:unity-scopes-api
Diff against target: 1673 lines (+615/-325)
31 files modified
CMakeLists.txt (+4/-2)
debian/control (+3/-0)
debian/libunity-scopes1.scope.click-hook (+3/-0)
debian/libunity-scopes1.symbols (+5/-0)
debian/rules (+4/-1)
demo/CMakeLists.txt (+1/-0)
demo/click/CMakeLists.txt (+1/-0)
demo/click/scope-click/CMakeLists.txt (+34/-0)
demo/click/scope-click/click-build.sh (+47/-0)
demo/click/scope-click/click/CMakeLists.txt (+8/-0)
demo/click/scope-click/click/manifest.json.in (+19/-0)
demo/click/scope-click/scope-click.cpp (+95/-0)
demo/click/scope-click/scope-click.ini.in (+9/-0)
demo/click/scope-click/scope-click.map (+9/-0)
include/unity/scopes/ScopeMetadata.h (+14/-0)
include/unity/scopes/internal/RegistryConfig.h (+2/-0)
include/unity/scopes/internal/ScopeConfig.h (+3/-0)
include/unity/scopes/internal/ScopeMetadataImpl.h (+3/-0)
include/unity/scopes/internal/smartscopes/SmartScope.h (+25/-5)
scoperegistry/FindFiles.cpp (+10/-34)
scoperegistry/scoperegistry.cpp (+125/-70)
scoperunner/scoperunner.cpp (+86/-143)
src/scopes/ScopeMetadata.cpp (+5/-0)
src/scopes/internal/RegistryConfig.cpp (+10/-0)
src/scopes/internal/ScopeConfig.cpp (+32/-0)
src/scopes/internal/ScopeMetadataImpl.cpp (+17/-1)
test/gtest/scopes/Registry/Registry_test.cpp (+22/-0)
test/gtest/scopes/internal/ScopeMetadataImpl/ScopeMetadataImpl_test.cpp (+5/-1)
test/whitespace/CMakeLists.txt (+5/-1)
test/whitespace/check_whitespace.py (+9/-5)
test/whitespace/check_whitespace.sh (+0/-62)
To merge this branch: bzr merge lp:~mhr3/unity-scopes-api/always-join-threads
Reviewer Review Type Date Requested Status
Unity Team Pending
Review via email: mp+214801@code.launchpad.net

This proposal has been superseded by a proposal from 2014-04-08.

Commit message

Always join worker threads.

Description of the change

Always join worker threads. Otherwise if something throws an exception, the thread is destructed without being joined, and that's not a good thing to do.

To post a comment you must log in.
302. By Michal Hruby

Wrap the trap thread also in smartscopesproxy

303. By Marcus Tomlinson

Init state receiver first

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-04-04 14:53:32 +0000
3+++ CMakeLists.txt 2014-04-08 16:22:25 +0000
4@@ -54,11 +54,12 @@
5 endif()
6
7 include(FindPkgConfig)
8-find_package(Boost COMPONENTS regex serialization REQUIRED)
9+find_package(Boost COMPONENTS system filesystem regex serialization REQUIRED)
10 pkg_check_modules(UNITY_API libunity-api>=0.1.1 REQUIRED)
11 pkg_check_modules(PROCESS_CPP process-cpp>=1.0.0 REQUIRED)
12 pkg_check_modules(LTTNG_UST lttng-ust REQUIRED)
13 pkg_check_modules(LIBURCU_BP liburcu-bp REQUIRED)
14+pkg_check_modules(APPARMOR REQUIRED libapparmor REQUIRED)
15 find_program(LTTNG_EXECUTABLE lttng)
16 if (NOT LTTNG_EXECUTABLE)
17 message(SEND_ERROR "Cannot find LTTng executable: ensure that lttng-tools is installed")
18@@ -100,7 +101,7 @@
19 endif()
20 set(CAPNPC_FLAGS "" CACHE STRING "Extra flags for capnpc.")
21
22-set(OTHER_INCLUDE_DIRS ${OTHER_INCLUDE_DIRS} ${UNITY_API_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${JSONCPP_INCLUDE_DIRS} ${PROCESS_CPP_INCLUDE_DIRS})
23+set(OTHER_INCLUDE_DIRS ${OTHER_INCLUDE_DIRS} ${UNITY_API_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${JSONCPP_INCLUDE_DIRS} ${PROCESS_CPP_INCLUDE_DIRS} ${APPARMOR_INCLUDE_DIRS})
24 set(OTHER_LIBS ${UNITY_API_LDFLAGS} ${OTHER_LIBS})
25
26 # Standard install paths
27@@ -218,6 +219,7 @@
28 ${Boost_LIBRARIES}
29 ${JSONCPP_LDFLAGS}
30 ${PROCESS_CPP_LDFLAGS}
31+ ${APPARMOR_LDFLAGS}
32 ${ZMQPPLIB}
33 ${ZMQLIB}
34 ${CAPNPLIB}
35
36=== modified file 'debian/control'
37--- debian/control 2014-04-04 14:53:32 +0000
38+++ debian/control 2014-04-08 16:22:25 +0000
39@@ -2,6 +2,7 @@
40 Priority: optional
41 Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
42 Build-Depends: debhelper (>= 9),
43+ click-dev (>= 0.2.2),
44 cmake,
45 doxygen,
46 google-mock,
47@@ -9,8 +10,10 @@
48 pkg-config,
49 python3,
50 capnproto,
51+ libapparmor-dev,
52 libprocess-cpp-dev (>= 1.0.0),
53 libunity-api-dev (>= 7.80.5~),
54+ libboost-filesystem-dev,
55 libboost-regex-dev,
56 libboost-serialization-dev,
57 libcapnp-dev (>= 0.4.0),
58
59=== added file 'debian/libunity-scopes1.scope.click-hook'
60--- debian/libunity-scopes1.scope.click-hook 1970-01-01 00:00:00 +0000
61+++ debian/libunity-scopes1.scope.click-hook 2014-04-08 16:22:25 +0000
62@@ -0,0 +1,3 @@
63+Pattern: ${home}/.local/share/unity-scopes/${id}
64+User-Level: yes
65+Hook-Name: scope
66
67=== modified file 'debian/libunity-scopes1.symbols'
68--- debian/libunity-scopes1.symbols 2014-04-04 17:36:38 +0000
69+++ debian/libunity-scopes1.symbols 2014-04-08 16:22:25 +0000
70@@ -430,6 +430,8 @@
71 (c++)"unity::scopes::internal::MiddlewareFactory::to_kind(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
72 (c++)"unity::scopes::internal::MiddlewareFactory::MiddlewareFactory(unity::scopes::internal::RuntimeImpl*)@Base" 0.4.0+14.04.20140312.1
73 (c++)"unity::scopes::internal::MiddlewareFactory::~MiddlewareFactory()@Base" 0.4.0+14.04.20140312.1
74+ (c++)"unity::scopes::internal::ScopeMetadataImpl::set_confinement_type(unity::scopes::ConfinementType)@Base" 0replaceme
75+ (c++)"unity::scopes::internal::ScopeMetadataImpl::confinement_type() const@Base" 0replaceme
76 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_author(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
77 (c++)"unity::scopes::internal::ScopeMetadataImpl::deserialize(std::map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, unity::scopes::Variant, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, unity::scopes::Variant> > > const&)@Base" 0.4.0+14.04.20140312.1
78 (c++)"unity::scopes::internal::ScopeMetadataImpl::set_hot_key(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
79@@ -511,6 +513,7 @@
80 (c++)"unity::scopes::PreviewWidget::id() const@Base" 0.4.0+14.04.20140312.1
81 (c++)"unity::scopes::PreviewWidget::data() const@Base" 0.4.0+14.04.20140312.1
82 (c++)"unity::scopes::PreviewWidget::serialize() const@Base" 0.4.0+14.04.20140312.1
83+ (c++)"unity::scopes::ScopeMetadata::confinement_type() const@Base" 0replaceme
84 (c++)"unity::scopes::ScopeMetadata::description() const@Base" 0.4.0+14.04.20140312.1
85 (c++)"unity::scopes::ScopeMetadata::search_hint() const@Base" 0.4.0+14.04.20140312.1
86 (c++)"unity::scopes::ScopeMetadata::display_name() const@Base" 0.4.0+14.04.20140312.1
87@@ -610,6 +613,7 @@
88 (c++)"unity::scopes::internal::RuntimeImpl::factory() const@Base" 0.4.0+14.04.20140312.1
89 (c++)"unity::scopes::internal::RuntimeImpl::registry() const@Base" 0.4.0+14.04.20140312.1
90 (c++)"unity::scopes::internal::RuntimeImpl::scope_id() const@Base" 0.4.0+14.04.20140312.1
91+ (c++)"unity::scopes::internal::ScopeConfig::confinement_type() const@Base" 0replaceme
92 (c++)"unity::scopes::internal::ScopeConfig::description() const@Base" 0.4.0+14.04.20140312.1
93 (c++)"unity::scopes::internal::ScopeConfig::search_hint() const@Base" 0.4.0+14.04.20140312.1
94 (c++)"unity::scopes::internal::ScopeConfig::display_name() const@Base" 0.4.0+14.04.20140312.1
95@@ -634,6 +638,7 @@
96 (c++)"unity::scopes::internal::RuntimeConfig::registry_configfile() const@Base" 0.4.2+14.04.20140404.2
97 (c++)"unity::scopes::internal::RuntimeConfig::default_middleware_configfile() const@Base" 0.4.2+14.04.20140404.2
98 (c++)"unity::scopes::internal::MiddlewareBase::runtime() const@Base" 0.4.0+14.04.20140312.1
99+ (c++)"unity::scopes::internal::RegistryConfig::click_installdir() const@Base" 0replaceme
100 (c++)"unity::scopes::internal::RegistryConfig::endpointdir() const@Base" 0.4.0+14.04.20140312.1
101 (c++)"unity::scopes::internal::RegistryConfig::mw_configfile() const@Base" 0.4.0+14.04.20140312.1
102 (c++)"unity::scopes::internal::RegistryConfig::oem_installdir() const@Base" 0.4.0+14.04.20140312.1
103
104=== modified file 'debian/rules'
105--- debian/rules 2013-12-19 02:35:14 +0000
106+++ debian/rules 2014-04-08 16:22:25 +0000
107@@ -6,7 +6,7 @@
108 export DPKG_GENSYMBOLS_CHECK_LEVEL=4
109
110 %:
111- dh $@ --parallel --fail-missing
112+ dh $@ --parallel --fail-missing --with click
113
114 override_dh_auto_configure:
115 dh_auto_configure -- -DLIBDIR=/usr/lib/$(DEB_HOST_MULTIARCH)
116@@ -14,3 +14,6 @@
117 # Tests are not written to be run in parallel.
118 override_dh_auto_test:
119 dh_auto_test --max-parallel=1 -- ARGS="--verbose"
120+
121+override_dh_click:
122+ dh_click --name scope
123
124=== modified file 'demo/CMakeLists.txt'
125--- demo/CMakeLists.txt 2014-02-03 09:04:04 +0000
126+++ demo/CMakeLists.txt 2014-04-08 16:22:25 +0000
127@@ -1,3 +1,4 @@
128+add_subdirectory(click)
129 add_subdirectory(scopes)
130 add_subdirectory(stand-alone)
131
132
133=== added directory 'demo/click'
134=== added file 'demo/click/CMakeLists.txt'
135--- demo/click/CMakeLists.txt 1970-01-01 00:00:00 +0000
136+++ demo/click/CMakeLists.txt 2014-04-08 16:22:25 +0000
137@@ -0,0 +1,1 @@
138+add_subdirectory(scope-click)
139
140=== added directory 'demo/click/scope-click'
141=== added file 'demo/click/scope-click/CMakeLists.txt'
142--- demo/click/scope-click/CMakeLists.txt 1970-01-01 00:00:00 +0000
143+++ demo/click/scope-click/CMakeLists.txt 2014-04-08 16:22:25 +0000
144@@ -0,0 +1,34 @@
145+
146+if(CLICK_MODE)
147+ project(unity-scope-click C CXX)
148+ cmake_minimum_required(VERSION 2.8.10)
149+
150+ include(GNUInstallDirs)
151+ include(FindPkgConfig)
152+
153+ pkg_check_modules(UNITY_SCOPES REQUIRED libunity-scopes>=0.4.0)
154+ add_definitions(${UNITY_SCOPES_CFLAGS} ${UNITY_SCOPES_CFLAGS_OTHER})
155+
156+ add_definitions(-std=c++11)
157+endif(CLICK_MODE)
158+
159+add_subdirectory(click)
160+
161+set(symbol_map "${CMAKE_CURRENT_SOURCE_DIR}/scope-click.map")
162+
163+add_library(scope-click MODULE scope-click.cpp)
164+# Add_dependencies should be used sparingly. In this case we need the global
165+# header to be generated before we start building the client binary.
166+add_dependencies(scope-click globalheader)
167+set_target_properties(scope-click PROPERTIES
168+ LINK_FLAGS "${ldflags} -Wl,--version-script,${symbol_map}")
169+set_target_properties(scope-click PROPERTIES LINK_DEPENDS ${symbol_map})
170+
171+configure_file(scope-click.ini.in scope-click.ini)
172+
173+if(CLICK_MODE)
174+ install(TARGETS scope-click
175+ DESTINATION "${CMAKE_INSTALL_PREFIX}/scope-click/")
176+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/scope-click.ini"
177+ DESTINATION "${CMAKE_INSTALL_PREFIX}/scope-click/")
178+endif(CLICK_MODE)
179
180=== added directory 'demo/click/scope-click/click'
181=== added file 'demo/click/scope-click/click-build.sh'
182--- demo/click/scope-click/click-build.sh 1970-01-01 00:00:00 +0000
183+++ demo/click/scope-click/click-build.sh 2014-04-08 16:22:25 +0000
184@@ -0,0 +1,47 @@
185+#!/bin/sh
186+
187+# Copyright (C) 2014 Canonical Ltd
188+#
189+# This program is free software: you can redistribute it and/or modify
190+# it under the terms of the GNU Lesser General Public License version 3 as
191+# published by the Free Software Foundation.
192+#
193+# This program is distributed in the hope that it will be useful,
194+# but WITHOUT ANY WARRANTY; without even the implied warranty of
195+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
196+# GNU Lesser General Public License for more details.
197+#
198+# You should have received a copy of the GNU Lesser General Public License
199+# along with this program. If not, see <http://www.gnu.org/licenses/>.
200+#
201+# Authored by: Pete Woods <pete.woods@canonical.com>
202+
203+# Simple script to build a click packaged scope.
204+
205+
206+export LC_ALL=C
207+
208+if [ "$#" -ne 1 ]; then
209+ echo "Usage: click-build.sh amd64|armhf|..."
210+ exit 1
211+fi
212+
213+BZR_SOURCE=${1:-lp:scope-click}
214+
215+CLICK_ARCH="$1"
216+rm -rf "$CLICK_ARCH-build"
217+rm -rf "package"
218+mkdir "$CLICK_ARCH-build"
219+(
220+ cd "$CLICK_ARCH-build"
221+ cmake .. \
222+ -DCMAKE_INSTALL_PREFIX:PATH=../package \
223+ -DCLICK_MODE=on \
224+ -DCLICK_ARCH="$CLICK_ARCH" \
225+ -DBZR_REVNO=$(cd ..; bzr revno) \
226+ -DBZR_SOURCE="$BZR_SOURCE"
227+ make install
228+)
229+click build package
230+rm -rf "$CLICK_ARCH-build"
231+rm -rf "package"
232
233=== added file 'demo/click/scope-click/click/CMakeLists.txt'
234--- demo/click/scope-click/click/CMakeLists.txt 1970-01-01 00:00:00 +0000
235+++ demo/click/scope-click/click/CMakeLists.txt 2014-04-08 16:22:25 +0000
236@@ -0,0 +1,8 @@
237+if(CLICK_MODE)
238+ if(NOT BZR_REVNO)
239+ set(BZR_REVNO "latest")
240+ endif(NOT BZR_REVNO)
241+ configure_file(manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/manifest.json)
242+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json
243+ DESTINATION ${CMAKE_INSTALL_PREFIX})
244+endif(CLICK_MODE)
245
246=== added file 'demo/click/scope-click/click/manifest.json.in'
247--- demo/click/scope-click/click/manifest.json.in 1970-01-01 00:00:00 +0000
248+++ demo/click/scope-click/click/manifest.json.in 2014-04-08 16:22:25 +0000
249@@ -0,0 +1,19 @@
250+{
251+ "description": "A pretend click scope",
252+ "framework": "ubuntu-sdk-14.04-dev1",
253+ "architecture": "@CLICK_ARCH@",
254+ "hooks": {
255+ "scope-click": {
256+ "scope": "scope-click"
257+ }
258+ },
259+ "icon": "@CLICK_SCOPE_ICON@",
260+ "maintainer": "Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>",
261+ "name": "com.ubuntu.scope-click",
262+ "title": "Click Scope",
263+ "version": "1.0.0.@BZR_REVNO@",
264+ "x-source": {
265+ "vcs-bzr": "@BZR_SOURCE@",
266+ "vcs-bzr-revno": "@BZR_REVNO@"
267+ }
268+}
269
270=== added file 'demo/click/scope-click/scope-click.cpp'
271--- demo/click/scope-click/scope-click.cpp 1970-01-01 00:00:00 +0000
272+++ demo/click/scope-click/scope-click.cpp 2014-04-08 16:22:25 +0000
273@@ -0,0 +1,95 @@
274+/*
275+ * Copyright (C) 2014 Canonical Ltd
276+ *
277+ * This program is free software: you can redistribute it and/or modify
278+ * it under the terms of the GNU Lesser General Public License version 3 as
279+ * published by the Free Software Foundation.
280+ *
281+ * This program is distributed in the hope that it will be useful,
282+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
283+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
284+ * GNU Lesser General Public License for more details.
285+ *
286+ * You should have received a copy of the GNU Lesser General Public License
287+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
288+ *
289+ * Authored by: Michi Henning <michi.henning@canonical.com>
290+ */
291+
292+#include <unity/scopes/ScopeBase.h>
293+
294+#include <iostream>
295+#include <thread>
296+
297+#define EXPORT __attribute__ ((visibility ("default")))
298+
299+using namespace std;
300+using namespace unity::scopes;
301+
302+// Demonstration of building a click scope. This file has the bare minimum scope implementation.
303+
304+class MyQuery : public SearchQueryBase
305+{
306+public:
307+ MyQuery()
308+ {
309+ }
310+
311+ ~MyQuery()
312+ {
313+ }
314+
315+ virtual void cancelled() override
316+ {
317+ cerr << "scope-click: received cancel request" << endl;
318+ }
319+
320+ virtual void run(SearchReplyProxy const&) override
321+ {
322+ cerr << "scope-click: received query" << endl;
323+ this_thread::sleep_for(chrono::seconds(3));
324+ cerr << "scope-click: query complete" << endl;
325+ }
326+};
327+
328+class MyScope : public ScopeBase
329+{
330+public:
331+ virtual int start(string const&, RegistryProxy const&) override
332+ {
333+ return VERSION;
334+ }
335+
336+ virtual void stop() override {}
337+
338+ virtual SearchQueryBase::UPtr search(CannedQuery const&, SearchMetadata const&) override
339+ {
340+ return SearchQueryBase::UPtr(new MyQuery);
341+ }
342+
343+ virtual PreviewQueryBase::UPtr preview(Result const&, ActionMetadata const&) override
344+ {
345+ return nullptr;
346+ }
347+};
348+
349+extern "C"
350+{
351+
352+ EXPORT
353+ unity::scopes::ScopeBase*
354+ // cppcheck-suppress unusedFunction
355+ UNITY_SCOPE_CREATE_FUNCTION()
356+ {
357+ return new MyScope;
358+ }
359+
360+ EXPORT
361+ void
362+ // cppcheck-suppress unusedFunction
363+ UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base)
364+ {
365+ delete scope_base;
366+ }
367+
368+}
369
370=== added file 'demo/click/scope-click/scope-click.ini.in'
371--- demo/click/scope-click/scope-click.ini.in 1970-01-01 00:00:00 +0000
372+++ demo/click/scope-click/scope-click.ini.in 2014-04-08 16:22:25 +0000
373@@ -0,0 +1,9 @@
374+[ScopeConfig]
375+DisplayName = scope-click.DisplayName
376+Description = scope-click.Description
377+Art = scope-click.Art
378+Author = Canonical Ltd.
379+Icon = scope-click.Icon
380+SearchHint = scope-click.SearchHint
381+HotKey = scope-click.HotKey
382+ConfinementType = UntrustedLocal
383
384=== added file 'demo/click/scope-click/scope-click.map'
385--- demo/click/scope-click/scope-click.map 1970-01-01 00:00:00 +0000
386+++ demo/click/scope-click/scope-click.map 2014-04-08 16:22:25 +0000
387@@ -0,0 +1,9 @@
388+{
389+global:
390+ "unity_scope_create";
391+ "unity_scope_destroy";
392+local:
393+ extern "C++" {
394+ *;
395+ };
396+};
397
398=== modified file 'include/unity/scopes/ScopeMetadata.h'
399--- include/unity/scopes/ScopeMetadata.h 2014-04-03 16:46:00 +0000
400+++ include/unity/scopes/ScopeMetadata.h 2014-04-08 16:22:25 +0000
401@@ -27,8 +27,16 @@
402 namespace scopes
403 {
404
405+enum class ConfinementType
406+{
407+ Trusted,
408+ UntrustedLocal,
409+ UntrustedInternet
410+};
411+
412 namespace internal
413 {
414+
415 class ScopeMetadataImpl;
416 } // namespace internal
417
418@@ -71,6 +79,12 @@
419 std::string scope_id() const;
420
421 /**
422+ \brief Get the scope type.
423+ \return The type of the scope.
424+ */
425+ ConfinementType confinement_type() const;
426+
427+ /**
428 \brief Get the proxy object for this scope.
429 \return The scope proxy.
430 */
431
432=== modified file 'include/unity/scopes/internal/RegistryConfig.h'
433--- include/unity/scopes/internal/RegistryConfig.h 2014-01-28 03:12:35 +0000
434+++ include/unity/scopes/internal/RegistryConfig.h 2014-04-08 16:22:25 +0000
435@@ -45,6 +45,7 @@
436 std::string mw_configfile() const;
437 std::string scope_installdir() const; // Directory for Canonical scopes
438 std::string oem_installdir() const; // Directory for OEM scope config files
439+ std::string click_installdir() const; // Directory for Click scope config files
440 std::string scoperunner_path() const; // Path to scoperunner binary
441 std::string ss_registry_identity() const; // Identity of smart scopes registry
442 std::string ss_registry_endpoint() const; // Endpoint of smart scopes registry
443@@ -57,6 +58,7 @@
444 std::string mw_configfile_;
445 std::string scope_installdir_;
446 std::string oem_installdir_;
447+ std::string click_installdir_;
448 std::string scoperunner_path_;
449 std::string ss_registry_identity_;
450 std::string ss_registry_endpoint_;
451
452=== modified file 'include/unity/scopes/internal/ScopeConfig.h'
453--- include/unity/scopes/internal/ScopeConfig.h 2014-03-18 10:25:32 +0000
454+++ include/unity/scopes/internal/ScopeConfig.h 2014-04-08 16:22:25 +0000
455@@ -21,6 +21,7 @@
456
457 #include <unity/scopes/internal/ConfigBase.h>
458 #include <unity/scopes/Variant.h>
459+#include <unity/scopes/ScopeMetadata.h>
460
461 namespace unity
462 {
463@@ -41,6 +42,7 @@
464 ~ScopeConfig();
465
466 bool overrideable() const; // Optional, returns false if not present
467+ ConfinementType confinement_type() const; // Optional, returns Trusted if not present
468 std::string display_name() const;
469 std::string description() const;
470 std::string author() const;
471@@ -54,6 +56,7 @@
472
473 private:
474 bool overrideable_;
475+ ConfinementType confinement_type_;
476 std::string display_name_;
477 std::string description_;
478 std::string author_;
479
480=== modified file 'include/unity/scopes/internal/ScopeMetadataImpl.h'
481--- include/unity/scopes/internal/ScopeMetadataImpl.h 2014-04-02 16:54:53 +0000
482+++ include/unity/scopes/internal/ScopeMetadataImpl.h 2014-04-08 16:22:25 +0000
483@@ -44,6 +44,7 @@
484 ScopeMetadataImpl& operator=(ScopeMetadataImpl&&) = default;
485
486 std::string scope_id() const;
487+ ConfinementType confinement_type() const;
488 ScopeProxy proxy() const;
489 std::string display_name() const; // localized
490 std::string description() const; // localized
491@@ -57,6 +58,7 @@
492 std::string scope_directory() const;
493
494 void set_scope_id(std::string const& scope_id);
495+ void set_confinement_type(ConfinementType scope_type);
496 void set_proxy(ScopeProxy const& proxy);
497 void set_display_name(std::string const& display_name);
498 void set_description(std::string const& description);
499@@ -78,6 +80,7 @@
500
501 MiddlewareBase* mw_;
502 std::string scope_id_;
503+ ConfinementType confinement_type_;
504 ScopeProxy proxy_;
505 std::string display_name_;
506 std::string description_;
507
508=== modified file 'include/unity/scopes/internal/smartscopes/SmartScope.h'
509--- include/unity/scopes/internal/smartscopes/SmartScope.h 2014-03-26 10:01:03 +0000
510+++ include/unity/scopes/internal/smartscopes/SmartScope.h 2014-04-08 16:22:25 +0000
511@@ -48,11 +48,22 @@
512 : scope_id_(scope_id)
513 , query_(query)
514 {
515+ static const std::string no_net_hint("no-internet");
516+ if (hints.contains_hint(no_net_hint))
517+ {
518+ auto var = hints[no_net_hint];
519+ if (var.which() == Variant::Type::Bool && var.get_bool())
520+ {
521+ std::cout << "SmartQuery(): networking disabled for remote scope " << scope_id << ", skipping" << std::endl;
522+ return;
523+ }
524+ }
525+
526 SmartScopesClient::SPtr ss_client = reg->get_ssclient();
527 std::string base_url = reg->get_base_url(scope_id_);
528
529- ///! TODO: session_id, query_id, locale, country
530- search_handle_ = ss_client->search(base_url, query_.query_string(), query.department_id(), "session_id", 0, hints.form_factor(), "", "", hints.cardinality());
531+ ///! TODO: session_id, query_id, country
532+ search_handle_ = ss_client->search(base_url, query_.query_string(), query.department_id(), "session_id", 0, hints.form_factor(), hints.locale(), "", hints.cardinality());
533 }
534
535 ~SmartQuery() noexcept
536@@ -61,11 +72,20 @@
537
538 virtual void cancelled() override
539 {
540- search_handle_->cancel_search();
541+ if (search_handle_ != nullptr)
542+ {
543+ search_handle_->cancel_search();
544+ }
545 }
546
547 virtual void run(SearchReplyProxy const& reply) override
548 {
549+ if (search_handle_ == nullptr)
550+ {
551+ // this can happen if networking is disabled
552+ return;
553+ }
554+
555 std::vector<SearchResult> results = search_handle_->get_search_results();
556 std::map<std::string, Category::SCPtr> categories;
557
558@@ -124,8 +144,8 @@
559 SmartScopesClient::SPtr ss_client = reg->get_ssclient();
560 std::string base_url = reg->get_base_url(scope_id_);
561
562- ///! TODO: session_id, widgets_api_version, locale, country
563- preview_handle_ = ss_client->preview(base_url, result_["result_json"].get_string(), "session_id", hints.form_factor(), 0, "", "");
564+ ///! TODO: session_id, widgets_api_version, country
565+ preview_handle_ = ss_client->preview(base_url, result_["result_json"].get_string(), "session_id", hints.form_factor(), 0, hints.locale(), "");
566 }
567
568 ~SmartPreview()
569
570=== modified file 'scoperegistry/FindFiles.cpp'
571--- scoperegistry/FindFiles.cpp 2014-04-03 12:57:25 +0000
572+++ scoperegistry/FindFiles.cpp 2014-04-08 16:22:25 +0000
573@@ -25,8 +25,11 @@
574 #include <string.h>
575 #include <sys/stat.h>
576
577+#include <boost/filesystem/path.hpp>
578+
579 using namespace std;
580 using namespace unity;
581+using namespace boost;
582
583 namespace scoperegistry
584 {
585@@ -34,17 +37,6 @@
586 namespace
587 {
588
589-bool has_suffix(string const& s, string const& suffix)
590-{
591- auto s_len = s.length();
592- auto suffix_len = suffix.length();
593- if (s_len >= suffix_len)
594- {
595- return s.compare(s_len - suffix_len, suffix_len, suffix) == 0;
596- }
597- return false;
598-}
599-
600 // Return all paths underneath the given dir that are of the given type
601 // or are a symbolic link.
602
603@@ -91,7 +83,7 @@
604
605 } // namespace
606
607-// Return all files of the form dir/<somescope>/<scomescope>.ini that are regular files or
608+// Return all files of the form dir/*/<scomescope>.ini that are regular files or
609 // symbolic links and have the specified suffix.
610 // The empty suffix is legal and causes all regular files and symlinks to be returned.
611
612@@ -102,32 +94,16 @@
613 auto subdirs = find_entries(install_dir, Directory);
614 for (auto subdir : subdirs)
615 {
616- string scope_id = basename(const_cast<char*>(subdir.c_str())); // basename() modifies its argument
617 auto candidates = find_entries(subdir, File);
618 for (auto c : candidates)
619 {
620- string config_name = basename(const_cast<char*>(c.c_str())); // basename() modifies its argument
621- if (config_name == scope_id + suffix)
622- {
623- files.emplace_back(c);
624+ // TODO Check for multiple ini files
625+
626+ filesystem::path path(c);
627+ if (path.extension() != suffix) {
628+ continue;
629 }
630- }
631- }
632-
633- return files;
634-}
635-
636-// Return all files with the given suffix in dir.
637-
638-vector<string> find_files(string const& dir, string const& suffix)
639-{
640- vector<string> files;
641-
642- auto candidates = find_entries(dir, File);
643- for (auto c : candidates)
644- {
645- if (has_suffix(c, suffix))
646- {
647+
648 files.emplace_back(c);
649 }
650 }
651
652=== modified file 'scoperegistry/scoperegistry.cpp'
653--- scoperegistry/scoperegistry.cpp 2014-04-03 16:46:00 +0000
654+++ scoperegistry/scoperegistry.cpp 2014-04-08 16:22:25 +0000
655@@ -39,12 +39,15 @@
656 #include <libgen.h>
657 #include <unistd.h>
658
659+#include <boost/filesystem/path.hpp>
660+
661 using namespace scoperegistry;
662 using namespace std;
663 using namespace unity;
664 using namespace unity::scopes;
665 using namespace unity::scopes::internal;
666 using namespace unity::util;
667+using namespace boost;
668
669 char const* prog_name;
670
671@@ -57,30 +60,68 @@
672 cerr << prog_name << ": " << msg << endl;
673 }
674
675-string strip_suffix(string const& s, string const& suffix)
676-{
677- auto s_len = s.length();
678- auto suffix_len = suffix.length();
679- if (s_len >= suffix_len)
680- {
681- if (s.compare(s_len - suffix_len, suffix_len, suffix) == 0)
682- {
683- return string(s, 0, s_len - suffix_len);
684- }
685- }
686- return s;
687-}
688-
689 // if path is an absolute path, just return it. otherwise, append it to scopedir.
690-string relative_scope_path_to_abs_path(string const& path, string const& scopedir)
691+filesystem::path relative_scope_path_to_abs_path(filesystem::path const& path, filesystem::path const& scopedir)
692 {
693- if (path.size() > 0 && path[0] != '/')
694+ if (path.is_relative())
695 {
696- return scopedir + "/" + path;
697+ return scopedir / path;
698 }
699 return path;
700 }
701
702+// throwing an exception without joining with a thread is a bad, bad thing to do, so let's RAII to avoid doing it
703+struct SignalThreadWrapper
704+{
705+ std::shared_ptr<core::posix::SignalTrap> termination_trap;
706+ std::shared_ptr<core::posix::SignalTrap> child_trap;
707+ std::unique_ptr<core::posix::ChildProcess::DeathObserver> death_observer;
708+ std::thread termination_trap_worker;
709+ std::thread child_trap_worker;
710+
711+ SignalThreadWrapper() :
712+ // We shutdown the runtime whenever these signals happen.
713+ termination_trap(core::posix::trap_signals_for_all_subsequent_threads(
714+ {
715+ core::posix::Signal::sig_int,
716+ core::posix::Signal::sig_hup,
717+ core::posix::Signal::sig_term
718+ })),
719+ // And we maintain our list of processes with the help of sig_chld.
720+ child_trap(core::posix::trap_signals_for_all_subsequent_threads(
721+ {
722+ core::posix::Signal::sig_chld
723+ })),
724+ // The death observer is required to make sure that we reap all child processes
725+ // whenever multiple sigchld's are compressed together.
726+ death_observer(core::posix::ChildProcess::DeathObserver::create_once_with_signal_trap(child_trap)),
727+ // Starting up both traps.
728+ termination_trap_worker([&]() { termination_trap->run(); }),
729+ child_trap_worker([&]() { child_trap->run(); })
730+ {
731+ }
732+
733+ core::Signal<core::posix::Signal>& signal_raised()
734+ {
735+ return termination_trap->signal_raised();
736+ }
737+
738+ ~SignalThreadWrapper()
739+ {
740+ // Stop termination_trap
741+ termination_trap->stop();
742+ if (termination_trap_worker.joinable())
743+ termination_trap_worker.join();
744+
745+ // Please note that the child_trap must only be stopped once the
746+ // termination_trap thread has been joined. We otherwise will encounter
747+ // a race between the middleware shutting down and not receiving sigchld anymore.
748+ child_trap->stop();
749+ if (child_trap_worker.joinable())
750+ child_trap_worker.join();
751+ }
752+};
753+
754 // Return a map of <scope, config_file> pairs for all scopes (Canonical and OEM scopes).
755 // If a Canonical scope is overrideable and the OEM has configured a scope with the
756 // same id, the OEM scope overrides the Canonical one.
757@@ -98,8 +139,8 @@
758 auto config_files = find_scope_config_files(scope_installdir, ".ini");
759 for (auto&& path : config_files)
760 {
761- string file_name = basename(const_cast<char*>(string(path).c_str())); // basename() modifies its argument
762- string scope_id = strip_suffix(file_name, ".ini");
763+ filesystem::path p(path);
764+ string scope_id = p.stem().native();
765 try
766 {
767 ScopeConfig config(path);
768@@ -125,8 +166,9 @@
769 auto oem_paths = find_scope_config_files(oem_installdir, ".ini");
770 for (auto&& path : oem_paths)
771 {
772- string file_name = basename(const_cast<char*>(string(path).c_str())); // basename() modifies its argument
773- string scope_id = strip_suffix(file_name, ".ini");
774+ filesystem::path p(path);
775+ string file_name = p.filename().native();
776+ string scope_id = p.stem().native();
777 if (fixed_scopes.find(scope_id) == fixed_scopes.end())
778 {
779 overrideable_scopes[scope_id] = path; // Replaces scope if it was present already
780@@ -149,6 +191,40 @@
781 return fixed_scopes;
782 }
783
784+map<string, string> find_click_scopes(map<string, string> const& local_scopes, string const& click_installdir)
785+{
786+ map<string, string> click_scopes;
787+
788+ if (!click_installdir.empty())
789+ {
790+ try
791+ {
792+ auto click_paths = find_scope_config_files(click_installdir, ".ini");
793+ for (auto&& path : click_paths)
794+ {
795+ filesystem::path p(path);
796+ string file_name = p.filename().native();
797+ string scope_id = p.stem().native();
798+ if (local_scopes.find(scope_id) == local_scopes.end())
799+ {
800+ click_scopes[scope_id] = path;
801+ }
802+ else
803+ {
804+ error("ignoring non-overrideable scope config \"" + file_name + "\" in click directory " + click_installdir);
805+ }
806+ }
807+ }
808+ catch (ResourceException const& e)
809+ {
810+ error(e.what());
811+ error("could not open Click installation directory, ignoring Click scopes");
812+ }
813+ }
814+
815+ return click_scopes;
816+}
817+
818 // For each scope, open the config file for the scope, create the metadata info from the config,
819 // and add an entry to the RegistryObject.
820
821@@ -156,18 +232,19 @@
822 map<string, string> const& all_scopes,
823 MiddlewareBase::SPtr const& mw,
824 string const& scoperunner_path,
825- string const& config_file)
826+ string const& config_file,
827+ bool click)
828 {
829 for (auto&& pair : all_scopes)
830 {
831 try
832 {
833 unique_ptr<ScopeMetadataImpl> mi(new ScopeMetadataImpl(mw.get()));
834- ScopeConfig sc(pair.second);
835+ string scope_config(pair.second);
836+ ScopeConfig sc(scope_config);
837
838- // dirname modifies its argument, so we need a copy of scope ini path.
839- std::vector<char> scope_ini(pair.second.c_str(), pair.second.c_str() + pair.second.size() + 1);
840- const std::string scope_dir(dirname(&scope_ini[0]));
841+ filesystem::path scope_path(scope_config);
842+ filesystem::path scope_dir(scope_path.parent_path());
843
844 mi->set_scope_id(pair.first);
845 mi->set_display_name(sc.display_name());
846@@ -175,17 +252,24 @@
847 mi->set_author(sc.author());
848 mi->set_invisible(sc.invisible());
849 mi->set_appearance_attributes(sc.appearance_attributes());
850- mi->set_scope_directory(scope_dir);
851+ mi->set_scope_directory(scope_dir.native());
852+
853+ if (click && (sc.confinement_type() == ConfinementType::Trusted))
854+ {
855+ throw unity::InvalidArgumentException("Invalid type, Trusted for click scope: " + pair.first);
856+ }
857+ mi->set_confinement_type(sc.confinement_type());
858+
859 try
860 {
861- mi->set_art(relative_scope_path_to_abs_path(sc.art(), scope_dir));
862+ mi->set_art(relative_scope_path_to_abs_path(sc.art(), scope_dir).native());
863 }
864 catch (NotFoundException const&)
865 {
866 }
867 try
868 {
869- mi->set_icon(relative_scope_path_to_abs_path(sc.icon(), scope_dir));
870+ mi->set_icon(relative_scope_path_to_abs_path(sc.icon(), scope_dir).native());
871 }
872 catch (NotFoundException const&)
873 {
874@@ -220,7 +304,7 @@
875 {
876 throw unity::InvalidArgumentException("Invalid scope runner executable for scope: " + pair.first);
877 }
878- exec_data.scoperunner_path = relative_scope_path_to_abs_path(custom_exec, scope_dir);
879+ exec_data.scoperunner_path = relative_scope_path_to_abs_path(custom_exec, scope_dir).native();
880 }
881 catch (NotFoundException const&)
882 {
883@@ -278,29 +362,7 @@
884
885 try
886 {
887- // We shutdown the runtime whenever these signals happen.
888- auto termination_trap = core::posix::trap_signals_for_all_subsequent_threads(
889- {
890- core::posix::Signal::sig_int,
891- core::posix::Signal::sig_hup,
892- core::posix::Signal::sig_term
893- });
894-
895- // And we maintain our list of processes with the help of sig_chld.
896- auto child_trap = core::posix::trap_signals_for_all_subsequent_threads(
897- {
898- core::posix::Signal::sig_chld
899- });
900-
901- // The death observer is required to make sure that we reap all child processes
902- // whenever multiple sigchld's are compressed together.
903- auto death_observer =
904- core::posix::ChildProcess::DeathObserver::create_once_with_signal_trap(
905- child_trap);
906-
907- // Starting up both traps.
908- std::thread termination_trap_worker([termination_trap]() { termination_trap->run(); });
909- std::thread child_trap_worker([child_trap]() { child_trap->run(); });
910+ SignalThreadWrapper signal_handler_wrapper;
911
912 // And finally creating our runtime.
913 RuntimeConfig rt_config(config_file);
914@@ -315,6 +377,7 @@
915 string mw_configfile;
916 string scope_installdir;
917 string oem_installdir;
918+ string click_installdir;
919 string scoperunner_path;
920 string ss_reg_id;
921 string ss_reg_endpoint;
922@@ -325,6 +388,7 @@
923 mw_configfile = c.mw_configfile();
924 scope_installdir = c.scope_installdir();
925 oem_installdir = c.oem_installdir();
926+ click_installdir = c.click_installdir();
927 scoperunner_path = c.scoperunner_path();
928 ss_reg_id = c.ss_registry_identity();
929 ss_reg_endpoint = c.ss_registry_endpoint();
930@@ -334,7 +398,7 @@
931
932 // Inform the signal thread that it should shutdown the middleware
933 // if we get a termination signal.
934- termination_trap->signal_raised().connect([middleware](core::posix::Signal signal)
935+ signal_handler_wrapper.signal_raised().connect([middleware](core::posix::Signal signal)
936 {
937 switch(signal)
938 {
939@@ -349,25 +413,28 @@
940 });
941
942 // The registry object stores the local and remote scopes
943- RegistryObject::SPtr registry(new RegistryObject(*death_observer));
944+ RegistryObject::SPtr registry(new RegistryObject(*signal_handler_wrapper.death_observer));
945
946 // Add the metadata for each scope to the lookup table.
947 // We do this before starting any of the scopes, so aggregating scopes don't get a lookup failure if
948 // they look for another scope in the registry.
949
950 auto local_scopes = find_local_scopes(scope_installdir, oem_installdir);
951+ auto click_scopes = find_click_scopes(local_scopes, click_installdir);
952
953 // Before we add the local scopes, we check whether any scopes were explicitly specified
954 // on the command line. If so, scopes on the command line override scopes in
955 // configuration files.
956 for (auto i = 2; i < argc; ++i)
957 {
958- string file_name = basename(const_cast<char*>(string(argv[i]).c_str())); // basename() modifies its argument
959- string scope_id = strip_suffix(file_name, ".ini");
960+ filesystem::path path(argv[i]);
961+ string scope_id = path.stem().native();
962 local_scopes[scope_id] = argv[i]; // operator[] overwrites pre-existing entries
963 }
964
965- add_local_scopes(registry, local_scopes, middleware, scoperunner_path, runtime->configfile());
966+ add_local_scopes(registry, local_scopes, middleware, scoperunner_path, runtime->configfile(), false);
967+ add_local_scopes(registry, click_scopes, middleware, scoperunner_path, runtime->configfile(), true);
968+ local_scopes.insert(click_scopes.begin(), click_scopes.end());
969 if (ss_reg_id.empty() || ss_reg_endpoint.empty())
970 {
971 error("no remote registry configured, only local scopes will be available");
972@@ -415,18 +482,6 @@
973 // Wait until we are done, which happens if we receive a termination signal.
974 middleware->wait_for_shutdown();
975
976- // Stop termination_trap
977- termination_trap->stop();
978- if (termination_trap_worker.joinable())
979- termination_trap_worker.join();
980-
981- // Please note that the child_trap must only be stopped once the
982- // termination_trap thread has been joined. We otherwise will encounter
983- // a race between the middleware shutting down and not receiving sigchld anymore.
984- child_trap->stop();
985- if (child_trap_worker.joinable())
986- child_trap_worker.join();
987-
988 exit_status = 0;
989 }
990 catch (std::exception const& e)
991
992=== modified file 'scoperunner/scoperunner.cpp'
993--- scoperunner/scoperunner.cpp 2014-04-03 14:49:30 +0000
994+++ scoperunner/scoperunner.cpp 2014-04-08 16:22:25 +0000
995@@ -21,6 +21,7 @@
996 #include <unity/scopes/internal/RegistryConfig.h>
997 #include <unity/scopes/internal/RuntimeConfig.h>
998 #include <unity/scopes/internal/RuntimeImpl.h>
999+#include <unity/scopes/internal/ScopeConfig.h>
1000 #include <unity/scopes/internal/ScopeLoader.h>
1001 #include <unity/scopes/internal/ScopeObject.h>
1002 #include <unity/scopes/internal/ThreadSafeQueue.h>
1003@@ -32,15 +33,21 @@
1004 #include <cassert>
1005 #include <future>
1006 #include <iostream>
1007+#include <sstream>
1008 #include <string>
1009 #include <unordered_map>
1010 #include <vector>
1011
1012 #include <libgen.h>
1013
1014+#include <boost/filesystem/path.hpp>
1015+
1016+#include <sys/apparmor.h>
1017+
1018 using namespace std;
1019 using namespace unity::scopes;
1020 using namespace unity::scopes::internal;
1021+using namespace boost;
1022
1023 namespace
1024 {
1025@@ -53,66 +60,66 @@
1026 cerr << prog_name << ": " << msg << endl;
1027 }
1028
1029-bool has_suffix(string const& s, string const& suffix)
1030-{
1031- auto s_len = s.length();
1032- auto suffix_len = suffix.length();
1033- if (s_len >= suffix_len)
1034- {
1035- return s.compare(s_len - suffix_len, suffix_len, suffix) == 0;
1036- }
1037- return false;
1038-}
1039-
1040-string strip_suffix(string const& s, string const& suffix)
1041-{
1042- auto s_len = s.length();
1043- auto suffix_len = suffix.length();
1044- if (s_len >= suffix_len)
1045- {
1046- if (s.compare(s_len - suffix_len, suffix_len, suffix) == 0)
1047- {
1048- return string(s, 0, s_len - suffix_len);
1049- }
1050- }
1051- return s;
1052-}
1053-
1054-// One thread for each scope, plus a future that the thread sets when it finishes.
1055-
1056-struct ThreadFuture
1057-{
1058- thread t;
1059- std::future<void> f;
1060-};
1061-
1062-// Each thread provides its own ID on a queue when it finishes. That allows us to
1063-// then locate the thread in the map. The promise is set by the thread so we can
1064-// find out what happened to it and join with it. Unfortunately, we have to jump
1065-// through these hoops because there is no way to wait on multiple futures in C++ 11.
1066-
1067-unordered_map<thread::id, ThreadFuture> threads;
1068-
1069-ThreadSafeQueue<thread::id> finished_threads;
1070-
1071-// Scope thread start function.
1072-
1073-void scope_thread(std::shared_ptr<core::posix::SignalTrap> trap,
1074- MWStateReceiverProxy reg_state_receiver,
1075- string const& mw_kind,
1076- string const& mw_config,
1077- string const& runtime_config,
1078- string const& scope_id,
1079- string const& lib_dir,
1080- promise<void> finished_promise)
1081-{
1082+// Run the scope specified by the config_file in a separate thread and wait for the thread to finish.
1083+// Return exit status for main to use.
1084+
1085+int run_scope(filesystem::path const& runtime_config, filesystem::path const& scope_config)
1086+{
1087+ auto trap = core::posix::trap_signals_for_all_subsequent_threads(
1088+ {
1089+ core::posix::Signal::sig_hup,
1090+ core::posix::Signal::sig_term
1091+ });
1092+
1093+ std::thread trap_worker([trap]() { trap->run(); });
1094+
1095+ // Retrieve the registry middleware and create a proxy to its state receiver
1096+ RuntimeConfig rt_config(runtime_config.native());
1097+ RegistryConfig reg_conf(rt_config.registry_identity(), rt_config.registry_configfile());
1098+ auto reg_runtime = RuntimeImpl::create(rt_config.registry_identity(), runtime_config.native());
1099+ auto reg_mw = reg_runtime->factory()->find(reg_runtime->registry_identity(), reg_conf.mw_kind());
1100+ auto reg_state_receiver = reg_mw->create_state_receiver_proxy("StateReceiver");
1101+
1102+ string lib_dir = scope_config.parent_path().native();
1103+ string scope_id = scope_config.stem().native();
1104+
1105+ int exit_status = 1;
1106 try
1107 {
1108 // Instantiate the run time, create the middleware, load the scope from its
1109 // shared library, and call the scope's start() method.
1110- auto rt = RuntimeImpl::create(scope_id, runtime_config);
1111- auto mw = rt->factory()->create(scope_id, mw_kind, mw_config);
1112- ScopeLoader::SPtr loader = ScopeLoader::load(scope_id, lib_dir + "lib" + scope_id + ".so", rt->registry());
1113+ auto rt = RuntimeImpl::create(scope_id, runtime_config.native());
1114+ auto mw = rt->factory()->create(scope_id, reg_conf.mw_kind(), reg_conf.mw_configfile());
1115+
1116+ ScopeConfig sc(scope_config.c_str());
1117+
1118+ // Drop our privileges
1119+ string profile;
1120+ switch (sc.confinement_type())
1121+ {
1122+ case ConfinementType::Trusted:
1123+ break;
1124+ case ConfinementType::UntrustedLocal:
1125+ profile = "unity-scope-local";
1126+ break;
1127+ case ConfinementType::UntrustedInternet:
1128+ profile = "unity-scope-internet";
1129+ break;
1130+ }
1131+
1132+ if (!profile.empty())
1133+ {
1134+ int profile_change_code = aa_change_profile(profile.c_str());
1135+ if (profile_change_code != 0)
1136+ {
1137+ ostringstream message;
1138+ message << "Couldn't change to AppArmor profile [" << profile
1139+ << "] error = [" << profile_change_code << "]";
1140+ throw ConfigException(message.str());
1141+ }
1142+ }
1143+
1144+ ScopeLoader::SPtr loader = ScopeLoader::load(scope_id, lib_dir + "/lib" + scope_id + ".so", rt->registry());
1145 loader->start();
1146
1147 // Give a thread to the scope to do with as it likes. If the scope doesn't want to use it and
1148@@ -141,82 +148,15 @@
1149 // destructor will still call stop() on the scope.
1150 run_future.get();
1151
1152- finished_promise.set_value();
1153+ exit_status = 0;
1154+ }
1155+ catch (std::exception const& e)
1156+ {
1157+ error(e.what());
1158 }
1159 catch (...)
1160 {
1161- finished_promise.set_exception(current_exception());
1162- }
1163-
1164- finished_threads.push(this_thread::get_id());
1165-}
1166-
1167-// Run each of the scopes in config_files in a separate thread and wait for each thread to finish.
1168-// Return the number of threads that did not terminate normally.
1169-
1170-int run_scopes(string const& runtime_config, vector<string> config_files)
1171-{
1172- auto trap = core::posix::trap_signals_for_all_subsequent_threads(
1173- {
1174- core::posix::Signal::sig_hup,
1175- core::posix::Signal::sig_term
1176- });
1177-
1178- std::thread trap_worker([trap]() { trap->run(); });
1179-
1180- // Retrieve the registry middleware and create a proxy to its state receiver
1181- RuntimeConfig rt_config(runtime_config);
1182- RegistryConfig reg_conf(rt_config.registry_identity(), rt_config.registry_configfile());
1183- auto reg_runtime = RuntimeImpl::create(rt_config.registry_identity(), runtime_config);
1184- auto reg_mw = reg_runtime->factory()->find(reg_runtime->registry_identity(), reg_conf.mw_kind());
1185- auto reg_state_receiver = reg_mw->create_state_receiver_proxy("StateReceiver");
1186-
1187- for (auto file : config_files)
1188- {
1189- string file_name = basename(const_cast<char*>(string(file).c_str())); // basename() modifies its argument
1190- auto dir_len = file.size() - file_name.size();
1191- string dir = file.substr(0, dir_len);
1192- if (*dir.rbegin() != '/')
1193- {
1194- dir += "/";
1195- }
1196- string scope_id = strip_suffix(file_name, ".ini");
1197-
1198- // For each scope, create a thread that loads the scope and initializes it.
1199- // Each thread gets a promise to indicate when it is finished. When a thread
1200- // completes, it fulfils the promise, and pushes its ID onto the finished queue.
1201- // We collect exit status from the thread via the future from each promise.
1202- promise<void> p;
1203- auto f = p.get_future();
1204- thread t(scope_thread, trap, reg_state_receiver, reg_conf.mw_kind(), reg_conf.mw_configfile(),
1205- runtime_config, scope_id, dir, move(p));
1206-
1207- auto id = t.get_id();
1208- threads[id] = ThreadFuture { move(t), move(f) };
1209- }
1210-
1211- // Now wait for the threads to finish (in any order).
1212- int num_errors = 0;
1213- for (int i = threads.size(); i > 0; --i)
1214- {
1215- try
1216- {
1217- auto id = finished_threads.wait_and_pop();
1218- auto it = threads.find(id);
1219- assert(it != threads.end());
1220- it->second.t.join();
1221- it->second.f.get(); // This will throw if the thread terminated due to an exception
1222- }
1223- catch (std::exception const& e)
1224- {
1225- error(e.what());
1226- ++num_errors;
1227- }
1228- catch (...)
1229- {
1230- error("unknown exception");
1231- ++num_errors;
1232- }
1233+ error("unknown exception");
1234 }
1235
1236 trap->stop();
1237@@ -224,7 +164,7 @@
1238 if (trap_worker.joinable())
1239 trap_worker.join();
1240
1241- return num_errors;
1242+ return exit_status;
1243 }
1244
1245 } // namespace
1246@@ -240,27 +180,30 @@
1247 ::pthread_sigmask(SIG_SETMASK, &set, nullptr);
1248
1249 prog_name = basename(argv[0]);
1250- if (argc < 3)
1251+ if (argc != 3)
1252 {
1253- cerr << "usage: " << prog_name << " runtime.ini configfile.ini [configfile.ini ...]" << endl;
1254+ cerr << "usage: " << prog_name << " runtime.ini configfile.ini" << endl;
1255 return 2;
1256 }
1257 char const* const runtime_config = argv[1];
1258+ char const* const scope_config = argv[2];
1259
1260 int exit_status = 1;
1261 try
1262 {
1263- vector<string> config_files;
1264- for (int i = 2; i < argc; ++i)
1265- {
1266- if (!has_suffix(argv[i], ".ini"))
1267- {
1268- throw ConfigException(string("invalid config file name: \"") + argv[i] + "\": missing .ini extension");
1269- }
1270- config_files.push_back(argv[i]);
1271- }
1272-
1273- exit_status = run_scopes(runtime_config, config_files);
1274+ filesystem::path runtime_path(runtime_config);
1275+ if (runtime_path.extension() != ".ini")
1276+ {
1277+ throw ConfigException(string("invalid runtime config file name: \"") + runtime_config + "\": missing .ini extension");
1278+ }
1279+
1280+ filesystem::path scope_path(scope_config);
1281+ if (scope_path.extension() != ".ini")
1282+ {
1283+ throw ConfigException(string("invalid scope config file name: \"") + scope_config + "\": missing .ini extension");
1284+ }
1285+
1286+ exit_status = run_scope(runtime_path, scope_path);
1287 }
1288 catch (std::exception const& e)
1289 {
1290
1291=== modified file 'src/scopes/ScopeMetadata.cpp'
1292--- src/scopes/ScopeMetadata.cpp 2014-04-02 16:54:53 +0000
1293+++ src/scopes/ScopeMetadata.cpp 2014-04-08 16:22:25 +0000
1294@@ -72,6 +72,11 @@
1295 return p->scope_id();
1296 }
1297
1298+ConfinementType ScopeMetadata::confinement_type() const
1299+{
1300+ return p->confinement_type();
1301+}
1302+
1303 ScopeProxy ScopeMetadata::proxy() const
1304 {
1305 return p->proxy();
1306
1307=== modified file 'src/scopes/internal/RegistryConfig.cpp'
1308--- src/scopes/internal/RegistryConfig.cpp 2014-01-28 03:12:35 +0000
1309+++ src/scopes/internal/RegistryConfig.cpp 2014-04-08 16:22:25 +0000
1310@@ -48,6 +48,11 @@
1311 mw_configfile_ = get_string(REGISTRY_CONFIG_GROUP, mw_kind_ + ".ConfigFile");
1312 scope_installdir_ = get_string(REGISTRY_CONFIG_GROUP, "Scope.InstallDir");
1313 oem_installdir_ = get_optional_string(REGISTRY_CONFIG_GROUP, "OEM.InstallDir");
1314+ click_installdir_ = get_optional_string(REGISTRY_CONFIG_GROUP, "Click.InstallDir");
1315+ if (click_installdir_.empty())
1316+ {
1317+ click_installdir_ = string(getenv("HOME")) + "/.local/share/unity-scopes/";
1318+ }
1319 scoperunner_path_ = get_string(REGISTRY_CONFIG_GROUP, "Scoperunner.Path");
1320 if (scoperunner_path_[0] != '/')
1321 {
1322@@ -96,6 +101,11 @@
1323 return oem_installdir_;
1324 }
1325
1326+string RegistryConfig::click_installdir() const
1327+{
1328+ return click_installdir_;
1329+}
1330+
1331 string RegistryConfig::scoperunner_path() const
1332 {
1333 return scoperunner_path_;
1334
1335=== modified file 'src/scopes/internal/ScopeConfig.cpp'
1336--- src/scopes/internal/ScopeConfig.cpp 2014-03-31 16:05:42 +0000
1337+++ src/scopes/internal/ScopeConfig.cpp 2014-04-08 16:22:25 +0000
1338@@ -39,6 +39,7 @@
1339 {
1340 const string overrideable_str = "Override";
1341 const string scope_id_str = "DisplayName";
1342+ const string scope_confinement_type_str = "ConfinementType";
1343 const string description_str = "Description";
1344 const string author_str = "Author";
1345 const string art_str = "Art";
1346@@ -47,6 +48,10 @@
1347 const string hot_key_str = "HotKey";
1348 const string invisible_str = "Invisible";
1349 const string scope_runner_exec = "ScopeRunner";
1350+
1351+ const string scope_confinement_type_trusted_str = "Trusted";
1352+ const string scope_confinement_type_untrusted_local_str = "UntrustedLocal";
1353+ const string scope_confinement_type_untrusted_internet_str = "UntrustedInternet";
1354 }
1355
1356 ScopeConfig::ScopeConfig(string const& configfile) :
1357@@ -60,6 +65,28 @@
1358 {
1359 overrideable_ = false;
1360 }
1361+
1362+ confinement_type_ = ConfinementType::Trusted;
1363+ try
1364+ {
1365+ string confinement_type = parser()->get_string(SCOPE_CONFIG_GROUP, scope_confinement_type_str);
1366+ if (confinement_type == scope_confinement_type_trusted_str)
1367+ {
1368+ confinement_type_ = ConfinementType::Trusted;
1369+ }
1370+ else if (confinement_type == scope_confinement_type_untrusted_local_str)
1371+ {
1372+ confinement_type_ = ConfinementType::UntrustedLocal;
1373+ }
1374+ else if (confinement_type == scope_confinement_type_untrusted_internet_str)
1375+ {
1376+ confinement_type_ = ConfinementType::UntrustedInternet;
1377+ }
1378+ }
1379+ catch (LogicException const& e)
1380+ {
1381+ }
1382+
1383 display_name_ = parser()->get_string(SCOPE_CONFIG_GROUP, scope_id_str);
1384 description_ = parser()->get_string(SCOPE_CONFIG_GROUP, description_str);
1385 author_ = parser()->get_string(SCOPE_CONFIG_GROUP, author_str);
1386@@ -141,6 +168,11 @@
1387 return overrideable_;
1388 }
1389
1390+ConfinementType ScopeConfig::confinement_type() const
1391+{
1392+ return confinement_type_;
1393+}
1394+
1395 string ScopeConfig::display_name() const
1396 {
1397 return display_name_;
1398
1399=== modified file 'src/scopes/internal/ScopeMetadataImpl.cpp'
1400--- src/scopes/internal/ScopeMetadataImpl.cpp 2014-04-02 17:05:14 +0000
1401+++ src/scopes/internal/ScopeMetadataImpl.cpp 2014-04-08 16:22:25 +0000
1402@@ -36,7 +36,7 @@
1403 {
1404
1405 ScopeMetadataImpl::ScopeMetadataImpl(MiddlewareBase* mw) :
1406- mw_(mw)
1407+ mw_(mw), confinement_type_(ConfinementType::Trusted)
1408 {
1409 }
1410
1411@@ -49,6 +49,7 @@
1412 ScopeMetadataImpl::ScopeMetadataImpl(ScopeMetadataImpl const& other) :
1413 mw_(other.mw_),
1414 scope_id_(other.scope_id_),
1415+ confinement_type_(other.confinement_type_),
1416 proxy_(other.proxy_),
1417 display_name_(other.display_name_),
1418 description_(other.description_),
1419@@ -87,6 +88,7 @@
1420 {
1421 mw_ = rhs.mw_;
1422 scope_id_ = rhs.scope_id_;
1423+ confinement_type_ = rhs.confinement_type_;
1424 proxy_ = rhs.proxy_;
1425 display_name_ = rhs.display_name_;
1426 description_ = rhs.description_;
1427@@ -107,6 +109,11 @@
1428 return scope_id_;
1429 }
1430
1431+ConfinementType ScopeMetadataImpl::confinement_type() const
1432+{
1433+ return confinement_type_;
1434+}
1435+
1436 ScopeProxy ScopeMetadataImpl::proxy() const
1437 {
1438 return proxy_;
1439@@ -191,6 +198,11 @@
1440 scope_id_ = scope_id;
1441 }
1442
1443+void ScopeMetadataImpl::set_confinement_type(ConfinementType confinement_type)
1444+{
1445+ confinement_type_ = confinement_type;
1446+}
1447+
1448 void ScopeMetadataImpl::set_proxy(ScopeProxy const& proxy)
1449 {
1450 proxy_ = proxy;
1451@@ -272,6 +284,7 @@
1452
1453 VariantMap var;
1454 var["scope_id"] = scope_id_;
1455+ var["confinement_type"] = (int) confinement_type_;
1456 VariantMap proxy;
1457 proxy["identity"] = proxy_->identity();
1458 proxy["endpoint"] = proxy_->endpoint();
1459@@ -364,6 +377,9 @@
1460
1461 // Optional fields
1462
1463+ it = var.find("confinement_type");
1464+ confinement_type_ = (ConfinementType) it->second.get_int();
1465+
1466 it = var.find("art");
1467 if (it != var.end())
1468 {
1469
1470=== modified file 'test/gtest/scopes/Registry/Registry_test.cpp'
1471--- test/gtest/scopes/Registry/Registry_test.cpp 2014-04-02 16:54:53 +0000
1472+++ test/gtest/scopes/Registry/Registry_test.cpp 2014-04-08 16:22:25 +0000
1473@@ -21,6 +21,9 @@
1474 #include <unity/scopes/SearchMetadata.h>
1475 #include <unity/scopes/SearchListenerBase.h>
1476 #include <unity/scopes/CategorisedResult.h>
1477+#include <boost/filesystem.hpp>
1478+#include <boost/system/error_code.hpp>
1479+#include <boost/filesystem/operations.hpp>
1480 #include <functional>
1481 #include <gtest/gtest.h>
1482 #include <signal.h>
1483@@ -86,6 +89,23 @@
1484 }
1485 }
1486
1487+bool wait_for_registry()
1488+{
1489+ const int num_retries = 10;
1490+ const boost::filesystem::path path("/tmp/RegistryTest");
1491+ for (int i = 0; i<num_retries; i++)
1492+ {
1493+ if (boost::filesystem::exists(path))
1494+ {
1495+ boost::system::error_code error;
1496+ auto st = boost::filesystem::status(path, error).type();
1497+ return st == boost::filesystem::file_type::socket_file;
1498+ }
1499+ sleep(1);
1500+ }
1501+ return false;
1502+}
1503+
1504 int main(int argc, char **argv)
1505 {
1506 ::testing::InitGoogleTest(&argc, argv);
1507@@ -102,6 +122,8 @@
1508 }
1509 else if (rpid > 0)
1510 {
1511+ // FIXME: remove this once we have async queries and can set arbitrary timeout when calling registry
1512+ EXPECT_TRUE(wait_for_registry());
1513 auto rc = RUN_ALL_TESTS();
1514 kill(rpid, SIGTERM);
1515 return rc;
1516
1517=== modified file 'test/gtest/scopes/internal/ScopeMetadataImpl/ScopeMetadataImpl_test.cpp'
1518--- test/gtest/scopes/internal/ScopeMetadataImpl/ScopeMetadataImpl_test.cpp 2014-04-03 16:46:00 +0000
1519+++ test/gtest/scopes/internal/ScopeMetadataImpl/ScopeMetadataImpl_test.cpp 2014-04-08 16:22:25 +0000
1520@@ -234,6 +234,7 @@
1521
1522 unique_ptr<ScopeMetadataImpl> mi(new ScopeMetadataImpl(&mw));
1523 mi->set_scope_id("scope_id");
1524+ mi->set_confinement_type(ConfinementType::UntrustedLocal);
1525 auto mw_proxy = mw.create_scope_proxy("identity", "endpoint");
1526 mi->set_proxy(ScopeImpl::create(mw_proxy, mw.runtime(), "scope_id"));
1527 mi->set_display_name("display_name");
1528@@ -249,8 +250,9 @@
1529 // Check that serialize() sets the map values correctly
1530 auto m = ScopeMetadataImpl::create(move(mi));
1531 auto var = m.serialize();
1532- EXPECT_EQ(11u, var.size());
1533+ EXPECT_EQ(12u, var.size());
1534 EXPECT_EQ("scope_id", var["scope_id"].get_string());
1535+ EXPECT_EQ(ConfinementType::UntrustedLocal, (ConfinementType) var["confinement_type"].get_int());
1536 EXPECT_EQ("display_name", var["display_name"].get_string());
1537 EXPECT_EQ("description", var["description"].get_string());
1538 EXPECT_EQ("author", var["author"].get_string());
1539@@ -264,6 +266,7 @@
1540 // Make another instance from the VariantMap and check its fields
1541 ScopeMetadataImpl c(var, &mw);
1542 EXPECT_EQ("scope_id", c.scope_id());
1543+ EXPECT_EQ(ConfinementType::UntrustedLocal, c.confinement_type());
1544 EXPECT_EQ("identity", c.proxy()->identity());
1545 EXPECT_EQ("endpoint", c.proxy()->endpoint());
1546 EXPECT_EQ("display_name", c.display_name());
1547@@ -448,6 +451,7 @@
1548 m["author"] = "author";
1549
1550 // Optional attributes
1551+ m["confinement_type"] = (int) ConfinementType::UntrustedLocal;
1552 m["art"] = "art";
1553 m["icon"] = "icon";
1554 m["search_hint"] = "search_hint";
1555
1556=== modified file 'test/whitespace/CMakeLists.txt'
1557--- test/whitespace/CMakeLists.txt 2013-05-29 04:57:50 +0000
1558+++ test/whitespace/CMakeLists.txt 2014-04-08 16:22:25 +0000
1559@@ -2,4 +2,8 @@
1560 # Test that all source files, cmakefiles, etc. do not contain trailing whitespace.
1561 #
1562
1563-add_test(whitespace ${CMAKE_CURRENT_SOURCE_DIR}/check_whitespace.py ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR})
1564+add_test(whitespace
1565+ ${CMAKE_CURRENT_SOURCE_DIR}/check_whitespace.py
1566+ ${CMAKE_SOURCE_DIR}
1567+ ${CMAKE_BINARY_DIR}
1568+)
1569
1570=== modified file 'test/whitespace/check_whitespace.py'
1571--- test/whitespace/check_whitespace.py 2013-06-27 08:38:02 +0000
1572+++ test/whitespace/check_whitespace.py 2014-04-08 16:22:25 +0000
1573@@ -80,7 +80,7 @@
1574
1575 parser = argparse.ArgumentParser(description = 'Test that source files do not contain trailing whitespace.')
1576 parser.add_argument('dir', nargs = 1, help = 'The directory to (recursively) search for source files')
1577-parser.add_argument('ignore_prefix', nargs = '?', default=None,
1578+parser.add_argument('ignore_prefix', nargs = '+', default=None,
1579 help = 'Ignore source files with a path that starts with the given prefix.')
1580 args = parser.parse_args()
1581
1582@@ -93,16 +93,20 @@
1583 # directory and check them for trailing whitespace.
1584
1585 directory = os.path.abspath(args.dir[0])
1586-ignore = args.ignore_prefix and os.path.abspath(args.ignore_prefix) or None
1587+ignores = args.ignore_prefix and args.ignore_prefix or []
1588
1589 found_whitespace = False
1590 try:
1591 for root, dirs, files in os.walk(directory, onerror = raise_error):
1592 for file in files:
1593 path = os.path.join(root, file)
1594- if not (ignore and path.startswith(ignore)) and pat.match(file):
1595- if scan_for_bad_whitespace(path):
1596- found_whitespace = True
1597+ ignored = False
1598+ for ignore in ignores:
1599+ if ignore and path.startswith(os.path.abspath(ignore)):
1600+ ignored = True
1601+ break
1602+ if not ignored and pat.match(file) and scan_for_bad_whitespace(path):
1603+ found_whitespace = True
1604
1605 except OSError as e:
1606 error("cannot create file list for \"" + dir + "\": " + e.strerror)
1607
1608=== removed file 'test/whitespace/check_whitespace.sh'
1609--- test/whitespace/check_whitespace.sh 2013-06-27 08:38:02 +0000
1610+++ test/whitespace/check_whitespace.sh 1970-01-01 00:00:00 +0000
1611@@ -1,62 +0,0 @@
1612-#!/bin/sh
1613-
1614-#
1615-# Copyright (C) 2013 Canonical Ltd
1616-#
1617-# This program is free software: you can redistribute it and/or modify
1618-# it under the terms of the GNU Lesser General Public License version 3 as
1619-# published by the Free Software Foundation.
1620-#
1621-# This program is distributed in the hope that it will be useful,
1622-# but WITHOUT ANY WARRANTY; without even the implied warranty of
1623-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1624-# GNU Lesser General Public License for more details.
1625-#
1626-# You should have received a copy of the GNU Lesser General Public License
1627-# along with this program. If not, see <http://www.gnu.org/licenses/>.
1628-#
1629-# Authored by: Michi Henning <michi.henning@canonical.com>
1630-#
1631-
1632-#
1633-# Check that files below the specified directory don't have lines with trailing whitespace.
1634-# Print out a messsage for each file with trailing whitespace and exit with non-zero status
1635-# if any such file is found.
1636-#
1637-
1638-usage()
1639-{
1640- echo "usage: check_whitespace.sh dir [ignore_dir]" >&2
1641- exit 2
1642-}
1643-
1644-[ $# -lt 1 ] && usage
1645-[ $# -gt 2 ] && usage
1646-
1647-ignore="grep -v CMakeFile"
1648-
1649-[ $# -eq 2 ] && {
1650- ignore="$ignore | grep -v \"$2\""
1651-}
1652-
1653-err=no
1654-for file in `find "$1" \
1655- -name '*.cpp' -o \
1656- -name '*.h' -o \
1657- -name '*.py' -o \
1658- -name '*.sh' -o \
1659- -name 'CMakeLists.txt' -o \
1660- -name '*.cmake' \
1661- | grep -v CMakeFiles \
1662- | eval $ignore`
1663-do
1664- grep -q '[ ]$' "$file"
1665- [ $? -eq 0 ] && {
1666- echo "$file: trailing whitespace"
1667- err=yes
1668- }
1669-done
1670-
1671-[ $err = yes ] && exit 1
1672-
1673-exit 0

Subscribers

People subscribed via source and target branches

to all changes: