From: Justin Cinkelj <justin.cink...@xlab.si>
Committer: Nadav Har'El <n...@scylladb.com>
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 <justin.cink...@xlab.si>
Message-Id: <1479825169-15499-4-git-send-email-justin.cink...@xlab.si>

---
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 osv-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to