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: