Skip to content

Commit

Permalink
Implement option to disable shell escaping.
Browse files Browse the repository at this point in the history
  • Loading branch information
christianmlong committed Mar 19, 2013
1 parent fbc49dd commit 8bc8d4c
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 12 deletions.
36 changes: 27 additions & 9 deletions fabric/operations.py
Expand Up @@ -595,7 +595,7 @@ def _sudo_prefix(user, group=None):
return prefix


def _shell_wrap(command, shell=True, sudo_prefix=None):
def _shell_wrap(command, shell_escape, shell=True, sudo_prefix=None):
"""
Conditionally wrap given command in env.shell (while honoring sudo.)
"""
Expand All @@ -608,11 +608,13 @@ def _shell_wrap(command, shell=True, sudo_prefix=None):
sudo_prefix = ""
else:
sudo_prefix += " "
# If we're shell wrapping, prefix shell and space, escape the command and
# then quote it. Otherwise, empty string.
# If we're shell wrapping, prefix shell and space. Next, escape the command
# if requested, and then quote it. Otherwise, empty string.
if shell:
shell = env.shell + " "
command = '"%s"' % _shell_escape(command)
if shell_escape:
command = _shell_escape(command)
command = '"%s"' % command
else:
shell = ""
# Resulting string should now have correct formatting
Expand Down Expand Up @@ -860,7 +862,7 @@ def _noop():

def _run_command(command, shell=True, pty=True, combine_stderr=True,
sudo=False, user=None, quiet=False, warn_only=False, stdout=None,
stderr=None, group=None, timeout=None):
stderr=None, group=None, timeout=None, shell_escape=None):
"""
Underpinnings of `run` and `sudo`. See their docstrings for more info.
"""
Expand All @@ -873,9 +875,15 @@ def _run_command(command, shell=True, pty=True, combine_stderr=True,
with manager():
# Set up new var so original argument can be displayed verbatim later.
given_command = command

# Check if shell_escape has been overridden in env
if shell_escape is None:
shell_escape = env.get('shell_escape', True)

# Handle context manager modifications, and shell wrapping
wrapped_command = _shell_wrap(
_prefix_commands(_prefix_env_vars(command), 'remote'),
shell_escape,
shell,
_sudo_prefix(user, group) if sudo else None
)
Expand Down Expand Up @@ -928,7 +936,7 @@ def _run_command(command, shell=True, pty=True, combine_stderr=True,

@needs_host
def run(command, shell=True, pty=True, combine_stderr=None, quiet=False,
warn_only=False, stdout=None, stderr=None, timeout=None):
warn_only=False, stdout=None, stderr=None, timeout=None, shell_escape=None):
"""
Run a shell command on a remote host.
Expand Down Expand Up @@ -985,6 +993,9 @@ def run(command, shell=True, pty=True, combine_stderr=None, quiet=False,
after which to time out. This will cause ``run`` to raise a
`~fabric.exceptions.CommandTimeout` exception.
If you want to disable Fabric's automatic attempts at escaping quotes,
dollar signs etc., specify ``shell_escape=False``.
Examples::
run("ls /var/www/")
Expand Down Expand Up @@ -1012,15 +1023,19 @@ def run(command, shell=True, pty=True, combine_stderr=None, quiet=False,
.. versionadded:: 1.6
The ``timeout`` argument.
.. versionadded:: 1.7
The ``shell_escape`` argument.
"""
return _run_command(command, shell, pty, combine_stderr, quiet=quiet,
warn_only=warn_only, stdout=stdout, stderr=stderr, timeout=timeout)
warn_only=warn_only, stdout=stdout, stderr=stderr, timeout=timeout,
shell_escape=shell_escape)


@needs_host
def sudo(command, shell=True, pty=True, combine_stderr=None, user=None,
quiet=False, warn_only=False, stdout=None, stderr=None, group=None,
timeout=None):
timeout=None, shell_escape=None):
"""
Run a shell command on a remote host, with superuser privileges.
Expand Down Expand Up @@ -1059,12 +1074,15 @@ def sudo(command, shell=True, pty=True, combine_stderr=None, user=None,
.. versionadded:: 1.5
The return value attributes ``.command`` and ``.real_command``.
.. versionadded:: 1.7
The ``shell_escape`` argument.
"""
return _run_command(
command, shell, pty, combine_stderr, sudo=True,
user=user if user else env.sudo_user,
group=group, quiet=quiet, warn_only=warn_only, stdout=stdout,
stderr=stderr, timeout=timeout
stderr=stderr, timeout=timeout, shell_escape=shell_escape,
)


Expand Down
18 changes: 15 additions & 3 deletions tests/test_operations.py
Expand Up @@ -250,7 +250,7 @@ def test_shell_wrap():
False, prefix, prefix + " " + command),
):
eq_.description = "_shell_wrap: %s" % description
yield eq_, _shell_wrap(command, shell, sudo_prefix), result
yield eq_, _shell_wrap(command, shell_escape=True, shell=shell, sudo_prefix=sudo_prefix), result
del eq_.description


Expand All @@ -261,17 +261,29 @@ def test_shell_wrap_escapes_command_if_shell_is_true():
"""
cmd = "cd \"Application Support\""
eq_(
_shell_wrap(cmd, shell=True),
_shell_wrap(cmd, shell_escape=True, shell=True),
'%s "%s"' % (env.shell, _shell_escape(cmd))
)


@with_settings(use_shell=True)
def test_shell_wrap_does_not_escape_command_if_shell_is_true_and_shell_escape_is_false():
"""
_shell_wrap() does no escaping if shell=True and shell_escape=False
"""
cmd = "cd \"Application Support\""
eq_(
_shell_wrap(cmd, shell_escape=False, shell=True),
'%s "%s"' % (env.shell, cmd)
)


def test_shell_wrap_does_not_escape_command_if_shell_is_false():
"""
_shell_wrap() does no escaping if shell=False
"""
cmd = "cd \"Application Support\""
eq_(_shell_wrap(cmd, shell=False), cmd)
eq_(_shell_wrap(cmd, shell_escape=True, shell=False), cmd)


def test_shell_escape_escapes_doublequotes():
Expand Down

0 comments on commit 8bc8d4c

Please sign in to comment.