Patchwork [3,of,4] windows: replace single quote with double quote when translating to cmd.exe

login
register
mail settings
Submitter Matt Harbison
Date July 16, 2018, 9:31 p.m.
Message ID <e71e478d5e4976835728.1531776694@mharbison-pc.attotech.com>
Download mbox | patch
Permalink /patch/32880/
State Accepted
Headers show

Comments

Matt Harbison - July 16, 2018, 9:31 p.m.
# HG changeset patch
# User Matt Harbison <matt_harbison@yahoo.com>
# Date 1531713519 14400
#      Sun Jul 15 23:58:39 2018 -0400
# Node ID e71e478d5e49768357287a2f181e8a2b23213239
# Parent  48070b1bc067ac31924c598686fb0822c6ff9409
windows: replace single quote with double quote when translating to cmd.exe

Since cmd.exe doesn't understand single quotes, single quotes to prevent $var
expansion is basically unusable without this.  Single quote isn't allowed in a
path name, so it seems unlikely to come up otherwise.

Patch

diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -893,7 +893,8 @@  be ``$HG_HOOKTYPE=incoming`` and ``$HG_H
 
   Some basic Unix syntax can be enabled for portability, including ``$VAR``
   and ``${VAR}`` style variables.  To use a literal ``$``, it must be
-  escaped with a back slash or inside of a strong quote.
+  escaped with a back slash or inside of a strong quote.  Strong quotes
+  will be replaced by double quotes after processing.
 
   This feature is enabled by adding a prefix of ``tonative.`` to the hook
   name on a new line, and setting it to ``True``.  For example::
diff --git a/mercurial/windows.py b/mercurial/windows.py
--- a/mercurial/windows.py
+++ b/mercurial/windows.py
@@ -268,7 +268,7 @@  def shelltocmdexe(path, env):
     'cmd %var1% %var2% %var3% $missing ${missing} %missing%'
     >>> # Single quote prevents expansion, as does \$ escaping
     >>> shelltocmdexe(b"cmd '$var1 ${var2} %var3%' \$var1 \${var2} \\", e)
-    "cmd '$var1 ${var2} %var3%' $var1 ${var2} \\"
+    'cmd "$var1 ${var2} %var3%" $var1 ${var2} \\'
     >>> # $$ is not special. %% is not special either, but can be the end and
     >>> # start of consecutive variables
     >>> shelltocmdexe(b"cmd $$ %% %var1%%var2%", e)
@@ -277,7 +277,7 @@  def shelltocmdexe(path, env):
     >>> shelltocmdexe(b"$var1 %var1%", {b'var1': b'%var2%', b'var2': b'boom'})
     '%var1% %var1%'
     """
-    if b'$' not in path:
+    if not any(c in path for c in b"$'"):
         return path
 
     varchars = pycompat.sysbytes(string.ascii_letters + string.digits) + b'_-'
@@ -292,7 +292,7 @@  def shelltocmdexe(path, env):
             pathlen = len(path)
             try:
                 index = path.index(b'\'')
-                res += b'\'' + path[:index + 1]
+                res += b'"' + path[:index] + b'"'
             except ValueError:
                 res += c + path
                 index = pathlen - 1
diff --git a/tests/test-histedit-fold.t b/tests/test-histedit-fold.t
--- a/tests/test-histedit-fold.t
+++ b/tests/test-histedit-fold.t
@@ -499,16 +499,15 @@  Test unix -> windows style variable subs
   > tonative.post-add = True
   > EOF
 
-TODO: Windows should output double quotes around "also $non-var"
   $ echo "foo" > amended.txt
   $ HGRCPATH=$TESTTMP/tmp.hgrc hg add -v amended.txt
   running hook pre-add: echo no variables
   no variables
   adding amended.txt
   converting hook "post-add" to native (windows !)
-  running hook post-add: echo ran %HG_ARGS%, literal $non-var, 'also $non-var', %HG_RESULT% (windows !)
+  running hook post-add: echo ran %HG_ARGS%, literal $non-var, "also $non-var", %HG_RESULT% (windows !)
   running hook post-add: echo ran $HG_ARGS, literal \$non-var, 'also $non-var', $HG_RESULT (no-windows !)
-  ran add -v amended.txt, literal $non-var, 'also $non-var', 0 (windows !)
+  ran add -v amended.txt, literal $non-var, "also $non-var", 0 (windows !)
   ran add -v amended.txt, literal $non-var, also $non-var, 0 (no-windows !)
   $ hg ci -q --config extensions.largefiles= --amend -I amended.txt
   The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)