From bbed17fe07b30a4d54e95b3bfb4c646819ce3b6b Mon Sep 17 00:00:00 2001 From: Vladimir Iakovlev Date: Thu, 9 Feb 2017 16:09:37 +0100 Subject: [PATCH] #N/A: Add `sudo_command_from_user_path` rule --- README.md | 1 + .../rules/test_sudo_command_from_user_path.py | 39 +++++++++++++++++++ thefuck/rules/sudo_command_from_user_path.py | 21 ++++++++++ 3 files changed, 61 insertions(+) create mode 100644 tests/rules/test_sudo_command_from_user_path.py create mode 100644 thefuck/rules/sudo_command_from_user_path.py diff --git a/README.md b/README.md index 0aeae4f1..5498bba8 100644 --- a/README.md +++ b/README.md @@ -235,6 +235,7 @@ using the matched rule and runs it. Rules enabled by default are as follows: * `sl_ls` – changes `sl` to `ls`; * `ssh_known_hosts` – removes host from `known_hosts` on warning; * `sudo` – prepends `sudo` to previous command if it failed because of permissions; +* `sudo_command_from_user_path` – runs commands from users `$PATH` with `sudo`; * `switch_lang` – switches command from your local layout to en; * `systemctl` – correctly orders parameters of confusing `systemctl`; * `test.py` – runs `py.test` instead of `test.py`; diff --git a/tests/rules/test_sudo_command_from_user_path.py b/tests/rules/test_sudo_command_from_user_path.py new file mode 100644 index 00000000..7d6dacee --- /dev/null +++ b/tests/rules/test_sudo_command_from_user_path.py @@ -0,0 +1,39 @@ +import pytest +from thefuck.rules.sudo_command_from_user_path import match, get_new_command +from tests.utils import Command + + +stderr = 'sudo: {}: command not found' + + +@pytest.fixture(autouse=True) +def which(mocker): + return mocker.patch('thefuck.rules.sudo_command_from_user_path.which', + return_value='/usr/bin/app') + + +@pytest.mark.parametrize('script, stderr', [ + ('sudo npm install -g react-native-cli', stderr.format('npm')), + ('sudo -u app appcfg update .', stderr.format('appcfg'))]) +def test_match(script, stderr): + assert match(Command(script, stderr=stderr)) + + +@pytest.mark.parametrize('script, stderr, which_result', [ + ('npm --version', stderr.format('npm'), '/usr/bin/npm'), + ('sudo npm --version', '', '/usr/bin/npm'), + ('sudo npm --version', stderr.format('npm'), None)]) +def test_not_match(which, script, stderr, which_result): + which.return_value = which_result + assert not match(Command(script, stderr=stderr)) + + +@pytest.mark.parametrize('script, stderr, result', [ + ('sudo npm install -g react-native-cli', + stderr.format('npm'), + 'sudo env "PATH=$PATH" npm install -g react-native-cli'), + ('sudo -u app appcfg update .', + stderr.format('appcfg'), + 'sudo -u app env "PATH=$PATH" appcfg update .')]) +def test_get_new_command(script, stderr, result): + assert get_new_command(Command(script, stderr=stderr)) == result diff --git a/thefuck/rules/sudo_command_from_user_path.py b/thefuck/rules/sudo_command_from_user_path.py new file mode 100644 index 00000000..39ddace9 --- /dev/null +++ b/thefuck/rules/sudo_command_from_user_path.py @@ -0,0 +1,21 @@ +import re +from thefuck.utils import for_app, which, replace_argument + + +def _get_command_name(command): + found = re.findall(r'sudo: (.*): command not found', command.stderr) + if found: + return found[0] + + +@for_app('sudo') +def match(command): + if 'command not found' in command.stderr: + command_name = _get_command_name(command) + return which(command_name) + + +def get_new_command(command): + command_name = _get_command_name(command) + return replace_argument(command.script, command_name, + u'env "PATH=$PATH" {}'.format(command_name))