[PATCH] hooks: allow Unix style environment variables on external Windows hooks

Matt Harbison mharbison72 at gmail.com
Mon Jul 3 21:57:01 EDT 2017


On Mon, 03 Jul 2017 12:15:49 -0400, FUJIWARA Katsunori  
<foozy at lares.dti.ne.jp> wrote:

> At Mon, 3 Jul 2017 22:32:32 +0900,
> Yuya Nishihara wrote:
>>
>> On Sun, 02 Jul 2017 01:45:00 -0400, Matt Harbison wrote:
>> > # HG changeset patch
>> > # User Matt Harbison <matt_harbison at yahoo.com>
>> > # Date 1498969929 14400
>> > #      Sun Jul 02 00:32:09 2017 -0400
>> > # Node ID 5684913c02965f4a6bb43320e8aa189333962dd1
>> > # Parent  61ed2cc98fd17c50c7adf634d777d946781a9fc1
>> > hooks: allow Unix style environment variables on external Windows  
>> hooks
>> >
>> > This will help making common hooks between Windows and non-Windows  
>> platforms.
>> > The hook is launched via cmd.exe, which doesn't understand $var, nor  
>> single
>> > quotes.  Therefore, all that is handled is converting $var to %var%,  
>> and
>> > allowing a literal '$' if escaped with '\'.  Like Unix variables,  
>> Windows will
>> > substitute in the middle of a word (e.g. foo%bar%), so I don't think  
>> there are
>> > any other special cases to handle.
>>
>> (+CC foozy, another Windows expert)
>>
>> Perhaps we'll need to update the help. '$' could be included in a valid
>> filename, which now escape is required.
>>
>> > --- a/mercurial/hook.py
>> > +++ b/mercurial/hook.py
>> > @@ -8,6 +8,7 @@
>> >  from __future__ import absolute_import
>> >
>> >  import os
>> > +import re
>> >  import sys
>> >
>> >  from .i18n import _
>> > @@ -116,6 +117,17 @@
>> >      return r, False
>> >
>> >  def _exthook(ui, repo, htype, name, cmd, args, throw):
>> > +    if pycompat.osname == 'nt':
>> > +        # Replace Unix style environment variables with Windows  
>> style variables,
>> > +        # for replacement by cmd.exe.  Treat '\$' as a literal $.
>> > +        def replacer(m):
>> > +            prefix = m.group(1)
>> > +            if prefix == '\\':
>> > +                return '$' + m.group(2)
>> > +            return prefix + '%' + m.group(2) + '%'
>> > +
>> > +        cmd = re.sub(br'(.?)\$(.+?)\b', replacer, cmd)
>
> How about '(.?)\$([A-Za-z_]\w*)' for more strict matching against
> variable name?

Unfortunately, that strictness is... optimistic:

https://ss64.com/nt/syntax-variables.html

Names can include spaces, '{', '}', and '$'.  Ugh.

Or are you saying we don't need to support those characters, because they  
wouldn't be portable anyway?  (The fact that there are built-ins with some  
non portable characters like 'COMMONPROGRAMFILES(X86)' gives me slight  
pause, though I've never seen any of the other characters in practice.   
And mostly the convenience is when using variables exported by hg.)

> BTW, is supporting simple "{}" surround over engineering in this case?

Seems easy to do, and reasonable.

>     def replacer(m):
>         prefix = m.group(1)
>         if prefix == '\\':
>             return '$' + m.group(2)
>         varname = m.group(2)
>         if varname.startswith('{'):
>             return prefix + '%' + m.group(2)[1:-1] + '%'
>         return prefix + '%' + m.group(2) + '%'
>
>     cmd = re.sub(br'(.?)\$({[A-Za-z_]\w*}|[A-Za-z_]\w*)', replacer, cmd)
>
> This allows concatenation of environment variables and normal texts
> (e.g. ${FOO}BAR).
>
>> Can you move this to windows.py, which hosts several shell-related  
>> functions.
>> I think the function can have some doctests.
>>


More information about the Mercurial-devel mailing list