Skip to content

Commit

Permalink
Quote arguments with carets for cmd.exe
Browse files Browse the repository at this point in the history
Carets introduce a difficult situation since they are essentially
"lossy" when parses. Consider this in cmd.exe:

    > echo "foo^bar"
    "foo^bar"
    > echo foo^^bar
    foo^bar

The two commands produce different results, but are both parsed by the
shell as `foo^bar`, and there's essentially no sensible way to tell what
was actually passed in. This implementation assumes the quoted variation
(the first) since it is easier to implement, and arguably the more common
case.

Fix #3307.
  • Loading branch information
uranusjr committed Nov 28, 2018
1 parent f4c325c commit 94d6fd6
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 2 deletions.
19 changes: 17 additions & 2 deletions pipenv/cmdparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,29 @@ def cmdify(self):
Foul characters include:
* Whitespaces.
* Carets (^). (pypa/pipenv#3307)
* Parentheses in the command. (pypa/pipenv#3168)
Carets introduce a difficult situation since they are essentially
"lossy" when parses. Consider this in cmd.exe::
> echo "foo^bar"
"foo^bar"
> echo foo^^bar
foo^bar
The two commands produce different results, but are both parsed by the
shell as `foo^bar`, and there's essentially no sensible way to tell
what was actually passed in. This implementation assumes the quoted
variation (the first) since it is easier to implement, and arguably
the more common case.
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(itertools.chain(
[_quote_if_contains(self.command, r'[\s()]')],
(_quote_if_contains(arg, r'\s') for arg in self.args),
[_quote_if_contains(self.command, r'[\s^()]')],
(_quote_if_contains(arg, r'[\s^]') for arg in self.args),
))
9 changes: 9 additions & 0 deletions tests/unit/test_cmdparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,12 @@ def test_cmdify_quote_if_paren_in_command():
'-c',
"print(123)",
]), script


@pytest.mark.run
@pytest.mark.script
def test_cmdify_quote_if_carets():
"""Ensure arguments are quoted if they contain carets.
"""
script = Script('foo^bar', ['baz^rex'])
assert script.cmdify() == '"foo^bar" "baz^rex"', script

0 comments on commit 94d6fd6

Please sign in to comment.