Merge lp:unity-scopes-api/staging into lp:unity-scopes-api

Proposed by Paweł Stołowski
Status: Merged
Approved by: Marcus Tomlinson
Approved revision: 305
Merged at revision: 351
Proposed branch: lp:unity-scopes-api/staging
Merge into: lp:unity-scopes-api
Diff against target: 492 lines (+202/-97)
11 files modified
include/unity/scopes/internal/Utils.h (+5/-0)
scoperegistry/scoperegistry.cpp (+1/-51)
src/scopes/internal/JsonCppNode.cpp (+10/-0)
src/scopes/internal/Utils.cpp (+83/-0)
src/scopes/internal/zmq_middleware/ZmqObject.cpp (+1/-4)
test/gtest/scopes/Registry/scopes/testscopeB/testscopeB.cpp (+5/-1)
test/gtest/scopes/Registry/scopes/testscopeB/testscopeB.ini.in (+1/-1)
test/gtest/scopes/internal/SettingsDB/SettingsDB_test.cpp (+7/-3)
test/gtest/scopes/internal/Utils/Utils_test.cpp (+86/-0)
test/gtest/scopes/internal/zmq_middleware/RegistryI/RegistryI_test.cpp (+2/-37)
unity-scopes.map (+1/-0)
To merge this branch: bzr merge lp:unity-scopes-api/staging
Reviewer Review Type Date Requested Status
Marcus Tomlinson (community) Approve
Review via email: mp+271785@code.launchpad.net

Commit message

Merged devel.

Description of the change

Merged devel.

To post a comment you must log in.
Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

