changeset 23682:1642eb429536

windows: quote the specified string only when it has to be quoted Before this patch, "windows.shellquote" (as used as "util.shellquote") always quotes specified strings with double quotation marks, for external process invocation. But some problematic applications can't work correctly, when command line arguments are quoted: see issue4463 for detail. On the other hand, quoting itself is needed to specify arguments containing whitespaces and/or some special characters exactly. This patch makes "windows.shellquote" examine the specified string and quote it only when it may have to be quoted for safety.
author FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
date Thu, 25 Dec 2014 23:33:26 +0900
parents 9476cb62298e
children 5edb387158a1
files mercurial/windows.py tests/test-extdiff.t
diffstat 2 files changed, 20 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/windows.py	Thu Dec 25 23:33:26 2014 +0900
+++ b/mercurial/windows.py	Thu Dec 25 23:33:26 2014 +0900
@@ -148,10 +148,20 @@
 # backslash before every double quote (being careful with the double
 # quote we've appended to the end)
 _quotere = None
+_needsshellquote = None
 def shellquote(s):
     global _quotere
     if _quotere is None:
         _quotere = re.compile(r'(\\*)("|\\$)')
+    global _needsshellquote
+    if _needsshellquote is None:
+        # ":" and "\\" are also treated as "safe character", because
+        # they are used as a part of path name (and the latter doesn't
+        # work as "escape character", like one on posix) on Windows
+        _needsshellquote = re.compile(r'[^a-zA-Z0-9._:/\\-]').search
+    if not _needsshellquote(s) and not _quotere.search(s):
+        # "s" shouldn't have to be quoted
+        return s
     return '"%s"' % _quotere.sub(r'\1\1\\\2', s)
 
 def quotecommand(cmd):
--- a/tests/test-extdiff.t	Thu Dec 25 23:33:26 2014 +0900
+++ b/tests/test-extdiff.t	Thu Dec 25 23:33:26 2014 +0900
@@ -107,11 +107,11 @@
   $ echo a >> a
 #if windows
   $ hg --debug 4463a | grep '^running'
-  running '"echo" a-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob)
+  running 'echo a-naked \'single quoted\' "double quoted" *\\a *\\a' in */extdiff.* (glob)
   $ hg --debug 4463b | grep '^running'
-  running 'echo b-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob)
+  running 'echo b-naked \'single quoted\' "double quoted" *\\a *\\a' in */extdiff.* (glob)
   $ hg --debug echo | grep '^running'
-  running '"*echo*" "*\\a" "*\\a"' in */extdiff.* (glob)
+  running '*echo* *\\a *\\a' in */extdiff.* (glob)
 #else
   $ hg --debug 4463a | grep '^running'
   running '\'echo\' a-naked \'single quoted\' "double quoted" \'*/a\' \'$TESTTMP/a/a\'' in */extdiff.* (glob)
@@ -138,15 +138,15 @@
   > EOF
 #if windows
   $ hg --debug 4463b2 | grep '^running'
-  running 'echo b2-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob)
+  running 'echo b2-naked \'single quoted\' "double quoted" *\\a *\\a' in */extdiff.* (glob)
   $ hg --debug 4463b3 | grep '^running'
-  running 'echo b3-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob)
+  running 'echo b3-naked \'single quoted\' "double quoted" *\\a *\\a' in */extdiff.* (glob)
   $ hg --debug 4463b4 | grep '^running'
-  running 'echo "*\\a" "*\\a"' in */extdiff.* (glob)
-  $ hg --debug 4463b4 --option 'being quoted' | grep '^running'
-  running 'echo "being quoted" "*\\a" "*\\a"' in */extdiff.* (glob)
-  $ hg --debug extdiff -p echo --option 'being quoted' | grep '^running'
-  running '"echo" "being quoted" "*\\a" "*\\a"' in */extdiff.* (glob)
+  running 'echo *\\a *\\a' in */extdiff.* (glob)
+  $ hg --debug 4463b4 --option b4-naked --option 'being quoted' | grep '^running'
+  running 'echo b4-naked "being quoted" *\\a *\\a' in */extdiff.* (glob)
+  $ hg --debug extdiff -p echo --option echo-naked --option 'being quoted' | grep '^running'
+  running 'echo echo-naked "being quoted" *\\a *\\a' in */extdiff.* (glob)
 #else
   $ hg --debug 4463b2 | grep '^running'
   running 'echo b2-naked \'single quoted\' "double quoted" \'*/a\' \'$TESTTMP/a/a\'' in */extdiff.* (glob)