On Tue, 2010-11-09, Philip Martin wrote:
> Paul Burba <ptbu...@gmail.com> writes:
> 
> >   File "C:\SVN\src-trunk-2\subversion\tests\cmdline\svntest\main.py",
> > line 433, in spawn_process
> >     subprocess.list2cmdline(varargs)))
> >   File "C:\Python26\lib\subprocess.py", line 541, in list2cmdline
> >     needquote = (" " in arg) or ("\t" in arg) or ("|" in arg) or not arg
> > TypeError: argument of type 'int' is not iterable
> > FAIL:  commit_tests.py 41: set revision props during remote mkdir
> > ]]]
> >
> > No time to look into this further today, but I can check it out tomorrow.
> 
> Mapping to strings looks like it should fix that:
> 
>       subprocess.list2cmdline(map(str varargs))))

Thanks: I forgot to run the full test suite.  (With a comma: map(str,
varargs).)

But I realized list2cmdline() is Windows-specific, so although we're
only using it for display purposes it's not nice for us Unix types.  (We
like to be able to copy and paste and run the displayed command.)

I have searched the web for a generic way of doing this, and found
references to several methods including subprocess.list2cmdline(),
pipes.quote(), commands.mkarg(), and various code snippets.  None of
these are good generic solutions.  I saw recent discussions on a Python
mailing list about the need for a generic solution.

So here is another patch, doing the best I can for now.  I'm still
testing this one.

- Julian

Fix Windows command-line argument quoting in the Python test harness.
Arguments ending with a backslash were not correctly quoted, among other
issues.  This reverts r875257.

* subversion/tests/cmdline/svntest/main.py
  (_quote_arg): Do the quoting more correctly, using subprocess.list2cmdline()
    on Windows and in-line code on Unix.
  (open_pipe): Pass the list of arguments directly to subprocess.Popen()
    instead of trying to quote it ourselves on Windows.  Use our own quoting
    only for display purposes.
--This line, and those below, will be ignored--

Index: subversion/tests/cmdline/svntest/main.py
===================================================================
--- subversion/tests/cmdline/svntest/main.py	(revision 1032629)
+++ subversion/tests/cmdline/svntest/main.py	(working copy)
@@ -340,29 +340,28 @@ def run_command(command, error_expected,
 # system:
 _safe_arg_re = re.compile(r'^[A-Za-z\d\.\_\/\-\:\...@]+$')
 
 def _quote_arg(arg):
   """Quote ARG for a command line.
 
-  Simply surround every argument in double-quotes unless it contains
+  Return a quoted version of the string ARG, or just ARG if it contains
   only universally harmless characters.
 
   WARNING: This function cannot handle arbitrary command-line
-  arguments.  It can easily be confused by shell metacharacters.  A
-  perfect job would be difficult and OS-dependent (see, for example,
-  http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp).
-  In other words, this function is just good enough for what we need
-  here."""
+  arguments: it is just good enough for what we need here."""
 
   arg = str(arg)
   if _safe_arg_re.match(arg):
     return arg
+
+  if windows:
+    # Note: subprocess.list2cmdline is Windows-specific.
+    return subprocess.list2cmdline([arg])
   else:
-    if os.name != 'nt':
-      arg = arg.replace('$', '\$')
-    return '"%s"' % (arg,)
+    # Quoting suitable for most Unix shells.
+    return "'" + arg.replace("'", "'\\''") + "'"
 
 def open_pipe(command, bufsize=0, stdin=None, stdout=None, stderr=None):
   """Opens a subprocess.Popen pipe to COMMAND using STDIN,
   STDOUT, and STDERR.  BUFSIZE is passed to subprocess.Popen's
   argument of the same name.
 
@@ -372,21 +371,13 @@ def open_pipe(command, bufsize=0, stdin=
 
   # On Windows subprocess.Popen() won't accept a Python script as
   # a valid program to execute, rather it wants the Python executable.
   if (sys.platform == 'win32') and (command[0].endswith('.py')):
     command.insert(0, sys.executable)
 
-  # Quote only the arguments on Windows.  Later versions of subprocess,
-  # 2.5.2+ confirmed, don't require this quoting, but versions < 2.4.3 do.
-  if sys.platform == 'win32':
-    args = command[1:]
-    args = ' '.join([_quote_arg(x) for x in args])
-    command = command[0] + ' ' + args
-    command_string = command
-  else:
-    command_string = ' '.join(command)
+  command_string = command[0] + ' ' + ' '.join(map(_quote_arg, command[1:]))
 
   if not stdin:
     stdin = subprocess.PIPE
   if not stdout:
     stdout = subprocess.PIPE
   if not stderr:

Reply via email to