From e798f64ffde20c549e2e0df5834e4194c74adb0a Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Sat, 15 Feb 2020 15:33:19 -0500 Subject: [PATCH] Use shlex.quote for quoting shell arguments --- CHANGES.rst | 2 ++ click/_compat.py | 4 ++++ click/_termui_impl.py | 28 ++++++++++++++-------------- tests/test_imports.py | 2 +- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index b8e6a4486..0d4f40941 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -55,6 +55,8 @@ Unreleased distinguish it from the next option. :issue:`1075` - Consider ``sensible-editor`` when determining the editor to use for ``click.edit()``. :pr:`1469` +- Arguments to system calls such as the executable path passed to + ``click.edit`` can contains spaces. :pr:`1470` Version 7.0 diff --git a/click/_compat.py b/click/_compat.py index f8efb2979..676285448 100644 --- a/click/_compat.py +++ b/click/_compat.py @@ -162,6 +162,8 @@ def seekable(self): iteritems = lambda x: x.iteritems() range_type = xrange + from pipes import quote as shlex_quote + def is_bytes(x): return isinstance(x, (buffer, bytearray)) @@ -268,6 +270,8 @@ def filename_to_ui(value): isidentifier = lambda x: x.isidentifier() iteritems = lambda x: iter(x.items()) + from shlex import quote as shlex_quote + def is_bytes(x): return isinstance(x, (bytes, memoryview, bytearray)) diff --git a/click/_termui_impl.py b/click/_termui_impl.py index 66668213b..09e9fbb12 100644 --- a/click/_termui_impl.py +++ b/click/_termui_impl.py @@ -16,9 +16,9 @@ import time import math import contextlib -from ._compat import _default_text_stdout, range_type, PY2, isatty, \ - open_stream, strip_ansi, term_len, get_best_encoding, WIN, int_types, \ - CYGWIN +from ._compat import _default_text_stdout, range_type, isatty, \ + open_stream, shlex_quote, strip_ansi, term_len, get_best_encoding, WIN, \ + int_types, CYGWIN from .utils import echo from .exceptions import ClickException @@ -328,7 +328,7 @@ def pager(generator, color=None): fd, filename = tempfile.mkstemp() os.close(fd) try: - if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0: + if hasattr(os, 'system') and os.system("more %s" % shlex_quote(filename)) == 0: return _pipepager(generator, 'more', color) return _nullpager(stdout, generator, color) finally: @@ -396,7 +396,7 @@ def _tempfilepager(generator, cmd, color): with open_stream(filename, 'wb')[0] as f: f.write(text.encode(encoding)) try: - os.system(cmd + ' "' + filename + '"') + os.system("%s %s" % (shlex_quote(cmd), shlex_quote(filename))) finally: os.unlink(filename) @@ -441,8 +441,11 @@ def edit_file(self, filename): else: environ = None try: - c = subprocess.Popen('%s "%s"' % (editor, filename), - env=environ, shell=True) + c = subprocess.Popen( + "%s %s" % (shlex_quote(editor), shlex_quote(filename)), + env=environ, + shell=True + ) exit_code = c.wait() if exit_code != 0: raise ClickException('%s: Editing failed!' % editor) @@ -513,19 +516,16 @@ def _unquote_file(url): elif WIN: if locate: url = _unquote_file(url) - args = 'explorer /select,"%s"' % _unquote_file( - url.replace('"', '')) + args = "explorer /select,%s" % (shlex_quote(url),) else: - args = 'start %s "" "%s"' % ( - wait and '/WAIT' or '', url.replace('"', '')) + args = 'start %s "" %s' % ("/WAIT" if wait else "", shlex_quote(url)) return os.system(args) elif CYGWIN: if locate: url = _unquote_file(url) - args = 'cygstart "%s"' % (os.path.dirname(url).replace('"', '')) + args = "cygstart %s" % (shlex_quote(os.path.dirname(url)),) else: - args = 'cygstart %s "%s"' % ( - wait and '-w' or '', url.replace('"', '')) + args = "cygstart %s %s" % ("-w" if wait else "", shlex_quote(url)) return os.system(args) try: diff --git a/tests/test_imports.py b/tests/test_imports.py index 8e9a97df6..268c60688 100644 --- a/tests/test_imports.py +++ b/tests/test_imports.py @@ -32,7 +32,7 @@ def tracking_import(module, locals=None, globals=None, fromlist=None, ALLOWED_IMPORTS = set([ 'weakref', 'os', 'struct', 'collections', 'sys', 'contextlib', 'functools', 'stat', 're', 'codecs', 'inspect', 'itertools', 'io', - 'threading', 'colorama', 'errno', 'fcntl', 'datetime' + 'threading', 'colorama', 'errno', 'fcntl', 'datetime', 'pipes', 'shlex' ]) if WIN: