mirror of
https://github.com/nvbn/thefuck.git
synced 2025-11-03 00:22:10 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f082ba829f | ||
|
|
112e20d7c5 | ||
|
|
95007220fb | ||
|
|
56f636f3d8 | ||
|
|
932a7c5db5 | ||
|
|
1bed4d4e8d | ||
|
|
e0bba379ff | ||
|
|
045959ec47 | ||
|
|
65aeea857e | ||
|
|
793e883073 | ||
|
|
a395ac568c | ||
|
|
29e70e14a0 | ||
|
|
0cdd23edcf | ||
|
|
36d80859a4 | ||
|
|
2b12b4bfce | ||
|
|
91c1fe414a |
@@ -144,14 +144,17 @@ using matched rule and run it. Rules enabled by default:
|
||||
* `cd_parent` – changes `cd..` to `cd ..`;
|
||||
* `cd_mkdir` – creates directories before cd'ing into them;
|
||||
* `cp_omitting_directory` – adds `-a` when you `cp` directory;
|
||||
* `dry` – fix repetitions like "git git push";
|
||||
* `fix_alt_space` – replaces Alt+Space with Space character;
|
||||
* `git_add` – fix *"Did you forget to 'git add'?"*;
|
||||
* `git_checkout` – creates the branch before checking-out;
|
||||
* `git_no_command` – fixes wrong git commands like `git brnch`;
|
||||
* `git_push` – adds `--set-upstream origin $branch` to previous failed `git push`;
|
||||
* `has_exists_script` – prepends `./` when script/binary exists;
|
||||
* `lein_not_task` – fixes wrong `lein` tasks like `lein rpl`;
|
||||
* `mkdir_p` – adds `-p` when you trying to create directory without parent;
|
||||
* `no_command` – fixes wrong console commands, for example `vom/vim`;
|
||||
* `man_no_space` – fixes man commands without spaces, for example `mandiff`;
|
||||
* `pacman` – installs app with `pacman` or `yaourt` if it is not installed;
|
||||
* `pip_unknown_command` – fixes wrong pip commands, for example `pip instatl/pip install`;
|
||||
* `python_command` – prepends `python` when you trying to run not executable/without `./` python script;
|
||||
@@ -193,13 +196,13 @@ def match(command, settings):
|
||||
|
||||
def get_new_command(command, settings):
|
||||
return 'sudo {}'.format(command.script)
|
||||
|
||||
|
||||
# Optional:
|
||||
enabled_by_default = True
|
||||
|
||||
def side_effect(command, settings):
|
||||
subprocess.call('chmod 777 .', shell=True)
|
||||
|
||||
|
||||
priority = 1000 # Lower first
|
||||
```
|
||||
|
||||
|
||||
@@ -28,4 +28,4 @@ call('git commit -am "Bump to {}"'.format(version), shell=True)
|
||||
call('git tag {}'.format(version), shell=True)
|
||||
call('git push', shell=True)
|
||||
call('git push --tags', shell=True)
|
||||
call('python setup.py sdist upload', shell=True)
|
||||
call('python setup.py sdist bdist_wheel upload', shell=True)
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
pytest
|
||||
mock
|
||||
pytest-mock
|
||||
wheel
|
||||
|
||||
5
setup.py
5
setup.py
@@ -1,7 +1,7 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
|
||||
VERSION = '1.36'
|
||||
VERSION = '1.38'
|
||||
|
||||
|
||||
setup(name='thefuck',
|
||||
@@ -17,4 +17,5 @@ setup(name='thefuck',
|
||||
zip_safe=False,
|
||||
install_requires=['pathlib', 'psutil', 'colorama', 'six'],
|
||||
entry_points={'console_scripts': [
|
||||
'thefuck = thefuck.main:main', 'thefuck-alias = thefuck.main:alias']})
|
||||
'thefuck = thefuck.main:main',
|
||||
'thefuck-alias = thefuck.shells:app_alias']})
|
||||
|
||||
17
tests/rules/test_dry.py
Normal file
17
tests/rules/test_dry.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
from thefuck.rules.dry import match, get_new_command
|
||||
from tests.utils import Command
|
||||
|
||||
|
||||
@pytest.mark.parametrize('command', [
|
||||
Command(script='cd cd foo'),
|
||||
Command(script='git git push origin/master')])
|
||||
def test_match(command):
|
||||
assert match(command, None)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('command, new_command', [
|
||||
(Command('cd cd foo'), 'cd foo'),
|
||||
(Command('git git push origin/master'), 'git push origin/master')])
|
||||
def test_get_new_command(command, new_command):
|
||||
assert get_new_command(command, None) == new_command
|
||||
12
tests/rules/test_man_no_space.py
Normal file
12
tests/rules/test_man_no_space.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from thefuck.rules.man_no_space import match, get_new_command
|
||||
from tests.utils import Command
|
||||
|
||||
|
||||
def test_match():
|
||||
assert match(Command('mandiff', stderr='mandiff: command not found'), None)
|
||||
assert not match(Command(), None)
|
||||
|
||||
|
||||
def test_get_new_command():
|
||||
assert get_new_command(
|
||||
Command('mandiff'), None) == 'man diff'
|
||||
@@ -14,10 +14,8 @@ def test_default(enabled, rules, result):
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def load_source(monkeypatch):
|
||||
mock = Mock()
|
||||
monkeypatch.setattr('thefuck.conf.load_source', mock)
|
||||
return mock
|
||||
def load_source(mocker):
|
||||
return mocker.patch('thefuck.conf.load_source')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -6,15 +6,15 @@ from thefuck import main, conf, types
|
||||
from tests.utils import Rule, Command
|
||||
|
||||
|
||||
def test_load_rule(monkeypatch):
|
||||
def test_load_rule(mocker):
|
||||
match = object()
|
||||
get_new_command = object()
|
||||
load_source = Mock()
|
||||
load_source.return_value = Mock(match=match,
|
||||
get_new_command=get_new_command,
|
||||
enabled_by_default=True,
|
||||
priority=900)
|
||||
monkeypatch.setattr('thefuck.main.load_source', load_source)
|
||||
load_source = mocker.patch(
|
||||
'thefuck.main.load_source',
|
||||
return_value=Mock(match=match,
|
||||
get_new_command=get_new_command,
|
||||
enabled_by_default=True,
|
||||
priority=900))
|
||||
assert main.load_rule(Path('/rules/bash.py')) \
|
||||
== Rule('bash', match, get_new_command, priority=900)
|
||||
load_source.assert_called_once_with('bash', '/rules/bash.py')
|
||||
@@ -22,10 +22,8 @@ def test_load_rule(monkeypatch):
|
||||
|
||||
class TestGetRules(object):
|
||||
@pytest.fixture(autouse=True)
|
||||
def glob(self, monkeypatch):
|
||||
mock = Mock(return_value=[])
|
||||
monkeypatch.setattr('thefuck.main.Path.glob', mock)
|
||||
return mock
|
||||
def glob(self, mocker):
|
||||
return mocker.patch('thefuck.main.Path.glob', return_value=[])
|
||||
|
||||
def _compare_names(self, rules, names):
|
||||
return [r.name for r in rules] == names
|
||||
@@ -118,10 +116,8 @@ class TestGetMatchedRule(object):
|
||||
|
||||
class TestRunRule(object):
|
||||
@pytest.fixture(autouse=True)
|
||||
def confirm(self, monkeypatch):
|
||||
mock = Mock(return_value=True)
|
||||
monkeypatch.setattr('thefuck.main.confirm', mock)
|
||||
return mock
|
||||
def confirm(self, mocker):
|
||||
return mocker.patch('thefuck.main.confirm', return_value=True)
|
||||
|
||||
def test_run_rule(self, capsys):
|
||||
main.run_rule(Rule(get_new_command=lambda *_: 'new-command'),
|
||||
@@ -147,10 +143,8 @@ class TestRunRule(object):
|
||||
|
||||
class TestConfirm(object):
|
||||
@pytest.fixture
|
||||
def stdin(self, monkeypatch):
|
||||
mock = Mock(return_value='\n')
|
||||
monkeypatch.setattr('sys.stdin.read', mock)
|
||||
return mock
|
||||
def stdin(self, mocker):
|
||||
return mocker.patch('sys.stdin.read', return_value='\n')
|
||||
|
||||
def test_when_not_required(self, capsys):
|
||||
assert main.confirm('command', None, Mock(require_confirmation=False))
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
import pytest
|
||||
from mock import Mock, MagicMock
|
||||
from thefuck import shells
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def builtins_open(monkeypatch):
|
||||
mock = MagicMock()
|
||||
monkeypatch.setattr('six.moves.builtins.open', mock)
|
||||
return mock
|
||||
def builtins_open(mocker):
|
||||
return mocker.patch('six.moves.builtins.open')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def isfile(monkeypatch):
|
||||
mock = Mock(return_value=True)
|
||||
monkeypatch.setattr('os.path.isfile', mock)
|
||||
return mock
|
||||
def isfile(mocker):
|
||||
return mocker.patch('os.path.isfile', return_value=True)
|
||||
|
||||
|
||||
class TestGeneric(object):
|
||||
@@ -32,9 +27,8 @@ class TestGeneric(object):
|
||||
@pytest.mark.usefixtures('isfile')
|
||||
class TestBash(object):
|
||||
@pytest.fixture(autouse=True)
|
||||
def Popen(self, monkeypatch):
|
||||
mock = Mock()
|
||||
monkeypatch.setattr('thefuck.shells.Popen', mock)
|
||||
def Popen(self, mocker):
|
||||
mock = mocker.patch('thefuck.shells.Popen')
|
||||
mock.return_value.stdout.read.return_value = (
|
||||
b'alias l=\'ls -CF\'\n'
|
||||
b'alias la=\'ls -A\'\n'
|
||||
@@ -52,16 +46,15 @@ class TestBash(object):
|
||||
|
||||
def test_put_to_history(self, builtins_open):
|
||||
shells.Bash().put_to_history('ls')
|
||||
builtins_open.return_value.__enter__.return_value.\
|
||||
builtins_open.return_value.__enter__.return_value. \
|
||||
write.assert_called_once_with('ls\n')
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('isfile')
|
||||
class TestZsh(object):
|
||||
@pytest.fixture(autouse=True)
|
||||
def Popen(self, monkeypatch):
|
||||
mock = Mock()
|
||||
monkeypatch.setattr('thefuck.shells.Popen', mock)
|
||||
def Popen(self, mocker):
|
||||
mock = mocker.patch('thefuck.shells.Popen')
|
||||
mock.return_value.stdout.read.return_value = (
|
||||
b'l=\'ls -CF\'\n'
|
||||
b'la=\'ls -A\'\n'
|
||||
@@ -77,9 +70,9 @@ class TestZsh(object):
|
||||
def test_to_shell(self):
|
||||
assert shells.Zsh().to_shell('pwd') == 'pwd'
|
||||
|
||||
def test_put_to_history(self, builtins_open, monkeypatch):
|
||||
monkeypatch.setattr('thefuck.shells.time',
|
||||
lambda: 1430707243.3517463)
|
||||
def test_put_to_history(self, builtins_open, mocker):
|
||||
mocker.patch('thefuck.shells.time',
|
||||
return_value=1430707243.3517463)
|
||||
shells.Zsh().put_to_history('ls')
|
||||
builtins_open.return_value.__enter__.return_value. \
|
||||
write.assert_called_once_with(': 1430707243:0;ls\n')
|
||||
write.assert_called_once_with(': 1430707243:0;ls\n')
|
||||
|
||||
@@ -121,10 +121,6 @@ def run_rule(rule, command, settings):
|
||||
print(new_command)
|
||||
|
||||
|
||||
def alias():
|
||||
print(shells.app_alias())
|
||||
|
||||
|
||||
def main():
|
||||
colorama.init()
|
||||
user_dir = setup_user_dir()
|
||||
|
||||
12
thefuck/rules/dry.py
Normal file
12
thefuck/rules/dry.py
Normal file
@@ -0,0 +1,12 @@
|
||||
def match(command, settings):
|
||||
split_command = command.script.split()
|
||||
|
||||
return len(split_command) >= 2 and split_command[0] == split_command[1]
|
||||
|
||||
|
||||
def get_new_command(command, settings):
|
||||
return command.script[command.script.find(' ')+1:]
|
||||
|
||||
# it should be rare enough to actually have to type twice the same word, so
|
||||
# this rule can have a higher priority to come before things like "cd cd foo"
|
||||
priority = 900
|
||||
15
thefuck/rules/git_checkout.py
Normal file
15
thefuck/rules/git_checkout.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import re
|
||||
|
||||
|
||||
def match(command, settings):
|
||||
return ('git' in command.script
|
||||
and 'did not match any file(s) known to git.' in command.stderr
|
||||
and "Did you forget to 'git add'?" not in command.stderr)
|
||||
|
||||
|
||||
def get_new_command(command, settings):
|
||||
missing_file = re.findall(
|
||||
r"error: pathspec '([^']*)' "
|
||||
"did not match any file\(s\) known to git.", command.stderr)[0]
|
||||
|
||||
return 'git branch {} && {}'.format(missing_file, command.script)
|
||||
9
thefuck/rules/man_no_space.py
Normal file
9
thefuck/rules/man_no_space.py
Normal file
@@ -0,0 +1,9 @@
|
||||
def match(command, settings):
|
||||
return (command.script.startswith(u'man')
|
||||
and u'command not found' in command.stderr.lower())
|
||||
|
||||
|
||||
def get_new_command(command, settings):
|
||||
return u'man {}'.format(command.script[3:])
|
||||
|
||||
priority = 2000
|
||||
Reference in New Issue
Block a user