1
0
mirror of https://github.com/nvbn/thefuck.git synced 2025-02-22 12:58:33 +00:00

#334 Speed-up rules with caching for_app decorator

This commit is contained in:
nvbn 2015-08-27 16:42:09 +03:00
parent bc78f1bbee
commit 0c283ff2b8
33 changed files with 142 additions and 113 deletions

View File

@ -1,6 +1,6 @@
import pytest import pytest
from mock import Mock
from thefuck.rules.lein_not_task import match, get_new_command from thefuck.rules.lein_not_task import match, get_new_command
from tests.utils import Command
@pytest.fixture @pytest.fixture
@ -14,10 +14,10 @@ Did you mean this?
def test_match(is_not_task): def test_match(is_not_task):
assert match(Mock(script='lein rpl', stderr=is_not_task), None) assert match(Command(script='lein rpl', stderr=is_not_task), None)
assert not match(Mock(script='ls', stderr=is_not_task), None) assert not match(Command(script='ls', stderr=is_not_task), None)
def test_get_new_command(is_not_task): def test_get_new_command(is_not_task):
assert get_new_command(Mock(script='lein rpl --help', stderr=is_not_task), assert get_new_command(Command(script='lein rpl --help', stderr=is_not_task),
None) == ['lein repl --help', 'lein jar --help'] None) == ['lein repl --help', 'lein jar --help']

View File

@ -1,16 +1,16 @@
from mock import patch, Mock
from thefuck.rules.ls_lah import match, get_new_command from thefuck.rules.ls_lah import match, get_new_command
from tests.utils import Command
def test_match(): def test_match():
assert match(Mock(script='ls'), None) assert match(Command(script='ls'), None)
assert match(Mock(script='ls file.py'), None) assert match(Command(script='ls file.py'), None)
assert match(Mock(script='ls /opt'), None) assert match(Command(script='ls /opt'), None)
assert not match(Mock(script='ls -lah /opt'), None) assert not match(Command(script='ls -lah /opt'), None)
assert not match(Mock(script='pacman -S binutils'), None) assert not match(Command(script='pacman -S binutils'), None)
assert not match(Mock(script='lsof'), None) assert not match(Command(script='lsof'), None)
def test_get_new_command(): def test_get_new_command():
assert get_new_command(Mock(script='ls file.py'), None) == 'ls -lah file.py' assert get_new_command(Command(script='ls file.py'), None) == 'ls -lah file.py'
assert get_new_command(Mock(script='ls'), None) == 'ls -lah' assert get_new_command(Command(script='ls'), None) == 'ls -lah'

View File

@ -1,6 +1,8 @@
import re import re
from thefuck.utils import for_app
@for_app('apt-get')
def match(command, settings): def match(command, settings):
return command.script.startswith('apt-get search') return command.script.startswith('apt-get search')

View File

@ -1,10 +1,10 @@
import re import re
from thefuck.utils import replace_argument from thefuck.utils import replace_argument, for_app
@for_app('cargo')
def match(command, settings): def match(command, settings):
return ('cargo' in command.script return ('No such subcommand' in command.stderr
and 'No such subcommand' in command.stderr
and 'Did you mean' in command.stderr) and 'Did you mean' in command.stderr)

View File