ACK

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/unity/scopes/internal/Utils.h'
2--- include/unity/scopes/internal/Utils.h 2015-04-10 03:55:25 +0000
3+++ include/unity/scopes/internal/Utils.h 2015-09-21 09:13:55 +0000
4@@ -22,6 +22,8 @@
5 #include <string>
6 #include <sstream>
7
8+#include <boost/filesystem.hpp>
9+
10 namespace unity
11 {
12
13@@ -57,6 +59,9 @@
14
15 void make_directories(std::string const& path_name, mode_t mode);
16
17+std::vector<std::string> split_exec_args(std::string const& id, std::string const& custom_exec);
18+std::string convert_exec_rel_to_abs(std::string const& id, boost::filesystem::path const& scope_dir, std::string const& custom_exec);
19+
20 } // namespace internal
21
22 } // namespace scopes
23
24=== modified file 'scoperegistry/scoperegistry.cpp'
25--- scoperegistry/scoperegistry.cpp 2015-07-01 11:02:46 +0000
26+++ scoperegistry/scoperegistry.cpp 2015-09-21 09:13:55 +0000
27@@ -259,30 +259,6 @@
28 }
29 }
30
31-string get_first_component(string const& id, string const& custom_exec)
32-{
33- if (custom_exec.empty())
34- {
35- throw unity::InvalidArgumentException("Invalid scope runner executable for scope: " + id);
36- }
37-
38- wordexp_t exp;
39- string result;
40-
41- // Split command into program and args
42- if (wordexp(custom_exec.c_str(), &exp, WRDE_NOCMD) == 0)
43- {
44- util::ResourcePtr<wordexp_t*, decltype(&wordfree)> free_guard(&exp, wordfree);
45- result = exp.we_wordv[0];
46- }
47- else
48- {
49- throw unity::InvalidArgumentException("Invalid scope runner executable for scope: " + id);
50- }
51-
52- return result;
53-}
54-
55 // For each scope, open the config file for the scope, create the metadata info from the config,
56 // and add an entry to the RegistryObject.
57 // If the scope uses settings, also parse the settings file and add the settings to the metadata.
58@@ -435,33 +411,7 @@
59
60 try
61 {
62- auto custom_exec = sc.scope_runner();
63- filesystem::path program(get_first_component( scope.first, custom_exec));
64- if (program.is_relative())
65- {
66- // First look inside the arch-specific directory
67- if (filesystem::exists(scope_dir / DEB_HOST_MULTIARCH / program))
68- {
69- // Join the full command, not just the program path
70- exec_data.custom_exec = (scope_dir / DEB_HOST_MULTIARCH / custom_exec).native();
71- }
72- // Next try in the non arch-aware directory
73- else if (filesystem::exists(scope_dir / program))
74- {
75- // Join the full command, not just the program path
76- exec_data.custom_exec = (scope_dir / custom_exec).native();
77- }
78- else
79- {
80- throw unity::InvalidArgumentException(
81- "Nonexistent scope runner '" + custom_exec
82- + "' executable for scope: " + scope.first);
83- }
84- }
85- else
86- {
87- exec_data.custom_exec = custom_exec;
88- }
89+ exec_data.custom_exec = convert_exec_rel_to_abs(scope.first, scope_dir, sc.scope_runner());
90 }
91 catch (NotFoundException const&)
92 {
93
94=== modified file 'src/scopes/internal/JsonCppNode.cpp'
95--- src/scopes/internal/JsonCppNode.cpp 2015-07-13 08:44:43 +0000
96+++ src/scopes/internal/JsonCppNode.cpp 2015-09-21 09:13:55 +0000
97@@ -279,6 +279,11 @@
98
99 JsonNodeInterface::SPtr JsonCppNode::get_node(std::string const& node_name) const
100 {
101+ if (!root_)
102+ {
103+ throw unity::LogicException("Current node is empty");
104+ }
105+
106 if (!root_.isMember(node_name))
107 {
108 throw unity::LogicException("Node " + node_name + " does not exist");
109@@ -290,6 +295,11 @@
110
111 JsonNodeInterface::SPtr JsonCppNode::get_node(unsigned int node_index) const
112 {
113+ if (!root_)
114+ {
115+ throw unity::LogicException("Current node is empty");
116+ }
117+
118 if (root_.type() != Json::arrayValue)
119 {
120 throw unity::LogicException("Root node is not an array");
121
122=== modified file 'src/scopes/internal/Utils.cpp'
123--- src/scopes/internal/Utils.cpp 2015-04-10 03:55:25 +0000
124+++ src/scopes/internal/Utils.cpp 2015-09-21 09:13:55 +0000
125@@ -19,12 +19,14 @@
126 #include <unity/scopes/internal/Utils.h>
127 #include <unity/scopes/ScopeExceptions.h>
128 #include <unity/UnityExceptions.h>
129+#include <unity/util/ResourcePtr.h>
130
131 #include <boost/filesystem.hpp>
132
133 #include <iomanip>
134 #include <locale>
135 #include <mutex>
136+#include <wordexp.h>
137
138 #include <sys/stat.h>
139
140@@ -190,6 +192,87 @@
141 }
142 }
143
144+vector<string> split_exec_args(string const& id, string const& custom_exec)
145+{
146+ if (custom_exec.empty())
147+ {
148+ throw unity::InvalidArgumentException("Invalid empty executable for scope: '" + id + "'");
149+ }
150+
151+ wordexp_t exp;
152+ vector<string> result;
153+
154+ // Split command into program and args
155+ if (wordexp(custom_exec.c_str(), &exp, WRDE_NOCMD) == 0)
156+ {
157+ util::ResourcePtr<wordexp_t*, decltype(&wordfree)> free_guard(&exp, wordfree);
158+ for (size_t i = 0; i < exp.we_wordc; ++i )
159+ {
160+ auto argument = string(exp.we_wordv[i]);
161+ if(argument.find_first_of(' ') != std::string::npos)
162+ {
163+ // This argument contains spaces, enclose it in quotation marks
164+ result.emplace_back("\"" + argument + "\"");
165+ }
166+ else
167+ {
168+ result.emplace_back(argument);
169+ }
170+ }
171+ }
172+ else
173+ {
174+ throw unity::InvalidArgumentException("Invalid executable for scope: '" + id + "'");
175+ }
176+
177+ return result;
178+}
179+
180+string convert_exec_rel_to_abs(string const& id, boost::filesystem::path const& scope_dir, string const& custom_exec)
181+{
182+ string result;
183+
184+ // Loop through each argument of the scope runner command and ensure all path args are absolute
185+ auto custom_exec_args = split_exec_args(id, custom_exec);
186+ for (auto custom_exec_arg : custom_exec_args)
187+ {
188+ boost::filesystem::path argument(custom_exec_arg);
189+ if (argument.is_relative())
190+ {
191+ // First look inside the arch-specific directory
192+ if (boost::filesystem::exists(scope_dir / DEB_HOST_MULTIARCH / argument))
193+ {
194+ // Append the argument as a relative path
195+ result += (scope_dir / DEB_HOST_MULTIARCH / argument).native() + " ";
196+ }
197+ // Next try in the non arch-aware directory
198+ else if (boost::filesystem::exists(scope_dir / argument))
199+ {
200+ // Append the argument as a relative path
201+ result += (scope_dir / argument).native() + " ";
202+ }
203+ // If this is the first argument (program name) it must exist, throw here
204+ else if (result.empty())
205+ {
206+ throw unity::InvalidArgumentException(
207+ "Nonexistent scope runner executable: '" + custom_exec_arg
208+ + "' for scope: '" + id + "'");
209+ }
210+ // Otherwise just append the argument as is
211+ else
212+ {
213+ result += custom_exec_arg + " ";
214+ }
215+ }
216+ else
217+ {
218+ result += custom_exec_arg + " ";
219+ }
220+ }
221+ result.resize(result.size() - 1);
222+ return result;
223+}
224+
225 } // namespace internal
226
227 } // namespace scopes
228
229=== modified file 'src/scopes/internal/zmq_middleware/ZmqObject.cpp'
230--- src/scopes/internal/zmq_middleware/ZmqObject.cpp 2015-08-04 04:56:01 +0000
231+++ src/scopes/internal/zmq_middleware/ZmqObject.cpp 2015-09-21 09:13:55 +0000
232@@ -250,16 +250,13 @@
233
234 ZmqObjectProxy::TwowayOutParams ZmqObjectProxy::invoke_twoway__(capnp::MessageBuilder& request, int64_t timeout)
235 {
236- RequestMode mode;
237 std::string endpoint;
238 {
239 lock_guard<mutex> lock(shared_mutex);
240- mode = mode_;
241 endpoint = endpoint_;
242+ assert(mode_ == RequestMode::Twoway);
243 }
244
245- assert(mode == RequestMode::Twoway);
246-
247 zmqpp::socket s(*mw_base()->context(), zmqpp::socket_type::request);
248 // Allow some linger time so we don't hang indefinitely if the other end disappears.
249 s.set(zmqpp::socket_option::linger, 100);
250
251=== modified file 'test/gtest/scopes/Registry/scopes/testscopeB/testscopeB.cpp'
252--- test/gtest/scopes/Registry/scopes/testscopeB/testscopeB.cpp 2014-12-05 03:05:37 +0000
253+++ test/gtest/scopes/Registry/scopes/testscopeB/testscopeB.cpp 2015-09-21 09:13:55 +0000
254@@ -25,6 +25,9 @@
255 #include <unity/scopes/Runtime.h>
256 #include <unity/scopes/PreviewReply.h>
257
258+#include <boost/filesystem.hpp>
259+
260+using namespace boost;
261 using namespace std;
262 using namespace unity::scopes;
263
264@@ -102,10 +105,11 @@
265 std::string scope_config = argc > 2 ? argv[2] : "FAIL";
266 std::string rt_config = argc > 3 ? argv[3] : "FAIL";
267 std::string unused_arg_2 = argc > 4 ? argv[4] : "FAIL";
268+ filesystem::path abs_path_arg(argc > 5 ? argv[5] : "FAIL");
269
270 // In order to test that custom exec splitting works, we check here that our arbitrary arguments
271 // have been delivered to us as expected.
272- if (unused_arg_1 == "unused arg 1" && unused_arg_2 == "unused arg 2")
273+ if (unused_arg_1 == "unused arg 1" && unused_arg_2 == "unused arg 2" && filesystem::exists(abs_path_arg))
274 {
275 MyScope scope;
276 auto runtime = Runtime::create_scope_runtime("testscopeB", rt_config);
277
278=== modified file 'test/gtest/scopes/Registry/scopes/testscopeB/testscopeB.ini.in'
279--- test/gtest/scopes/Registry/scopes/testscopeB/testscopeB.ini.in 2014-12-08 15:17:04 +0000
280+++ test/gtest/scopes/Registry/scopes/testscopeB/testscopeB.ini.in 2015-09-21 09:13:55 +0000
281@@ -6,5 +6,5 @@
282 Icon = data/scope-B.Icon
283 SearchHint = scope-B.SearchHint
284 HotKey = scope-B.HotKey
285-ScopeRunner = testscopeB "unused arg 1" %S %R unused' 'arg' '2
286+ScopeRunner = testscopeB "unused arg 1" %S %R unused' 'arg' '2 ./testscopeB.ini
287 IdleTimeout = 2
288
289=== modified file 'test/gtest/scopes/internal/SettingsDB/SettingsDB_test.cpp'
290--- test/gtest/scopes/internal/SettingsDB/SettingsDB_test.cpp 2015-07-13 14:43:24 +0000
291+++ test/gtest/scopes/internal/SettingsDB/SettingsDB_test.cpp 2015-09-21 09:13:55 +0000
292@@ -44,7 +44,7 @@
293 int fd = ::open(db_name.c_str(), O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
294 if (fd == -1)
295 {
296- FAIL() << "Couldn't open file " << db_name << " " << errno;
297+ FAIL() << "Couldn't open file " << db_name << ", errno: " << errno;
298 }
299
300 struct flock fl;
301@@ -56,7 +56,7 @@
302
303 if (::fcntl(fd, F_SETLKW, &fl) != 0)
304 {
305- FAIL() << "Couldn't get write lock for " << db_name << " " << errno;
306+ FAIL() << "Couldn't get write lock for " << db_name << ", errno: " << errno;
307 }
308
309 string pth = string(TEST_SRC_DIR) + "/" + src;
310@@ -71,7 +71,11 @@
311 char buf[1024];
312 while ((n = ::read(fd2, buf, 1024)) > 0)
313 {
314- ::write(fd, buf, n);
315+ int rc = ::write(fd, buf, n);
316+ if (rc != n)
317+ {
318+ FAIL() << "Write returned " << rc << ", expected " << n << " (" << db_name << ", errno: " << errno << ")";
319+ }
320 }
321 ::close(fd2);
322 ::close(fd);
323
324=== modified file 'test/gtest/scopes/internal/Utils/Utils_test.cpp'
325--- test/gtest/scopes/internal/Utils/Utils_test.cpp 2015-04-10 03:55:25 +0000
326+++ test/gtest/scopes/internal/Utils/Utils_test.cpp 2015-09-21 09:13:55 +0000
327@@ -132,3 +132,89 @@
328
329 chmod(child.c_str(), 0777); // Don't leave the dir behind without permissions.
330 }
331+
332+TEST(Utils, split_exec_args)
333+{
334+ // Test empty executable
335+ try
336+ {
337+ split_exec_args("test", "");
338+ FAIL();
339+ }
340+ catch (std::exception const& e)
341+ {
342+ EXPECT_STREQ("unity::InvalidArgumentException: Invalid empty executable for scope: 'test'", e.what());
343+ }
344+
345+ // Test invalid executable
346+ try
347+ {
348+ split_exec_args("test", "\"");
349+ FAIL();
350+ }
351+ catch (std::exception const& e)
352+ {
353+ EXPECT_STREQ("unity::InvalidArgumentException: Invalid executable for scope: 'test'", e.what());
354+ }
355+
356+ // Test argument splitting
357+ auto exec_args = split_exec_args("test", "/path\\ to/exec' 'file arg \"arg 2\" arg' '3 arg\\ 4");
358+ ASSERT_EQ(5, exec_args.size());
359+ EXPECT_STREQ("\"/path to/exec file\"", exec_args[0].c_str());
360+ EXPECT_STREQ("arg", exec_args[1].c_str());
361+ EXPECT_STREQ("\"arg 2\"", exec_args[2].c_str());
362+ EXPECT_STREQ("\"arg 3\"", exec_args[3].c_str());
363+ EXPECT_STREQ("\"arg 4\"", exec_args[4].c_str());
364+}
365+
366+TEST(Utils, convert_exec_rel_to_abs)
367+{
368+ // Test empty executable
369+ try
370+ {
371+ convert_exec_rel_to_abs("test", boost::filesystem::path(TEST_DIR), "");
372+ FAIL();
373+ }
374+ catch (std::exception const& e)
375+ {
376+ EXPECT_STREQ("unity::InvalidArgumentException: Invalid empty executable for scope: 'test'", e.what());
377+ }
378+
379+ // Test invalid executable
380+ try
381+ {
382+ convert_exec_rel_to_abs("test", boost::filesystem::path(TEST_DIR), "\"");
383+ FAIL();
384+ }
385+ catch (std::exception const& e)
386+ {
387+ EXPECT_STREQ("unity::InvalidArgumentException: Invalid executable for scope: 'test'", e.what());
388+ }
389+
390+ // Test nonexistent executable
391+ try
392+ {
393+ convert_exec_rel_to_abs("test", boost::filesystem::path(TEST_DIR), "noexec");
394+ FAIL();
395+ }
396+ catch (std::exception const& e)
397+ {
398+ EXPECT_STREQ("unity::InvalidArgumentException: Nonexistent scope runner executable: 'noexec' for scope: 'test'", e.what());
399+ }
400+
401+ // Test absolute executable
402+ auto abs_exec = convert_exec_rel_to_abs("test", boost::filesystem::path(TEST_DIR), "/bin/bash");
403+ EXPECT_STREQ("/bin/bash", abs_exec.c_str());
404+
405+ // Test absolute executable w/ args
406+ abs_exec = convert_exec_rel_to_abs("test", boost::filesystem::path(TEST_DIR), "/bin/bash arg \"arg 2\" arg' '3 arg\\ 4");
407+ EXPECT_STREQ("/bin/bash arg \"arg 2\" \"arg 3\" \"arg 4\"", abs_exec.c_str());
408+
409+ // Test relative executable (w/ ./)
410+ abs_exec = convert_exec_rel_to_abs("test", boost::filesystem::path(TEST_DIR), "./Utils_test");
411+ EXPECT_TRUE(boost::filesystem::exists(abs_exec));
412+
413+ // Test relative executable (w/o ./)
414+ abs_exec = convert_exec_rel_to_abs("test", boost::filesystem::path(TEST_DIR), "Utils_test");
415+ EXPECT_TRUE(boost::filesystem::exists(abs_exec));
416+}
417
418=== modified file 'test/gtest/scopes/internal/zmq_middleware/RegistryI/RegistryI_test.cpp'
419--- test/gtest/scopes/internal/zmq_middleware/RegistryI/RegistryI_test.cpp 2015-07-22 03:54:35 +0000
420+++ test/gtest/scopes/internal/zmq_middleware/RegistryI/RegistryI_test.cpp 2015-09-21 09:13:55 +0000
421@@ -28,6 +28,7 @@
422 #include <unity/scopes/internal/ScopeMetadataImpl.h>
423 #include <unity/scopes/internal/ScopeImpl.h>
424 #include <unity/scopes/internal/UniqueID.h>
425+#include <unity/scopes/internal/Utils.h>
426 #include <unity/scopes/internal/zmq_middleware/ZmqRegistry.h>
427 #include <unity/scopes/SearchMetadata.h>
428 #include <unity/scopes/ScopeExceptions.h>
429@@ -465,42 +466,6 @@
430 return count_child_procs() - start_process_count;
431 }
432
433- string convert_custom_exec(fs::path const& scope_dir, string const& custom_exec)
434- {
435- string result;
436-
437- vector<string> split;
438- boost::split(split, custom_exec, boost::is_space());
439- fs::path program(split.front());
440- if (program.is_relative())
441- {
442- // First look inside the arch-specific directory
443- if (fs::exists(scope_dir / DEB_HOST_MULTIARCH / program))
444- {
445- // Join the full command, not just the program path
446- result = (scope_dir / DEB_HOST_MULTIARCH / custom_exec).native();
447- }
448- // Next try in the non arch-aware directory
449- else if (fs::exists(scope_dir / program))
450- {
451- // Join the full command, not just the program path
452- result = (scope_dir / custom_exec).native();
453- }
454- else
455- {
456- throw unity::InvalidArgumentException(
457- "Nonexistent scope runner '" + custom_exec
458- + "' executable for scope");
459- }
460- }
461- else
462- {
463- result = custom_exec;
464- }
465-
466- return result;
467- }
468-
469 ScopeProxy start_testscopeB()
470 {
471 std::string test_scope_id = "testscopeB";
472@@ -519,7 +484,7 @@
473
474 RegistryObject::ScopeExecData exec_data;
475 exec_data.scope_id = test_scope_id;
476- exec_data.custom_exec = convert_custom_exec(REGISTRY_TEST_DIR "/scopes/testscopeB", sc.scope_runner());
477+ exec_data.custom_exec = convert_exec_rel_to_abs(test_scope_id, REGISTRY_TEST_DIR "/scopes/testscopeB", sc.scope_runner());
478 exec_data.runtime_config = runtime_ini;
479 exec_data.scope_config = test_scope_config;
480 exec_data.timeout_ms = process_timeout;
481
482=== modified file 'unity-scopes.map'
483--- unity-scopes.map 2015-04-10 03:55:25 +0000
484+++ unity-scopes.map 2015-09-21 09:13:55 +0000
485@@ -13,6 +13,7 @@
486 virtual?thunk?to?unity::scopes::[!iu]*;
487 vtable?for?unity::scopes::utility::[!i]*;
488 vtable?for?unity::scopes::[!iu]*;
489+ unity::scopes::internal::convert_exec_rel_to_abs*;
490 unity::scopes::internal::Executor::*;
491 unity::scopes::internal::IniSettingsSchema::*;
492 unity::scopes::internal::JsonSettingsSchema::*;

Subscribers

People subscribed via source and target branches

to all changes: