psss / rpms / python-tox

Forked from rpms/python-tox 4 years ago
Clone
6683010
# HG changeset patch
6683010
# User Clark Boylan <clark.boylan@gmail.com>
6683010
# Date 1391830704 28800
6683010
# Node ID 62fe57a8fd3f8f44be8957e59846387d2f505227
6683010
# Parent  b0360a54ab368ef428c7f83601ba6b64f6fec64f
6683010
Fix command expansion and parsing.
6683010
6683010
Tox testenv commands are parsed to expand variable substitutions and
6683010
construct the argv list that will be passed to exec. Prior to this
6683010
commit this parsing ate quotes surrounding variables and treated
6683010
multiword variables as single argv items. Neither behavior was correct.
6683010
To fix this create the expanded command before handing it off to shlex
6683010
to do the tokenization of the argv list. Doing the parsing in this
6683010
order ensures it is correct.
6683010
6683010
diff --git a/tests/test_config.py b/tests/test_config.py
6683010
--- a/tests/test_config.py
6683010
+++ b/tests/test_config.py
6683010
@@ -278,7 +278,7 @@
6683010
         #    "reader.getargvlist('section', 'key1')")
6683010
         assert reader.getargvlist('section', 'key1') == []
6683010
         x = reader.getargvlist("section", "key2")
6683010
-        assert x == [["cmd1", "with space", "grr"],
6683010
+        assert x == [["cmd1", "with", "space", "grr"],
6683010
                      ["cmd2", "grr"]]
6683010
 
6683010
     def test_argvlist_windows_escaping(self, tmpdir, newconfig):
6683010
@@ -304,7 +304,7 @@
6683010
         #    "reader.getargvlist('section', 'key1')")
6683010
         assert reader.getargvlist('section', 'key1') == []
6683010
         x = reader.getargvlist("section", "key2")
6683010
-        assert x == [["cmd1", "with space", "grr"]]
6683010
+        assert x == [["cmd1", "with", "space", "grr"]]
6683010
 
6683010
 
6683010
     def test_argvlist_quoting_in_command(self, tmpdir, newconfig):
6683010
diff --git a/tox/_config.py b/tox/_config.py
6683010
--- a/tox/_config.py
6683010
+++ b/tox/_config.py
6683010
@@ -527,30 +527,35 @@
6683010
     def _processcommand(self, command):
6683010
         posargs = getattr(self, "posargs", None)
6683010
 
6683010
-        # special treat posargs which might contain multiple arguments
6683010
-        # in their defaults
6683010
+        # Iterate through each word of the command substituting as
6683010
+        # appropriate to construct the new command string. This
6683010
+        # string is then broken up into exec argv components using
6683010
+        # shlex.
6683010
         newcommand = ""
6683010
         for word in CommandParser(command).words():
6683010
-            if word.startswith("{posargs:") and word.endswith("}"):
6683010
+            if word == "{posargs}" or word == "[]":
6683010
                 if posargs:
6683010
-                    word = "{posargs}"
6683010
+                    newcommand += " ".join(posargs)
6683010
+                continue
6683010
+            elif word.startswith("{posargs:") and word.endswith("}"):
6683010
+                if posargs:
6683010
+                    newcommand += " ".join(posargs)
6683010
+                    continue
6683010
                 else:
6683010
                     word = word[9:-1]
6683010
-            newcommand += word
6683010
+            new_arg = ""
6683010
+            new_word = self._replace(word)
6683010
+            new_word = self._replace(new_word)
6683010
+            new_arg += new_word
6683010
+            newcommand += new_arg
6683010
 
6683010
-        # now we can properly parse the command
6683010
-        argv = []
6683010
-        for arg in shlex.split(newcommand):
6683010
-            if arg in ('[]', "{posargs}"):
6683010
-                if posargs:
6683010
-                    argv.extend(posargs)
6683010
-                continue
6683010
-            new_arg = ""
6683010
-            for word in CommandParser(arg).words():
6683010
-                new_word = self._replace(word)
6683010
-                new_word = self._replace(new_word)
6683010
-                new_arg += new_word
6683010
-            argv.append(new_arg)
6683010
+        # Construct shlex object that will not escape any values,
6683010
+        # use all values as is in argv.
6683010
+        shlexer = shlex.shlex(newcommand, posix=True)
6683010
+        shlexer.whitespace_split = True
6683010
+        shlexer.escape = ''
6683010
+        shlexer.commenters = ''
6683010
+        argv = list(shlexer)
6683010
         return argv
6683010
 
6683010
     def getargv(self, section, name, default=None, replace=True):