@ -4,6 +4,7 @@ import os
from difflib import get_close_matches from difflib import get_close_matches
from thefuck.specific.sudo import sudo_support from thefuck.specific.sudo import sudo_support
from thefuck.rules import cd_mkdir from thefuck.rules import cd_mkdir
from thefuck.utils import for_app
__author__ = "mmussomele" __author__ = "mmussomele"
@ -16,6 +17,7 @@ def _get_sub_dirs(parent):
@sudo_support @sudo_support
@for_app('cd')
def match(command, settings): def match(command, settings):
"""Match function copied from cd_mkdir.py""" """Match function copied from cd_mkdir.py"""
return (command.script.startswith('cd ') return (command.script.startswith('cd ')

View File

@ -1,13 +1,14 @@
import re import re
from thefuck import shells from thefuck import shells
from thefuck.utils import for_app
from thefuck.specific.sudo import sudo_support from thefuck.specific.sudo import sudo_support
@sudo_support @sudo_support
@for_app('cd')
def match(command, settings): def match(command, settings):
return (command.script.startswith('cd ') return (('no such file or directory' in command.stderr.lower()
and ('no such file or directory' in command.stderr.lower() or 'cd: can\'t cd to' in command.stderr.lower()))
or 'cd: can\'t cd to' in command.stderr.lower()))
@sudo_support @sudo_support

View File

@ -1,11 +1,11 @@
import re import re
from thefuck.utils import replace_argument from thefuck.utils import replace_argument, for_app
@for_app('composer')
def match(command, settings): def match(command, settings):
return ('composer' in command.script return (('did you mean this?' in command.stderr.lower()
and ('did you mean this?' in command.stderr.lower() or 'did you mean one of these?' in command.stderr.lower()))
or 'did you mean one of these?' in command.stderr.lower()))
def get_new_command(command, settings): def get_new_command(command, settings):

View File

@ -1,12 +1,13 @@
import re import re
from thefuck.specific.sudo import sudo_support from thefuck.specific.sudo import sudo_support
from thefuck.utils import for_app
@sudo_support @sudo_support
@for_app('cp')
def match(command, settings): def match(command, settings):
stderr = command.stderr.lower() stderr = command.stderr.lower()
return command.script.startswith('cp ') \ return 'omitting directory' in stderr or 'is a directory' in stderr
and ('omitting directory' in stderr or 'is a directory' in stderr)
@sudo_support @sudo_support

View File

@ -1,8 +1,11 @@
from thefuck.utils import for_app
@for_app(['g++', 'clang++'])
def match(command, settings): def match(command, settings):
return (('g++' in command.script or 'clang++' in command.script) and return ('This file requires compiler and library support for the '
('This file requires compiler and library support for the ' 'ISO C++ 2011 standard.' in command.stderr or
'ISO C++ 2011 standard.' in command.stderr or '-Wc++11-extensions' in command.stderr)
'-Wc++11-extensions' in command.stderr))
def get_new_command(command, settings): def get_new_command(command, settings):

View File

@ -1,6 +1,7 @@
from thefuck import shells
import os import os
import tarfile import tarfile
from thefuck import shells
from thefuck.utils import for_app
def _is_tar_extract(cmd): def _is_tar_extract(cmd):
@ -20,19 +21,19 @@ def _tar_file(cmd):
for c in cmd.split(): for c in cmd.split():
for ext in tar_extensions: for ext in tar_extensions:
if c.endswith(ext): if c.endswith(ext):
return (c, c[0:len(c)-len(ext)]) return (c, c[0:len(c) - len(ext)])
@for_app('tar')
def match(command, settings): def match(command, settings):
return (command.script.startswith('tar') return ('-C' not in command.script
and '-C' not in command.script
and _is_tar_extract(command.script) and _is_tar_extract(command.script)
and _tar_file(command.script) is not None) and _tar_file(command.script) is not None)
def get_new_command(command, settings): def get_new_command(command, settings):
return shells.and_('mkdir -p {dir}', '{cmd} -C {dir}') \ return shells.and_('mkdir -p {dir}', '{cmd} -C {dir}') \
.format(dir=_tar_file(command.script)[1], cmd=command.script) .format(dir=_tar_file(command.script)[1], cmd=command.script)
def side_effect(old_cmd, command, settings): def side_effect(old_cmd, command, settings):

View File

@ -1,5 +1,6 @@
import os import os
import zipfile import zipfile
from thefuck.utils import for_app
def _is_bad_zip(file): def _is_bad_zip(file):
@ -20,9 +21,9 @@ def _zip_file(command):
return '{}.zip'.format(c) return '{}.zip'.format(c)
@for_app('unzip')
def match(command, settings): def match(command, settings):
return (command.script.startswith('unzip') return ('-d' not in command.script
and '-d' not in command.script
and _is_bad_zip(_zip_file(command))) and _is_bad_zip(_zip_file(command)))

View File

@ -1,14 +1,14 @@
from itertools import dropwhile, takewhile, islice from itertools import dropwhile, takewhile, islice
import re import re
import subprocess import subprocess
from thefuck.utils import replace_command from thefuck.utils import replace_command, for_app
from thefuck.specific.sudo import sudo_support from thefuck.specific.sudo import sudo_support
@sudo_support @sudo_support
@for_app('docker')
def match(command, settings): def match(command, settings):
return command.script.startswith('docker') \ return 'is not a docker command' in command.stderr
and 'is not a docker command' in command.stderr
def get_docker_commands(): def get_docker_commands():

View File

@ -1,4 +1,3 @@
from thefuck import utils
from thefuck.utils import replace_argument from thefuck.utils import replace_argument
from thefuck.specific.git import git_support from thefuck.specific.git import git_support

View File

@ -1,3 +1,4 @@
from thefuck.utils import for_app
# Appends .go when compiling go files # Appends .go when compiling go files
# #
# Example: # Example:
@ -5,6 +6,7 @@
# error: go run: no go files listed # error: go run: no go files listed
@for_app('go')
def match(command, settings): def match(command, settings):
return (command.script.startswith('go run ') return (command.script.startswith('go run ')
and not command.script.endswith('.go')) and not command.script.endswith('.go'))

View File

@ -1,6 +1,9 @@
from thefuck.utils import for_app
@for_app('grep')
def match(command, settings): def match(command, settings):
return (command.script.startswith('grep') return 'is a directory' in command.stderr.lower()
and 'is a directory' in command.stderr.lower())
def get_new_command(command, settings): def get_new_command(command, settings):

View File

@ -1,11 +1,11 @@
import re import re
import subprocess import subprocess
from thefuck.utils import replace_command from thefuck.utils import replace_command, for_app
@for_app('gulp')
def match(command, script): def match(command, script):
return command.script.startswith('gulp')\ return 'is not in your gulpfile' in command.stdout
and 'is not in your gulpfile' in command.stdout
def get_gulp_tasks(): def get_gulp_tasks():

View File

@ -1,10 +1,10 @@
import re import re
from thefuck.utils import replace_command from thefuck.utils import replace_command, for_app
@for_app('heroku')
def match(command, settings): def match(command, settings):
return command.script.startswith('heroku') and \ return 'is not a heroku command' in command.stderr and \
'is not a heroku command' in command.stderr and \
'Perhaps you meant' in command.stderr 'Perhaps you meant' in command.stderr

View File

@ -1,13 +1,16 @@
# Fixes common java command mistake """Fixes common java command mistake
#
# Example: Example:
# > java foo.java > java foo.java
# Error: Could not find or load main class foo.java Error: Could not find or load main class foo.java
"""
from thefuck.utils import for_app
@for_app('java')
def match(command, settings): def match(command, settings):
return (command.script.startswith('java ') return command.script.endswith('.java')
and command.script.endswith('.java'))
def get_new_command(command, settings): def get_new_command(command, settings):

View File

@ -1,14 +1,17 @@
# Appends .java when compiling java files """Appends .java when compiling java files
#
# Example: Example:
# > javac foo > javac foo
# error: Class names, 'foo', are only accepted if annotation error: Class names, 'foo', are only accepted if annotation
# processing is explicitly requested processing is explicitly requested
"""
from thefuck.utils import for_app
@for_app('javac')
def match(command, settings): def match(command, settings):
return (command.script.startswith('javac ') return not command.script.endswith('.java')
and not command.script.endswith('.java'))
def get_new_command(command, settings): def get_new_command(command, settings):

View File

@ -1,9 +1,10 @@
import re import re
from thefuck.utils import replace_command, get_all_matched_commands from thefuck.utils import replace_command, get_all_matched_commands, for_app
from thefuck.specific.sudo import sudo_support from thefuck.specific.sudo import sudo_support
@sudo_support @sudo_support
@for_app('lein')
def match(command, settings): def match(command, settings):
return (command.script.startswith('lein') return (command.script.startswith('lein')
and "is not a task. See 'lein help'" in command.stderr and "is not a task. See 'lein help'" in command.stderr

View File

@ -1,7 +1,9 @@
from thefuck.utils import for_app
@for_app('ls')
def match(command, settings): def match(command, settings):
return (command.script == 'ls' return 'ls -' not in command.script
or command.script.startswith('ls ')
and 'ls -' not in command.script)
def get_new_command(command, settings): def get_new_command(command, settings):

View File

@ -1,5 +1,5 @@
import re import re
from thefuck.utils import get_closest from thefuck.utils import get_closest, for_app
def extract_possibilities(command): def extract_possibilities(command):
@ -12,14 +12,12 @@ def extract_possibilities(command):
return possib return possib
@for_app('hg')
def match(command, settings): def match(command, settings):
return (command.script.startswith('hg ') return ('hg: unknown command' in command.stderr
and ('hg: unknown command' in command.stderr and '(did you mean one of ' in command.stderr
and '(did you mean one of ' in command.stderr or "hg: command '" in command.stderr
or "hg: command '" in command.stderr and "' is ambiguous:" in command.stderr)
and "' is ambiguous:" in command.stderr
)
)
def get_new_command(command, settings): def get_new_command(command, settings):

View File

@ -5,21 +5,21 @@
# The file ~/github.com does not exist. # The file ~/github.com does not exist.
# Perhaps you meant 'http://github.com'? # Perhaps you meant 'http://github.com'?
# #
from thefuck.utils import for_app
@for_app('open', 'xdg-open', 'gnome-open', 'kde-open')
def match(command, settings): def match(command, settings):
return (command.script.startswith(('open', 'xdg-open', 'gnome-open', 'kde-open')) return ('.com' in command.script
and ( or '.net' in command.script
'.com' in command.script or '.org' in command.script
or '.net' in command.script or '.ly' in command.script
or '.org' in command.script or '.io' in command.script
or '.ly' in command.script or '.se' in command.script
or '.io' in command.script or '.edu' in command.script
or '.se' in command.script or '.info' in command.script
or '.edu' in command.script or '.me' in command.script
or '.info' in command.script or 'www.' in command.script)
or '.me' in command.script
or 'www.' in command.script))
def get_new_command(command, settings): def get_new_command(command, settings):

View File

@ -1,7 +1,10 @@
import re import re
from thefuck.utils import replace_argument from thefuck.utils import replace_argument, for_app
from thefuck.specific.sudo import sudo_support
@sudo_support
@for_app('pip')
def match(command, settings): def match(command, settings):
return ('pip' in command.script and return ('pip' in command.script and
'unknown command' in command.stderr and 'unknown command' in command.stderr and

View File

@ -3,11 +3,12 @@
# Example: # Example:
# > python foo # > python foo
# error: python: can't open file 'foo': [Errno 2] No such file or directory # error: python: can't open file 'foo': [Errno 2] No such file or directory
from thefuck.utils import for_app
@for_app('python')
def match(command, settings): def match(command, settings):
return (command.script.startswith('python ') return not command.script.endswith('.py')
and not command.script.endswith('.py'))
def get_new_command(command, settings): def get_new_command(command, settings):

View File

@ -1,10 +1,10 @@
import shlex import shlex
from thefuck.utils import quote from thefuck.utils import quote, for_app
@for_app('sed')
def match(command, settings): def match(command, settings):
return ('sed' in command.script return "unterminated `s' command" in command.stderr
and "unterminated `s' command" in command.stderr)
def get_new_command(command, settings): def get_new_command(command, settings):

View File

@ -1,4 +1,5 @@
import re import re
from thefuck.utils import for_app
patterns = [ patterns = [
r'WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!', r'WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!',
@ -12,6 +13,7 @@ offending_pattern = re.compile(
commands = ['ssh', 'scp'] commands = ['ssh', 'scp']
@for_app(*commands)
def match(command, settings): def match(command, settings):
if not command.script: if not command.script:
return False return False

View File

@ -2,15 +2,16 @@
The confusion in systemctl's param order is massive. The confusion in systemctl's param order is massive.
""" """
from thefuck.specific.sudo import sudo_support from thefuck.specific.sudo import sudo_support
from thefuck.utils import for_app
@sudo_support @sudo_support
@for_app('systemctl')
def match(command, settings): def match(command, settings):
# Catches 'Unknown operation 'service'.' when executing systemctl with # Catches 'Unknown operation 'service'.' when executing systemctl with
# misordered arguments # misordered arguments
cmd = command.script.split() cmd = command.script.split()
return ('systemctl' in command.script and return ('Unknown operation \'' in command.stderr and
'Unknown operation \'' in command.stderr and
len(cmd) - cmd.index('systemctl') == 3) len(cmd) - cmd.index('systemctl') == 3)

View File

@ -1,10 +1,10 @@
from thefuck.utils import replace_command
import re import re
from thefuck.utils import replace_command, for_app
@for_app('tmux')
def match(command, settings): def match(command, settings):
return ('tmux' in command.script return ('ambiguous command:' in command.stderr
and 'ambiguous command:' in command.stderr
and 'could be:' in command.stderr) and 'could be:' in command.stderr)

View File

@ -1,9 +1,10 @@
from thefuck import shells from thefuck import shells
from thefuck.utils import for_app
@for_app('tsuru')
def match(command, settings): def match(command, settings):
return (command.script.startswith('tsuru') return ('not authenticated' in command.stderr
and 'not authenticated' in command.stderr
and 'session has expired' in command.stderr) and 'session has expired' in command.stderr)

View File

@ -1,10 +1,10 @@
import re import re
from thefuck.utils import get_all_matched_commands, replace_command from thefuck.utils import get_all_matched_commands, replace_command, for_app
@for_app('tsuru')
def match(command, settings): def match(command, settings):
return (command.script.startswith('tsuru ') return (' is not a tsuru command. See "tsuru help".' in command.stderr
and ' is not a tsuru command. See "tsuru help".' in command.stderr
and '\nDid you mean?\n\t' in command.stderr) and '\nDid you mean?\n\t' in command.stderr)

View File

@ -1,8 +1,10 @@
from thefuck import shells from thefuck import shells
from thefuck.utils import for_app
@for_app('vagrant')
def match(command, settings): def match(command, settings):
return command.script.startswith('vagrant ') and 'run `vagrant up`' in command.stderr.lower() return 'run `vagrant up`' in command.stderr.lower()
def get_new_command(command, settings): def get_new_command(command, settings):

View File

@ -2,21 +2,18 @@ from functools import wraps
import re import re
from shlex import split from shlex import split
from ..types import Command from ..types import Command
from ..utils import quote from ..utils import quote, for_app
def git_support(fn): def git_support(fn):
"""Resolves git aliases and supports testing for both git and hub.""" """Resolves git aliases and supports testing for both git and hub."""
# supports GitHub's `hub` command
# which is recommended to be used with `alias git=hub`
# but at this point, shell aliases have already been resolved
@for_app('git', 'hub')
@wraps(fn) @wraps(fn)
def wrapper(command, settings): def wrapper(command, settings):
# supports GitHub's `hub` command
# which is recommended to be used with `alias git=hub`
# but at this point, shell aliases have already been resolved
is_git_cmd = command.script.startswith(('git', 'hub'))
if not is_git_cmd:
return False
# perform git aliases expansion # perform git aliases expansion
if 'trace: alias expansion:' in command.stderr: if 'trace: alias expansion:' in command.stderr:
search = re.search("trace: alias expansion: ([^ ]*) => ([^\n]*)", search = re.search("trace: alias expansion: ([^ ]*) => ([^\n]*)",