windows: expand '~/' and '~\' to %USERPROFILE% when translating to cmd.exe
authorMatt Harbison <matt_harbison@yahoo.com>
Mon, 16 Jul 2018 00:32:33 -0400
changeset 38725 c382c19ce9bd
parent 38724 02b5b5c1bba8
child 38726 d79f3afb079e
windows: expand '~/' and '~\' to %USERPROFILE% when translating to cmd.exe It's convenient to be able to reference hooks in a portable location on any platform.
mercurial/help/config.txt
mercurial/windows.py
--- a/mercurial/help/config.txt	Sun Jul 15 23:58:39 2018 -0400
+++ b/mercurial/help/config.txt	Mon Jul 16 00:32:33 2018 -0400
@@ -892,9 +892,11 @@
 .. container:: windows
 
   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.  Strong quotes
-  will be replaced by double quotes after processing.
+  and ``${VAR}`` style variables.  A ``~`` followed by ``\`` or ``/`` will
+  be expanded to ``%USERPROFILE%`` to simulate a subset of tilde expansion
+  on Unix.  To use a literal ``$`` or ``~``, it must be 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::
--- a/mercurial/windows.py	Sun Jul 15 23:58:39 2018 -0400
+++ b/mercurial/windows.py	Mon Jul 16 00:32:33 2018 -0400
@@ -276,8 +276,11 @@
     >>> # No double substitution
     >>> shelltocmdexe(b"$var1 %var1%", {b'var1': b'%var2%', b'var2': b'boom'})
     '%var1% %var1%'
+    >>> # Tilde expansion
+    >>> shelltocmdexe(b"~/dir ~\dir2 ~tmpfile \~/", {})
+    '%USERPROFILE%/dir %USERPROFILE%\\dir2 ~tmpfile ~/'
     """
-    if not any(c in path for c in b"$'"):
+    if not any(c in path for c in b"$'~"):
         return path
 
     varchars = pycompat.sysbytes(string.ascii_letters + string.digits) + b'_-'
@@ -344,9 +347,13 @@
 
                 if c != '':
                     index -= 1
-        elif c == b'\\' and index + 1 < pathlen and path[index + 1] == b'$':
-            # Skip '\', but only if it is escaping $
-            res += b'$'
+        elif (c == b'~' and index + 1 < pathlen
+              and path[index + 1] in (b'\\', b'/')):
+            res += "%USERPROFILE%"
+        elif (c == b'\\' and index + 1 < pathlen
+              and path[index + 1] in (b'$', b'~')):
+            # Skip '\', but only if it is escaping $ or ~
+            res += path[index + 1]
             index += 1
         else:
             res += c