From: Justin Cinkelj <[email protected]>
Committer: Nadav Har'El <[email protected]>
Branch: master
command line: allow multiple commands per runscript file
Extend runscript to allow file with content like:
"/prog1 prm1; /prog2 prm2"
Tests are included.
Signed-off-by: Justin Cinkelj <[email protected]>
Message-Id: <[email protected]>
---
diff --git a/core/commands.cc b/core/commands.cc
--- a/core/commands.cc
+++ b/core/commands.cc
@@ -85,50 +85,65 @@ parse_command_line_min(const std::string line, bool &ok)
/*
If cmd starts with "runcript file", read content of file and
-update cmd with the content.
+return vector of all programs to be run.
+File can contain multiple commands per line.
ok flag is set to false on parse error, and left unchanged otherwise.
+
+If cmd doesn't start with runscript, then vector with size 0 is returned.
*/
-void runscript_expand(std::vector<std::string>& cmd, bool &ok)
+std::vector<std::vector<std::string>> runscript_expand(const
std::vector<std::string>& cmd, bool &ok)
{
+ std::vector<std::vector<std::string> > result;
if (cmd[0] == "runscript") {
- if (cmd.size()<2) {
- puts("Failed expanding runscript - filename missing.");
+ /*
+ The cmd vector ends with additional ";" or "\0" element.
+ */
+ if (cmd.size() != 3 && cmd[2].c_str()[0] != 0x00) {
+ puts("Failed expanding runscript - filename missing or extra
parameters present.");
ok = false;
- return;
+ return result;
}
auto fn = cmd[1];
std::ifstream in(fn);
std::string line;
// only first line up to \n is used.
getline(in, line);
- std::vector<std::vector<std::string> > result;
bool ok2;
result = parse_command_line_min(line, ok2);
debug("runscript expand fn='%s' line='%s'\n", fn.c_str(),
line.c_str());
if (ok2 == false) {
printf("Failed expanding runscript file='%s' line='%s'.\n",
fn.c_str(), line.c_str());
+ result.clear();
ok = false;
}
- else {
- cmd = result[0];
- }
}
+ return result;
}
std::vector<std::vector<std::string>>
parse_command_line(const std::string line, bool &ok)
{
- std::vector<std::vector<std::string> > result;
+ std::vector<std::vector<std::string> > result, result2;
result = parse_command_line_min(line, ok);
/*
If command starts with runscript, we need to read actual command to
execute from the given file.
*/
std::vector<std::vector<std::string>>::iterator cmd_iter;
- for (cmd_iter=result.begin(); ok && cmd_iter!=result.end();
cmd_iter++) {
- runscript_expand(*cmd_iter, ok);
+ for (cmd_iter=result.begin(); ok && cmd_iter!=result.end(); ) {
+ result2 = runscript_expand(*cmd_iter, ok);
+ if (result2.size() > 0) {
+ cmd_iter = result.erase(cmd_iter);
+ int pos;
+ pos = cmd_iter - result.begin();
+ result.insert(cmd_iter, result2.begin(), result2.end());
+ cmd_iter = result.begin() + pos + result2.size();
+ }
+ else {
+ cmd_iter++;
+ }
}
return result;
diff --git a/tests/tst-commands.cc b/tests/tst-commands.cc
--- a/tests/tst-commands.cc
+++ b/tests/tst-commands.cc
@@ -353,6 +353,168 @@ static bool test_runscript_multiple_with_args_quotes()
return true;
}
+static bool test_runscript_multiple_commands_per_line()
+{
+ std::ofstream of1("/myscript", std::ios::out | std::ios::binary);
+ of1 << "/prog1; /prog2";
+ of1.close();
+
+ std::vector<std::vector<std::string> > result;
+ std::vector<std::string> cmd = { "/prog1", "/prog2" };
+ bool ok;
+
+ result = osv::parse_command_line(
+ std::string("runscript \"/myscript\""),
+ ok);
+
+ if (!ok) {
+ return false;
+ }
+
+ if (result.size() != 2) {
+ return false;
+ }
+
+ if (result[0].size() != 2) {
+ return false;
+ }
+
+ if (result[1].size() != 2) {
+ return false;
+ }
+
+ for (size_t i = 0; i < result.size(); i++) {
+ if (result[i][0] != cmd[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool test_runscript_multiple_commands_per_line_with_args()
+{
+ std::ofstream of1("/myscript", std::ios::out | std::ios::binary);
+ of1 << "/prog1 pp1a ; /prog2 pp2a pp2b";
+ of1.close();
+
+ std::vector<std::vector<std::string> > result;
+ std::vector<std::string> cmd = { "/prog1", "/prog2" };
+ bool ok;
+
+ result = osv::parse_command_line(
+ std::string("runscript \"/myscript\""),
+ ok);
+
+ if (!ok) {
+ return false;
+ }
+
+ if (result.size() != 2) {
+ return false;
+ }
+
+ if (result[0].size() != 3) {
+ return false;
+ }
+
+ if (result[1].size() != 4) {
+ return false;
+ }
+
+ for (size_t i = 0; i < result.size(); i++) {
+ if (result[i][0] != cmd[i]) {
+ return false;
+ }
+ }
+
+ if (result[0][1] != std::string("pp1a")) {
+ return false;
+ }
+
+ if (result[1][1] != std::string("pp2a")) {
+ return false;
+ }
+ if (result[1][2] != std::string("pp2b")) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool test_runscript_multiple_commands_per_line_with_args_quotes()
+{
+ std::ofstream of1("/myscript", std::ios::out | std::ios::binary);
+ of1 << "/prog1 pp1a ; /prog2 pp2a pp2b; /prog3 pp3a \"pp3b1 pp3b2\"
\"pp3c1;pp3c2\" \"pp3d\" \" ;; --onx -fon;x \\t\"; ";
+ of1.close();
+
+ std::vector<std::vector<std::string> > result;
+ std::vector<std::string> cmd = { "/prog1", "/prog2", "/prog3" };
+ bool ok;
+
+ result = osv::parse_command_line(
+ std::string("runscript \"/myscript\""),
+ ok);
+
+ if (!ok) {
+ return false;
+ }
+
+ if (result.size() != 3) {
+ return false;
+ }
+
+ if (result[0].size() != 3) {
+ return false;
+ }
+
+ if (result[1].size() != 4) {
+ return false;
+ }
+
+ if (result[2].size() != 7) {
+ return false;
+ }
+
+ for (size_t i = 0; i < result.size(); i++) {
+ if (result[i][0] != cmd[i]) {
+ return false;
+ }
+ }
+
+ if (result[0][1] != std::string("pp1a")) {
+ return false;
+ }
+
+ if (result[1][1] != std::string("pp2a")) {
+ return false;
+ }
+ if (result[1][2] != std::string("pp2b")) {
+ return false;
+ }
+
+ if (result[2][1] != std::string("pp3a")) {
+ return false;
+ }
+ if (result[2][2] != std::string("pp3b1 pp3b2")) {
+ return false;
+ }
+ if (result[2][3] != std::string("pp3c1;pp3c2")) {
+ return false;
+ }
+ if (result[2][4] != std::string("pp3d")) {
+ return false;
+ }
+ if (result[2][5] != std::string(" ;; --onx -fon;x \t")) {
+ return false;
+ }
+ if (result[2][6] != std::string(";")) {
+ return false;
+ }
+
+ return true;
+}
+
int main(int argc, char *argv[])
{
report(test_parse_simplest(), "simplest command line");
@@ -369,6 +531,12 @@ int main(int argc, char *argv[])
"cpiod upload and haproxy launch");
report(test_runscript_multiple_with_args_quotes(),
"runscript multiple with args and quotes");
+ report(test_runscript_multiple_commands_per_line(),
+ "runscript multiple commands per line");
+ report(test_runscript_multiple_commands_per_line_with_args(),
+ "runscript multiple commands per line with args");
+ report(test_runscript_multiple_commands_per_line_with_args_quotes(),
+ "runscript multiple commands per line with args and quotes");
printf("SUMMARY: %d tests, %d failures\n", tests, fails);
return 0;
}
--
You received this message because you are subscribed to the Google Groups "OSv
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.