diff --git a/README.md b/README.md index be3420a1..532df6be 100644 --- a/README.md +++ b/README.md @@ -273,13 +273,13 @@ following rules are enabled by default: * `npm_wrong_command` – fixes wrong npm commands like `npm urgrade`; * `no_command` – fixes wrong console commands, for example `vom/vim`; * `no_such_file` – creates missing directories with `mv` and `cp` commands; +* `omnienv_no_such_command` – fixes wrong commands for `goenv`, `nodenv`, `pyenv` and `rbenv` (eg.: `pyenv isntall` or `goenv list`); * `open` – either prepends `http://` to address passed to `open` or create a new file or directory and passes it to `open`; * `pip_install` – fixes permission issues with `pip install` commands by adding `--user` or prepending `sudo` if necessary; * `pip_unknown_command` – fixes wrong `pip` commands, for example `pip instatl/pip install`; * `php_s` – replaces `-s` by `-S` when trying to run a local php server; * `port_already_in_use` – kills process that bound port; * `prove_recursively` – adds `-r` when called with directory; -* `pyenv_no_such_command` – fixes wrong pyenv commands like `pyenv isntall` or `pyenv list`; * `python_command` – prepends `python` when you try to run non-executable/without `./` python script; * `python_execute` – appends missing `.py` when executing Python files; * `python_module_error` – fixes ModuleNotFoundError by trying to `pip install` that module; diff --git a/tests/rules/test_pyenv_no_such_command.py b/tests/rules/test_omnienv_no_such_command.py similarity index 84% rename from tests/rules/test_pyenv_no_such_command.py rename to tests/rules/test_omnienv_no_such_command.py index 298620f7..45f84a6c 100644 --- a/tests/rules/test_pyenv_no_such_command.py +++ b/tests/rules/test_omnienv_no_such_command.py @@ -1,6 +1,6 @@ import pytest -from thefuck.rules.pyenv_no_such_command import get_new_command, match +from thefuck.rules.omnienv_no_such_command import get_new_command, match from thefuck.types import Command @@ -11,7 +11,7 @@ def output(pyenv_cmd): @pytest.fixture(autouse=True) def Popen(mocker): - mock = mocker.patch('thefuck.rules.pyenv_no_such_command.Popen') + mock = mocker.patch('thefuck.rules.omnienv_no_such_command.Popen') mock.return_value.stdout.readlines.return_value = ( b'--version\nactivate\ncommands\ncompletions\ndeactivate\nexec_\n' b'global\nhelp\nhooks\ninit\ninstall\nlocal\nprefix_\n' @@ -33,6 +33,11 @@ def test_match(script, pyenv_cmd, output): assert match(Command(script, output=output)) +def test_match_goenv_output_quote(): + """test goenv's specific output with quotes (')""" + assert match(Command('goenv list', output="goenv: no such command 'list'")) + + @pytest.mark.parametrize('script, output', [ ('pyenv global', 'system'), ('pyenv versions', ' 3.7.0\n 3.7.1\n* 3.7.2\n'), diff --git a/thefuck/rules/pyenv_no_such_command.py b/thefuck/rules/omnienv_no_such_command.py similarity index 50% rename from thefuck/rules/pyenv_no_such_command.py rename to thefuck/rules/omnienv_no_such_command.py index cc9b609e..ca8cc36d 100644 --- a/thefuck/rules/pyenv_no_such_command.py +++ b/thefuck/rules/omnienv_no_such_command.py @@ -1,8 +1,12 @@ import re -from subprocess import PIPE, Popen - from thefuck.utils import (cache, for_app, replace_argument, replace_command, which) +from subprocess import PIPE, Popen + + +supported_apps = 'goenv', 'nodenv', 'pyenv', 'rbenv' +enabled_by_default = any(which(a) for a in supported_apps) + COMMON_TYPOS = { 'list': ['versions', 'install --list'], @@ -10,24 +14,22 @@ COMMON_TYPOS = { } -@for_app('pyenv') +@for_app(*supported_apps, at_least=1) def match(command): - return 'pyenv: no such command' in command.output + return 'env: no such command ' in command.output -def get_pyenv_commands(): - proc = Popen(['pyenv', 'commands'], stdout=PIPE) +def get_app_commands(app): + proc = Popen([app, 'commands'], stdout=PIPE) return [line.decode('utf-8').strip() for line in proc.stdout.readlines()] -if which('pyenv'): - get_pyenv_commands = cache(which('pyenv'))(get_pyenv_commands) - - -@for_app('pyenv') def get_new_command(command): - broken = re.findall(r"pyenv: no such command `([^']*)'", command.output)[0] + broken = re.findall(r"env: no such command ['`]([^']*)'", command.output)[0] matched = [replace_argument(command.script, broken, common_typo) for common_typo in COMMON_TYPOS.get(broken, [])] - matched.extend(replace_command(command, broken, get_pyenv_commands())) + + app = command.script_parts[0] + app_commands = cache(which(app))(get_app_commands)(app) + matched.extend(replace_command(command, broken, app_commands)) return matched