1
0
mirror of https://github.com/nvbn/thefuck.git synced 2025-02-21 20:38:54 +00:00

Merge branch 'git-aliases' of https://github.com/mcarton/thefuck into mcarton-git-aliases

This commit is contained in:
nvbn 2015-07-19 21:27:04 +03:00
commit 90014b2b05
15 changed files with 93 additions and 38 deletions

View File

@ -3,15 +3,13 @@ from thefuck.rules.git_diff_staged import match, get_new_command
from tests.utils import Command from tests.utils import Command
@pytest.mark.parametrize('command', [ @pytest.mark.parametrize('command', [Command(script='git diff')])
Command(script='git diff'),
Command(script='git df'),
Command(script='git ds')])
def test_match(command): def test_match(command):
assert match(command, None) assert match(command, None)
@pytest.mark.parametrize('command', [ @pytest.mark.parametrize('command', [
Command(script='git diff --staged'),
Command(script='git tag'), Command(script='git tag'),
Command(script='git branch'), Command(script='git branch'),
Command(script='git log')]) Command(script='git log')])
@ -20,8 +18,6 @@ def test_not_match(command):
@pytest.mark.parametrize('command, new_command', [ @pytest.mark.parametrize('command, new_command', [
(Command('git diff'), 'git diff --staged'), (Command('git diff'), 'git diff --staged')])
(Command('git df'), 'git df --staged'),
(Command('git ds'), 'git ds --staged')])
def test_get_new_command(command, new_command): def test_get_new_command(command, new_command):
assert get_new_command(command, None) == new_command assert get_new_command(command, None) == new_command

View File

@ -3,22 +3,20 @@ from thefuck.rules.git_stash import match, get_new_command
from tests.utils import Command from tests.utils import Command
@pytest.fixture cherry_pick_error = (
def cherry_pick_error(): 'error: Your local changes would be overwritten by cherry-pick.\n'
return ('error: Your local changes would be overwritten by cherry-pick.\n' 'hint: Commit your changes or stash them to proceed.\n'
'hint: Commit your changes or stash them to proceed.\n' 'fatal: cherry-pick failed')
'fatal: cherry-pick failed')
@pytest.fixture rebase_error = (
def rebase_error(): 'Cannot rebase: Your index contains uncommitted changes.\n'
return ('Cannot rebase: Your index contains uncommitted changes.\n' 'Please commit or stash them.')
'Please commit or stash them.')
@pytest.mark.parametrize('command', [ @pytest.mark.parametrize('command', [
Command(script='git cherry-pick a1b2c3d', stderr=cherry_pick_error()), Command(script='git cherry-pick a1b2c3d', stderr=cherry_pick_error),
Command(script='git rebase -i HEAD~7', stderr=rebase_error())]) Command(script='git rebase -i HEAD~7', stderr=rebase_error)])
def test_match(command): def test_match(command):
assert match(command, None) assert match(command, None)

View File

@ -77,23 +77,23 @@ class TestGetCommand(object):
monkeypatch.setattr('thefuck.shells.to_shell', lambda x: x) monkeypatch.setattr('thefuck.shells.to_shell', lambda x: x)
def test_get_command_calls(self, Popen): def test_get_command_calls(self, Popen):
assert main.get_command(Mock(), assert main.get_command(Mock(env={}),
['thefuck', 'apt-get', 'search', 'vim']) \ ['thefuck', 'apt-get', 'search', 'vim']) \
== Command('apt-get search vim', 'stdout', 'stderr') == Command('apt-get search vim', 'stdout', 'stderr')
Popen.assert_called_once_with('apt-get search vim', Popen.assert_called_once_with('apt-get search vim',
shell=True, shell=True,
stdout=PIPE, stdout=PIPE,
stderr=PIPE, stderr=PIPE,
env={'LANG': 'C'}) env={})
@pytest.mark.parametrize('args, result', [ @pytest.mark.parametrize('args, result', [
(['thefuck', 'ls', '-la'], 'ls -la'), (['thefuck', 'ls', '-la'], 'ls -la'),
(['thefuck', 'ls'], 'ls')]) (['thefuck', 'ls'], 'ls')])
def test_get_command_script(self, args, result): def test_get_command_script(self, args, result):
if result: if result:
assert main.get_command(Mock(), args).script == result assert main.get_command(Mock(env={}), args).script == result
else: else:
assert main.get_command(Mock(), args) is None assert main.get_command(Mock(env={}), args) is None
class TestGetMatchedRule(object): class TestGetMatchedRule(object):

