diff --git a/tests/rules/test_git_push.py b/tests/rules/test_git_push.py index d452b028..7504a72a 100644 --- a/tests/rules/test_git_push.py +++ b/tests/rules/test_git_push.py @@ -14,11 +14,11 @@ To push the current branch and set the remote as upstream, use def test_match(stderr): - assert match(Command('git push master', '', stderr)) - assert not match(Command('git push master', '', '')) - assert not match(Command('ls', '', stderr)) + assert match(Command('git push master', '', stderr), None) + assert not match(Command('git push master', '', ''), None) + assert not match(Command('ls', '', stderr), None) def test_get_new_command(stderr): - assert get_new_command(Command('', '', stderr))\ + assert get_new_command(Command('', '', stderr), None)\ == "git push --set-upstream origin master" diff --git a/tests/rules/test_no_command.py b/tests/rules/test_no_command.py index a24d9bbb..6af1a32f 100644 --- a/tests/rules/test_no_command.py +++ b/tests/rules/test_no_command.py @@ -1,4 +1,4 @@ -from unittest.mock import patch +from unittest.mock import patch, Mock import pytest from subprocess import PIPE from thefuck.rules.no_command import match, get_new_command @@ -22,23 +22,24 @@ vom: command not found def test_match(command_found, command_not_found): with patch('thefuck.rules.no_command.Popen') as Popen: Popen.return_value.stderr.read.return_value = command_found - assert match(Command('aptget install vim', '', '')) + assert match(Command('aptget install vim', '', ''), None) Popen.assert_called_once_with('/usr/lib/command-not-found aptget', shell=True, stderr=PIPE) Popen.return_value.stderr.read.return_value = command_not_found - assert not match(Command('ls', '', '')) + assert not match(Command('ls', '', ''), None) with patch('thefuck.rules.no_command.Popen') as Popen: Popen.return_value.stderr.read.return_value = command_found - assert match(Command('sudo aptget install vim', '', '')) - Popen.assert_called_once_with('/usr/lib/command-not-found aptget', + assert match(Command('sudo aptget install vim', '', ''), + Mock(command_not_found='test')) + Popen.assert_called_once_with('test aptget', shell=True, stderr=PIPE) def test_get_new_command(command_found): with patch('thefuck.rules.no_command._get_output', return_value=command_found.decode()): - assert get_new_command(Command('aptget install vim', '', ''))\ + assert get_new_command(Command('aptget install vim', '', ''), None)\ == 'apt-get install vim' - assert get_new_command(Command('sudo aptget install vim', '', '')) \ + assert get_new_command(Command('sudo aptget install vim', '', ''), None) \ == 'sudo apt-get install vim' diff --git a/tests/rules/test_sudo.py b/tests/rules/test_sudo.py index 85ac3ffd..4f0c8318 100644 --- a/tests/rules/test_sudo.py +++ b/tests/rules/test_sudo.py @@ -3,11 +3,11 @@ from thefuck.rules.sudo import match, get_new_command def test_match(): - assert match(Command('', '', 'Permission denied')) - assert match(Command('', '', 'permission denied')) - assert match(Command('', '', "npm ERR! Error: EACCES, unlink")) - assert not match(Command('', '', '')) + assert match(Command('', '', 'Permission denied'), None) + assert match(Command('', '', 'permission denied'), None) + assert match(Command('', '', "npm ERR! Error: EACCES, unlink"), None) + assert not match(Command('', '', ''), None) def test_get_new_command(): - assert get_new_command(Command('ls', '', '')) == 'sudo ls' + assert get_new_command(Command('ls', '', ''), None) == 'sudo ls' diff --git a/tests/test_main.py b/tests/test_main.py index 2e7c8bbe..9bbfbd4c 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -27,9 +27,9 @@ def test_get_settings(): def test_is_rule_enabled(): - assert main.is_rule_enabled(main.Settings(None), Path('bash.py')) - assert main.is_rule_enabled(main.Settings(['bash']), Path('bash.py')) - assert not main.is_rule_enabled(main.Settings(['bash']), Path('lisp.py')) + assert main.is_rule_enabled(Mock(rules=None), Path('bash.py')) + assert main.is_rule_enabled(Mock(rules=['bash']), Path('bash.py')) + assert not main.is_rule_enabled(Mock(rules=['bash']), Path('lisp.py')) def test_load_rule(): @@ -50,13 +50,13 @@ def test_get_rules(): glob.return_value = [PosixPath('bash.py'), PosixPath('lisp.py')] assert main.get_rules( Path('~'), - main.Settings(None)) == [main.Rule('bash', 'bash'), + Mock(rules=None)) == [main.Rule('bash', 'bash'), main.Rule('lisp', 'lisp'), main.Rule('bash', 'bash'), main.Rule('lisp', 'lisp')] assert main.get_rules( Path('~'), - main.Settings(['bash'])) == [main.Rule('bash', 'bash'), + Mock(rules=['bash'])) == [main.Rule('bash', 'bash'), main.Rule('bash', 'bash')] @@ -73,9 +73,9 @@ def test_get_command(): def test_get_matched_rule(): - rules = [main.Rule(lambda x: x.script == 'cd ..', None), - main.Rule(lambda _: False, None)] + rules = [main.Rule(lambda x, _: x.script == 'cd ..', None), + main.Rule(lambda _, _: False, None)] assert main.get_matched_rule(main.Command('ls', '', ''), - rules) is None + rules, None) is None assert main.get_matched_rule(main.Command('cd ..', '', ''), - rules) == rules[0] + rules, None) == rules[0] diff --git a/thefuck/main.py b/thefuck/main.py index c1c0775e..1f48faf7 100644 --- a/thefuck/main.py +++ b/thefuck/main.py @@ -2,13 +2,11 @@ from collections import namedtuple from imp import load_source from pathlib import Path from os.path import expanduser -from os import environ from subprocess import Popen, PIPE import sys Command = namedtuple('Command', ('script', 'stdout', 'stderr')) -Settings = namedtuple('Settings', ('rules',)) Rule = namedtuple('Rule', ('match', 'get_new_command')) @@ -22,14 +20,16 @@ def setup_user_dir() -> Path: return user_dir -def get_settings(user_dir: Path) -> Settings: +def get_settings(user_dir: Path): """Returns prepared settings module.""" settings = load_source('settings', str(user_dir.joinpath('settings.py'))) - return Settings(getattr(settings, 'rules', None)) + if not hasattr(settings, 'rules'): + settings.rules = None + return settings -def is_rule_enabled(settings: Settings, rule: Path) -> bool: +def is_rule_enabled(settings, rule: Path) -> bool: """Returns `True` when rule mentioned in `rules` or `rules` isn't defined. @@ -43,7 +43,7 @@ def load_rule(rule: Path) -> Rule: return Rule(rule_module.match, rule_module.get_new_command) -def get_rules(user_dir: Path, settings: Settings) -> [Rule]: +def get_rules(user_dir: Path, settings) -> [Rule]: """Returns all enabled rules.""" bundled = Path(__file__).parent\ .joinpath('rules')\ @@ -61,16 +61,16 @@ def get_command(args: [str]) -> Command: result.stderr.read().decode()) -def get_matched_rule(command: Command, rules: [Rule]) -> Rule: +def get_matched_rule(command: Command, rules: [Rule], settings) -> Rule: """Returns first matched rule for command.""" for rule in rules: - if rule.match(command): + if rule.match(command, settings): return rule -def run_rule(rule: Rule, command: Command): +def run_rule(rule: Rule, command: Command, settings): """Runs command from rule for passed command.""" - new_command = rule.get_new_command(command) + new_command = rule.get_new_command(command, settings) print(new_command) @@ -79,8 +79,8 @@ def main(): user_dir = setup_user_dir() settings = get_settings(user_dir) rules = get_rules(user_dir, settings) - matched_rule = get_matched_rule(command, rules) + matched_rule = get_matched_rule(command, rules, settings) if matched_rule: - run_rule(matched_rule, command) + run_rule(matched_rule, command, settings) else: print('echo No fuck given') diff --git a/thefuck/rules/git_push.py b/thefuck/rules/git_push.py index 48bbc70f..bb9818f1 100644 --- a/thefuck/rules/git_push.py +++ b/thefuck/rules/git_push.py @@ -1,8 +1,8 @@ -def match(command): +def match(command, settings): return ('git' in command.script and 'push' in command.script and 'set-upstream' in command.stderr) -def get_new_command(command): +def get_new_command(command, settings): return command.stderr.split('\n')[-3].strip() diff --git a/thefuck/rules/no_command.py b/thefuck/rules/no_command.py index f7ded058..6e2bb361 100644 --- a/thefuck/rules/no_command.py +++ b/thefuck/rules/no_command.py @@ -2,20 +2,22 @@ from subprocess import Popen, PIPE import re -def _get_output(command): +def _get_output(command, settings): name = command.script.split(' ')[command.script.startswith('sudo')] - check_script = '/usr/lib/command-not-found {}'.format(name) + check_script = '{} {}'.format(getattr(settings, 'command_not_found', + '/usr/lib/command-not-found'), + name) result = Popen(check_script, shell=True, stderr=PIPE) return result.stderr.read().decode() -def match(command): - output = _get_output(command) +def match(command, settings): + output = _get_output(command, settings) return "No command" in output and "from package" in output -def get_new_command(command): - output = _get_output(command) +def get_new_command(command, settings): + output = _get_output(command, settings) broken_name = re.findall(r"No command '([^']*)' found", output)[0] fixed_name = re.findall(r"Command '([^']*)' from package", diff --git a/thefuck/rules/sudo.py b/thefuck/rules/sudo.py index 7d93b8c9..47537265 100644 --- a/thefuck/rules/sudo.py +++ b/thefuck/rules/sudo.py @@ -1,7 +1,7 @@ -def match(command): +def match(command, settings): return ('permission denied' in command.stderr.lower() or 'EACCES' in command.stderr) -def get_new_command(command): +def get_new_command(command, settings): return 'sudo {}'.format(command.script)