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.
--- 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)