View File

@ -1,6 +1,6 @@
import pytest import pytest
from mock import Mock from mock import Mock
from thefuck.utils import sudo_support, wrap_settings, memoize, get_closest from thefuck.utils import git_support, sudo_support, wrap_settings, memoize, get_closest
from thefuck.types import Settings from thefuck.types import Settings
from tests.utils import Command from tests.utils import Command
@ -26,6 +26,15 @@ def test_sudo_support(return_value, command, called, result):
fn.assert_called_once_with(Command(called), None) fn.assert_called_once_with(Command(called), None)
@pytest.mark.parametrize('called, command, stderr', [
('git co', 'git checkout', "19:22:36.299340 git.c:282 trace: alias expansion: co => 'checkout'"),
('git com file', 'git commit --verbose file', "19:23:25.470911 git.c:282 trace: alias expansion: com => 'commit' '--verbose'")])
def test_git_support(called, command, stderr):
@git_support
def fn(command, settings): return command.script
assert fn(Command(script=called, stderr=stderr), None) == command
def test_memoize(): def test_memoize():
fn = Mock(__name__='fn') fn = Mock(__name__='fn')
memoized = memoize(fn) memoized = memoize(fn)

View File

@ -30,7 +30,8 @@ DEFAULT_SETTINGS = {'rules': DEFAULT_RULES,
'require_confirmation': False, 'require_confirmation': False,
'no_colors': False, 'no_colors': False,
'debug': False, 'debug': False,
'priority': {}} 'priority': {},
'env': {'LANG': 'C', 'GIT_TRACE': '1'}}
ENV_TO_ATTR = {'THEFUCK_RULES': 'rules', ENV_TO_ATTR = {'THEFUCK_RULES': 'rules',
'THEFUCK_WAIT_COMMAND': 'wait_command', 'THEFUCK_WAIT_COMMAND': 'wait_command',

View File

@ -81,8 +81,12 @@ def get_command(settings, args):
script = shells.from_shell(script) script = shells.from_shell(script)
logs.debug('Call: {}'.format(script), settings) logs.debug('Call: {}'.format(script), settings)
result = Popen(script, shell=True, stdout=PIPE, stderr=PIPE,
env=dict(os.environ, LANG='C')) env = dict(os.environ)
env.update(settings.env)
logs.debug('Executing with env: {}'.format(env), settings)
result = Popen(script, shell=True, stdout=PIPE, stderr=PIPE, env=env)
if wait_output(settings, result): if wait_output(settings, result):
return types.Command(script, result.stdout.read().decode('utf-8'), return types.Command(script, result.stdout.read().decode('utf-8'),
result.stderr.read().decode('utf-8')) result.stderr.read().decode('utf-8'))

View File

@ -1,13 +1,15 @@
import re import re
from thefuck import shells from thefuck import utils, shells
@utils.git_support
def match(command, settings): def match(command, settings):
return ('git' in command.script return ('git' in command.script
and 'did not match any file(s) known to git.' in command.stderr and 'did not match any file(s) known to git.' in command.stderr
and "Did you forget to 'git add'?" in command.stderr) and "Did you forget to 'git add'?" in command.stderr)
@utils.git_support
def get_new_command(command, settings): def get_new_command(command, settings):
missing_file = re.findall( missing_file = re.findall(
r"error: pathspec '([^']*)' " r"error: pathspec '([^']*)' "

View File

@ -1,10 +1,12 @@
from thefuck import shells from thefuck import utils, shells
@utils.git_support
def match(command, settings): def match(command, settings):
# catches "git branch list" in place of "git branch" # catches "git branch list" in place of "git branch"
return command.script.split() == 'git branch list'.split() return command.script.split() == 'git branch list'.split()
@utils.git_support
def get_new_command(command, settings): def get_new_command(command, settings):
return shells.and_('git branch --delete list', 'git branch') return shells.and_('git branch --delete list', 'git branch')

View File

@ -1,13 +1,15 @@
import re import re
from thefuck import shells from thefuck import shells, utils
@utils.git_support
def match(command, settings): def match(command, settings):
return ('git' in command.script return ('git' in command.script
and 'did not match any file(s) known to git.' in command.stderr and 'did not match any file(s) known to git.' in command.stderr
and "Did you forget to 'git add'?" not in command.stderr) and "Did you forget to 'git add'?" not in command.stderr)
@utils.git_support
def get_new_command(command, settings): def get_new_command(command, settings):
missing_file = re.findall( missing_file = re.findall(
r"error: pathspec '([^']*)' " r"error: pathspec '([^']*)' "

View File

@ -1,6 +1,13 @@
from thefuck import utils
@utils.git_support
def match(command, settings): def match(command, settings):
return command.script.startswith('git d') return ('git' in command.script and
'diff' in command.script and
'--staged' not in command.script)
@utils.git_support
def get_new_command(command, settings): def get_new_command(command, settings):
return '{} --staged'.format(command.script) return '{} --staged'.format(command.script)

View File

@ -1,8 +1,8 @@
from difflib import get_close_matches
import re import re
from thefuck.utils import get_closest from thefuck.utils import get_closest, git_support
@git_support
def match(command, settings): def match(command, settings):
return ('git' in command.script return ('git' in command.script
and " is not a git command. See 'git --help'." in command.stderr and " is not a git command. See 'git --help'." in command.stderr
@ -18,6 +18,7 @@ def _get_all_git_matched_commands(stderr):
yield line.strip() yield line.strip()
@git_support
def get_new_command(command, settings): def get_new_command(command, settings):
broken_cmd = re.findall(r"git: '([^']*)' is not a git command", broken_cmd = re.findall(r"git: '([^']*)' is not a git command",
command.stderr)[0] command.stderr)[0]

View File

@ -1,12 +1,14 @@
from thefuck import shells from thefuck import shells, utils
@utils.git_support
def match(command, settings): def match(command, settings):
return ('git' in command.script return ('git' in command.script
and 'pull' in command.script and 'pull' in command.script
and 'set-upstream' in command.stderr) and 'set-upstream' in command.stderr)
@utils.git_support
def get_new_command(command, settings): def get_new_command(command, settings):
line = command.stderr.split('\n')[-3].strip() line = command.stderr.split('\n')[-3].strip()
branch = line.split(' ')[-1] branch = line.split(' ')[-1]

View File

@ -1,8 +1,13 @@
from thefuck import utils
@utils.git_support
def match(command, settings): def match(command, settings):
return ('git' in command.script return ('git' in command.script
and 'push' in command.script and 'push' in command.script
and 'set-upstream' in command.stderr) and 'set-upstream' in command.stderr)
@utils.git_support
def get_new_command(command, settings): def get_new_command(command, settings):
return command.stderr.split('\n')[-3].strip() return command.stderr.split('\n')[-3].strip()

View File

@ -1,12 +1,14 @@
from thefuck import shells from thefuck import shells, utils
@utils.git_support
def match(command, settings): def match(command, settings):
# catches "Please commit or stash them" and "Please, commit your changes or # catches "Please commit or stash them" and "Please, commit your changes or
# stash them before you can switch branches." # stash them before you can switch branches."
return 'git' in command.script and 'or stash them' in command.stderr return 'git' in command.script and 'or stash them' in command.stderr
@utils.git_support
def get_new_command(command, settings): def get_new_command(command, settings):
formatme = shells.and_('git stash', '{}') formatme = shells.and_('git stash', '{}')
return formatme.format(command.script) return formatme.format(command.script)

View File

@ -1,7 +1,9 @@
from difflib import get_close_matches from difflib import get_close_matches
from functools import wraps from functools import wraps
from shlex import split
import os import os
import pickle import pickle
import re
import six import six
from .types import Command from .types import Command
@ -9,11 +11,9 @@ from .types import Command
DEVNULL = open(os.devnull, 'w') DEVNULL = open(os.devnull, 'w')
if six.PY2: if six.PY2:
import pipes from pipes import quote
quote = pipes.quote
else: else:
import shlex from shlex import quote
quote = shlex.quote
def which(program): def which(program):
@ -73,6 +73,30 @@ def sudo_support(fn):
return wrapper return wrapper
def git_support(fn):
"""Resolve git aliases."""
@wraps(fn)
def wrapper(command, settings):
if (command.script.startswith('git') and
'trace: alias expansion:' in command.stderr):
search = re.search("trace: alias expansion: ([^ ]*) => ([^\n]*)",
command.stderr)
alias = search.group(1)
# by default git quotes everthing, for example:
# 'commit' '--amend'
# which is surprising and does not allow to easily test for
# eg. 'git commit'
expansion = ' '.join(map(quote, split(search.group(2))))
new_script = command.script.replace(alias, expansion)
command = Command._replace(command, script=new_script)
return fn(command, settings)
return wrapper
def memoize(fn): def memoize(fn):
"""Caches previous calls to the function.""" """Caches previous calls to the function."""
memo = {} memo = {}