mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
Quote command if it contains parentheses
The command can be safely quoted in this case since non-quotable commands (cmd built-in) do not have parentheses. Note that this change only applies to the command, not arguments. Parentheses in arguments can be correctly interpreted without quotes, and the quotes, like spaces, will cause incorrect outputs for echo etc.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Fix package installation when the virtual environment path contains parentheses.
|
||||
+17
-6
@@ -1,3 +1,4 @@
|
||||
import itertools
|
||||
import re
|
||||
import shlex
|
||||
|
||||
@@ -8,6 +9,12 @@ class ScriptEmptyError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
def _quote_if_contains(value, pattern):
|
||||
if next(re.finditer(pattern, value), None):
|
||||
return '"{0}"'.format(re.sub(r'(\\*)"', r'\1\1\\"', value))
|
||||
return value
|
||||
|
||||
|
||||
class Script(object):
|
||||
"""Parse a script line (in Pipfile's [scripts] section).
|
||||
|
||||
@@ -56,17 +63,21 @@ class Script(object):
|
||||
The result is then quoted into a pair of double quotes to be grouped.
|
||||
|
||||
An argument is intentionally not quoted if it does not contain
|
||||
whitespaces. This is done to be compatible with Windows built-in
|
||||
foul characters. This is done to be compatible with Windows built-in
|
||||
commands that don't work well with quotes, e.g. everything with `echo`,
|
||||
and DOS-style (forward slash) switches.
|
||||
|
||||
Foul characters include:
|
||||
|
||||
* Whitespaces.
|
||||
* Parentheses in the command. (pypa/pipenv#3168)
|
||||
|
||||
The intended use of this function is to pre-process an argument list
|
||||
before passing it into ``subprocess.Popen(..., shell=True)``.
|
||||
|
||||
See also: https://docs.python.org/3/library/subprocess.html#converting-argument-sequence
|
||||
"""
|
||||
return " ".join(
|
||||
arg if not next(re.finditer(r'\s', arg), None)
|
||||
else '"{0}"'.format(re.sub(r'(\\*)"', r'\1\1\\"', arg))
|
||||
for arg in self._parts
|
||||
)
|
||||
return " ".join(itertools.chain(
|
||||
[_quote_if_contains(self.command, r'[\s()]')],
|
||||
(_quote_if_contains(arg, r'\s') for arg in self.args),
|
||||
))
|
||||
|
||||
@@ -47,3 +47,20 @@ def test_cmdify_complex():
|
||||
'-c',
|
||||
""" "print(\'Double quote: \\\"\')" """.strip(),
|
||||
]), script
|
||||
|
||||
|
||||
@pytest.mark.run
|
||||
@pytest.mark.script
|
||||
def test_cmdify_quote_if_paren_in_command():
|
||||
"""Ensure ONLY the command is quoted if it contains parentheses.
|
||||
"""
|
||||
script = Script.parse(' '.join([
|
||||
'"C:\\Python36(x86)\\python.exe"',
|
||||
'-c',
|
||||
"print(123)",
|
||||
]))
|
||||
assert script.cmdify() == ' '.join([
|
||||
'"C:\\Python36(x86)\\python.exe"',
|
||||
'-c',
|
||||
"print(123)",
|
||||
]), script
|
||||
|
||||
Reference in New Issue
Block a user