mirror of
https://github.com/nvbn/thefuck.git
synced 2025-01-31 02:01:13 +00:00
Add information about writting yourself rules, revert no_command changes
This commit is contained in:
parent
1503dcf294
commit
1de9c5f77b
34
README.md
34
README.md
@ -61,6 +61,40 @@ And add to `.bashrc` or `.zshrc`:
|
||||
alias fuck='$(thefuck $(fc -ln -1))'
|
||||
```
|
||||
|
||||
## Creating your own rules
|
||||
|
||||
For adding your own rule you should create `your-rule-name.py`
|
||||
in `~/.thefuck/rules`. Rule should contain two functions:
|
||||
`match(command: Command, settings: Settings) -> bool`
|
||||
and `get_new_command(command: Command, settings: Settings) -> str`.
|
||||
|
||||
`Command` have three attributes: `script`, `stdout` and `stderr`.
|
||||
|
||||
`Settings` is `~/.thefuck/settings.py`.
|
||||
|
||||
Simple example of the rule for running script with `sudo`:
|
||||
|
||||
```python
|
||||
def match(command, settings):
|
||||
return ('permission denied' in command.stderr.lower()
|
||||
or 'EACCES' in command.stderr)
|
||||
|
||||
|
||||
def get_new_command(command, settings):
|
||||
return 'sudo {}'.format(command.script)
|
||||
```
|
||||
|
||||
[More examples of rules](https://github.com/nvbn/thefuck/tree/master/thefuck/rules),
|
||||
[utility functions for rules]((https://github.com/nvbn/thefuck/tree/master/thefuck/utils.py)).
|
||||
|
||||
## Settings
|
||||
|
||||
The Fuck have a few settings parameters:
|
||||
|
||||
* `rules` – list of enabled rules, by default all;
|
||||
* `command_not_found` – path to `command_not_found` binary,
|
||||
by default `/usr/lib/command-not-found`.
|
||||
|
||||
## Developing
|
||||
|
||||
Install `The Fuck` for development:
|
||||
|
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
|
||||
setup(name='thefuck',
|
||||
version=1.3,
|
||||
version=1.4,
|
||||
description="Magnificent app which corrects your previous console command",
|
||||
author='Vladimir Iakovlev',
|
||||
author_email='nvbn.rm@gmail.com',
|
||||
|
@ -1,7 +1,7 @@
|
||||
from subprocess import PIPE
|
||||
from mock import patch, Mock
|
||||
import pytest
|
||||
from thefuck.rules.no_command_apt import match, get_new_command
|
||||
from thefuck.rules.no_command import match, get_new_command
|
||||
from thefuck.main import Command
|
||||
|
||||
|
||||
@ -21,23 +21,30 @@ vom: command not found
|
||||
|
||||
@pytest.fixture
|
||||
def bins_exists(request):
|
||||
p = patch('thefuck.rules.no_command_apt.which',
|
||||
p = patch('thefuck.rules.no_command.which',
|
||||
return_value=True)
|
||||
p.start()
|
||||
request.addfinalizer(p.stop)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def settings():
|
||||
class _Settings(object):
|
||||
pass
|
||||
return _Settings
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('bins_exists')
|
||||
def test_match(command_found, command_not_found):
|
||||
with patch('thefuck.rules.no_command_apt.Popen') as Popen:
|
||||
def test_match(command_found, command_not_found, settings):
|
||||
with patch('thefuck.rules.no_command.Popen') as Popen:
|
||||
Popen.return_value.stderr.read.return_value = command_found
|
||||
assert match(Command('aptget install vim', '', ''), None)
|
||||
assert match(Command('aptget install vim', '', ''), settings)
|
||||
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', '', ''), None)
|
||||
assert not match(Command('ls', '', ''), settings)
|
||||
|
||||
with patch('thefuck.rules.no_command_apt.Popen') as Popen:
|
||||
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', '', ''),
|
||||
Mock(command_not_found='test'))
|
||||
@ -47,9 +54,9 @@ def test_match(command_found, command_not_found):
|
||||
|
||||
@pytest.mark.usefixtures('bins_exists')
|
||||
def test_get_new_command(command_found):
|
||||
with patch('thefuck.rules.no_command_apt._get_output',
|
||||
with patch('thefuck.rules.no_command._get_output',
|
||||
return_value=command_found.decode()):
|
||||
assert get_new_command(Command('aptget install vim', '', ''), None)\
|
||||
assert get_new_command(Command('aptget install vim', '', ''), settings)\
|
||||
== 'apt-get install vim'
|
||||
assert get_new_command(Command('sudo aptget install vim', '', ''), None) \
|
||||
assert get_new_command(Command('sudo aptget install vim', '', ''), settings) \
|
||||
== 'sudo apt-get install vim'
|
@ -1,25 +1,26 @@
|
||||
from subprocess import Popen, PIPE
|
||||
import re
|
||||
from thefuck.utils import which
|
||||
from thefuck.utils import which, wrap_settings
|
||||
|
||||
|
||||
def _get_bin(settings):
|
||||
return getattr(settings, 'command_not_found', '/usr/lib/command-not-found')
|
||||
local_settings = {'command_not_found': '/usr/lib/command-not-found'}
|
||||
|
||||
|
||||
def _get_output(command, settings):
|
||||
name = command.script.split(' ')[command.script.startswith('sudo')]
|
||||
check_script = '{} {}'.format(_get_bin(settings), name)
|
||||
check_script = '{} {}'.format(settings.command_not_found, name)
|
||||
result = Popen(check_script, shell=True, stderr=PIPE)
|
||||
return result.stderr.read().decode()
|
||||
|
||||
|
||||
@wrap_settings(local_settings)
|
||||
def match(command, settings):
|
||||
if which('apt-get') and which(_get_bin(settings)):
|
||||
if which(settings.command_not_found):
|
||||
output = _get_output(command, settings)
|
||||
return "No command" in output and "from package" in output
|
||||
|
||||
|
||||
@wrap_settings(local_settings)
|
||||
def get_new_command(command, settings):
|
||||
output = _get_output(command, settings)
|
||||
broken_name = re.findall(r"No command '([^']*)' found",
|
@ -1,7 +1,10 @@
|
||||
from functools import wraps
|
||||
import os
|
||||
|
||||
|
||||
def which(program):
|
||||
"""Returns `program` path or `None`."""
|
||||
|
||||
def is_exe(fpath):
|
||||
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
|
||||
|
||||
@ -17,3 +20,24 @@ def which(program):
|
||||
return exe_file
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def wrap_settings(params):
|
||||
"""Adds default values to settings if it not presented.
|
||||
|
||||
Usage:
|
||||
|
||||
@wrap_settings({'apt': '/usr/bin/apt'})
|
||||
def match(command, settings):
|
||||
print(settings.apt)
|
||||
|
||||
"""
|
||||
def decorator(fn):
|
||||
@wraps(fn)
|
||||
def wrapper(command, settings):
|
||||
for key, val in params.items():
|
||||
if not hasattr(settings, key):
|
||||
setattr(settings, key, val)
|
||||
return fn(command, settings)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
Loading…
x
Reference in New Issue
Block a user