250 normcasespec = encoding.normcasespecs.upper |
251 normcasespec = encoding.normcasespecs.upper |
251 normcasefallback = encoding.upperfallback |
252 normcasefallback = encoding.upperfallback |
252 |
253 |
253 def samestat(s1, s2): |
254 def samestat(s1, s2): |
254 return False |
255 return False |
|
256 |
|
257 def shelltocmdexe(path, env): |
|
258 r"""Convert shell variables in the form $var and ${var} inside ``path`` |
|
259 to %var% form. Existing Windows style variables are left unchanged. |
|
260 |
|
261 The variables are limited to the given environment. Unknown variables are |
|
262 left unchanged. |
|
263 |
|
264 >>> e = {b'var1': b'v1', b'var2': b'v2', b'var3': b'v3'} |
|
265 >>> # Only valid values are expanded |
|
266 >>> shelltocmdexe(b'cmd $var1 ${var2} %var3% $missing ${missing} %missing%', |
|
267 ... e) |
|
268 'cmd %var1% %var2% %var3% $missing ${missing} %missing%' |
|
269 >>> # Single quote prevents expansion, as does \$ escaping |
|
270 >>> shelltocmdexe(b"cmd '$var1 ${var2} %var3%' \$var1 \${var2} \\", e) |
|
271 "cmd '$var1 ${var2} %var3%' $var1 ${var2} \\" |
|
272 >>> # $$ -> $, %% is not special, but can be the end and start of variables |
|
273 >>> shelltocmdexe(b"cmd $$ %% %var1%%var2%", e) |
|
274 'cmd $ %% %var1%%var2%' |
|
275 >>> # No double substitution |
|
276 >>> shelltocmdexe(b"$var1 %var1%", {b'var1': b'%var2%', b'var2': b'boom'}) |
|
277 '%var1% %var1%' |
|
278 """ |
|
279 if b'$' not in path: |
|
280 return path |
|
281 |
|
282 varchars = pycompat.sysbytes(string.ascii_letters + string.digits) + b'_-' |
|
283 |
|
284 res = b'' |
|
285 index = 0 |
|
286 pathlen = len(path) |
|
287 while index < pathlen: |
|
288 c = path[index] |
|
289 if c == b'\'': # no expansion within single quotes |
|
290 path = path[index + 1:] |
|
291 pathlen = len(path) |
|
292 try: |
|
293 index = path.index(b'\'') |
|
294 res += b'\'' + path[:index + 1] |
|
295 except ValueError: |
|
296 res += c + path |
|
297 index = pathlen - 1 |
|
298 elif c == b'%': # variable |
|
299 path = path[index + 1:] |
|
300 pathlen = len(path) |
|
301 try: |
|
302 index = path.index(b'%') |
|
303 except ValueError: |
|
304 res += b'%' + path |
|
305 index = pathlen - 1 |
|
306 else: |
|
307 var = path[:index] |
|
308 res += b'%' + var + b'%' |
|
309 elif c == b'$': # variable or '$$' |
|
310 if path[index + 1:index + 2] == b'$': |
|
311 res += c |
|
312 index += 1 |
|
313 elif path[index + 1:index + 2] == b'{': |
|
314 path = path[index + 2:] |
|
315 pathlen = len(path) |
|
316 try: |
|
317 index = path.index(b'}') |
|
318 var = path[:index] |
|
319 |
|
320 # See below for why empty variables are handled specially |
|
321 if env.get(var, '') != '': |
|
322 res += b'%' + var + b'%' |
|
323 else: |
|
324 res += b'${' + var + b'}' |
|
325 except ValueError: |
|
326 res += b'${' + path |
|
327 index = pathlen - 1 |
|
328 else: |
|
329 var = b'' |
|
330 index += 1 |
|
331 c = path[index:index + 1] |
|
332 while c != b'' and c in varchars: |
|
333 var += c |
|
334 index += 1 |
|
335 c = path[index:index + 1] |
|
336 # Some variables (like HG_OLDNODE) may be defined, but have an |
|
337 # empty value. Those need to be skipped because when spawning |
|
338 # cmd.exe to run the hook, it doesn't replace %VAR% for an empty |
|
339 # VAR, and that really confuses things like revset expressions. |
|
340 # OTOH, if it's left in Unix format and the hook runs sh.exe, it |
|
341 # will substitute to an empty string, and everything is happy. |
|
342 if env.get(var, '') != '': |
|
343 res += b'%' + var + b'%' |
|
344 else: |
|
345 res += b'$' + var |
|
346 |
|
347 if c != '': |
|
348 index -= 1 |
|
349 elif c == b'\\' and index + 1 < pathlen and path[index + 1] == b'$': |
|
350 # Skip '\', but only if it is escaping $ |
|
351 res += b'$' |
|
352 index += 1 |
|
353 else: |
|
354 res += c |
|
355 |
|
356 index += 1 |
|
357 return res |
255 |
358 |
256 # A sequence of backslashes is special iff it precedes a double quote: |
359 # A sequence of backslashes is special iff it precedes a double quote: |
257 # - if there's an even number of backslashes, the double quote is not |
360 # - if there's an even number of backslashes, the double quote is not |
258 # quoted (i.e. it ends the quoted region) |
361 # quoted (i.e. it ends the quoted region) |
259 # - if there's an odd number of backslashes, the double quote is quoted |
362 # - if there's an odd number of backslashes, the double quote is quoted |