From b21c9ebb43972af700a903f9271c2ed03ed9bc76 Mon Sep 17 00:00:00 2001 From: nvbn Date: Tue, 25 Aug 2015 14:09:47 +0300 Subject: [PATCH] Move all app/os specific utils to `specific` package --- tests/rules/test_pacman.py | 4 +- tests/rules/test_pacman_not_found.py | 4 +- tests/specific/__init__.py | 0 tests/specific/test_git.py | 29 ++++++++ tests/specific/test_sudo.py | 18 +++++ tests/test_utils.py | 40 +---------- thefuck/rules/cd_correction.py | 2 +- thefuck/rules/cd_mkdir.py | 2 +- thefuck/rules/cp_omitting_directory.py | 2 +- thefuck/rules/docker_not_command.py | 3 +- thefuck/rules/fix_alt_space.py | 2 +- thefuck/rules/git_add.py | 5 +- thefuck/rules/git_branch_delete.py | 5 +- thefuck/rules/git_branch_list.py | 5 +- thefuck/rules/git_checkout.py | 5 +- thefuck/rules/git_diff_staged.py | 5 +- thefuck/rules/git_fix_stash.py | 5 +- thefuck/rules/git_not_command.py | 4 +- thefuck/rules/git_pull.py | 5 +- thefuck/rules/git_pull_clone.py | 5 +- thefuck/rules/git_push.py | 5 +- thefuck/rules/git_push_force.py | 5 +- thefuck/rules/git_push_pull.py | 5 +- thefuck/rules/git_stash.py | 5 +- thefuck/rules/has_exists_script.py | 2 +- thefuck/rules/lein_not_task.py | 4 +- thefuck/rules/mkdir_p.py | 2 +- thefuck/rules/no_command.py | 3 +- thefuck/rules/pacman.py | 2 +- thefuck/rules/pacman_not_found.py | 3 +- thefuck/rules/python_command.py | 2 +- thefuck/rules/rm_dir.py | 2 +- thefuck/rules/rm_root.py | 3 +- thefuck/rules/systemctl.py | 2 +- thefuck/specific/__init__.py | 0 thefuck/specific/archlinux.py | 41 +++++++++++ thefuck/specific/git.py | 37 ++++++++++ thefuck/specific/sudo.py | 24 +++++++ thefuck/utils.py | 99 +------------------------- 39 files changed, 214 insertions(+), 182 deletions(-) create mode 100644 tests/specific/__init__.py create mode 100644 tests/specific/test_git.py create mode 100644 tests/specific/test_sudo.py create mode 100644 thefuck/specific/__init__.py create mode 100644 thefuck/specific/archlinux.py create mode 100644 thefuck/specific/git.py create mode 100644 thefuck/specific/sudo.py diff --git a/tests/rules/test_pacman.py b/tests/rules/test_pacman.py index 4f42d677..f0e00515 100644 --- a/tests/rules/test_pacman.py +++ b/tests/rules/test_pacman.py @@ -29,7 +29,7 @@ def test_match(command): @pytest.mark.parametrize('command, return_value', [ (Command(script='vim', stderr='vim: command not found'), PKGFILE_OUTPUT_VIM), (Command(script='sudo vim', stderr='sudo: vim: command not found'), PKGFILE_OUTPUT_VIM)]) -@patch('thefuck.utils.subprocess') +@patch('thefuck.specific.archlinux.subprocess') @patch.multiple(pacman, create=True, pacman=pacman_cmd) def test_match_mocked(subp_mock, command, return_value): subp_mock.check_output.return_value = return_value @@ -75,7 +75,7 @@ def test_get_new_command(command, new_command, mocker): (Command('convert'), ['{} -S extra/imagemagick && convert'.format(pacman_cmd)], PKGFILE_OUTPUT_CONVERT), (Command('sudo'), ['{} -S core/sudo && sudo'.format(pacman_cmd)], PKGFILE_OUTPUT_SUDO), (Command('sudo convert'), ['{} -S extra/imagemagick && sudo convert'.format(pacman_cmd)], PKGFILE_OUTPUT_CONVERT)]) -@patch('thefuck.utils.subprocess') +@patch('thefuck.specific.archlinux.subprocess') @patch.multiple(pacman, create=True, pacman=pacman_cmd) def test_get_new_command_mocked(subp_mock, command, new_command, return_value): subp_mock.check_output.return_value = return_value diff --git a/tests/rules/test_pacman_not_found.py b/tests/rules/test_pacman_not_found.py index d659bd1f..c1c4a8da 100644 --- a/tests/rules/test_pacman_not_found.py +++ b/tests/rules/test_pacman_not_found.py @@ -22,7 +22,7 @@ def test_match(command): Command(script='yaourt -S llc', stderr='error: target not found: llc'), Command(script='pacman llc', stderr='error: target not found: llc'), Command(script='sudo pacman llc', stderr='error: target not found: llc')]) -@patch('thefuck.utils.subprocess') +@patch('thefuck.specific.archlinux.subprocess') def test_match_mocked(subp_mock, command): subp_mock.check_output.return_value = PKGFILE_OUTPUT_LLC assert match(command, None) @@ -42,7 +42,7 @@ def test_get_new_command(command, fixed): (Command(script='yaourt -S llc', stderr='error: target not found: llc'), ['yaourt -S extra/llvm', 'yaourt -S extra/llvm35']), (Command(script='pacman -S llc', stderr='error: target not found: llc'), ['pacman -S extra/llvm', 'pacman -S extra/llvm35']), (Command(script='sudo pacman -S llc', stderr='error: target not found: llc'), ['sudo pacman -S extra/llvm', 'sudo pacman -S extra/llvm35'])]) -@patch('thefuck.utils.subprocess') +@patch('thefuck.specific.archlinux.subprocess') def test_get_new_command_mocked(subp_mock, command, fixed): subp_mock.check_output.return_value = PKGFILE_OUTPUT_LLC assert get_new_command(command, None) == fixed diff --git a/tests/specific/__init__.py b/tests/specific/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/specific/test_git.py b/tests/specific/test_git.py new file mode 100644 index 00000000..549ce61c --- /dev/null +++ b/tests/specific/test_git.py @@ -0,0 +1,29 @@ +import pytest +from thefuck.specific.git import git_support +from tests.utils import Command + + +@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 + + +@pytest.mark.parametrize('command, is_git', [ + ('git pull', True), + ('hub pull', True), + ('git push --set-upstream origin foo', True), + ('hub push --set-upstream origin foo', True), + ('ls', False), + ('cat git', False), + ('cat hub', False)]) +def test_git_support_match(command, is_git): + @git_support + def fn(command, settings): return True + + assert fn(Command(script=command), None) == is_git diff --git a/tests/specific/test_sudo.py b/tests/specific/test_sudo.py new file mode 100644 index 00000000..46afa5c2 --- /dev/null +++ b/tests/specific/test_sudo.py @@ -0,0 +1,18 @@ +import pytest +from mock import Mock +from thefuck.specific.sudo import sudo_support +from tests.utils import Command + + +@pytest.mark.parametrize('return_value, command, called, result', [ + ('ls -lah', 'sudo ls', 'ls', 'sudo ls -lah'), + ('ls -lah', 'ls', 'ls', 'ls -lah'), + (['ls -lah'], 'sudo ls', 'ls', ['sudo ls -lah']), + (True, 'sudo ls', 'ls', True), + (True, 'ls', 'ls', True), + (False, 'sudo ls', 'ls', False), + (False, 'ls', 'ls', False)]) +def test_sudo_support(return_value, command, called, result): + fn = Mock(return_value=return_value, __name__='') + assert sudo_support(fn)(Command(command), None) == result + fn.assert_called_once_with(Command(called), None) diff --git a/tests/test_utils.py b/tests/test_utils.py index c31d91ad..b66f4c8e 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,10 +1,9 @@ import pytest from mock import Mock -from thefuck.utils import git_support, sudo_support, wrap_settings,\ +from thefuck.utils import wrap_settings,\ memoize, get_closest, get_all_executables, replace_argument, \ get_all_matched_commands from thefuck.types import Settings -from tests.utils import Command @pytest.mark.parametrize('override, old, new', [ @@ -16,43 +15,6 @@ def test_wrap_settings(override, old, new): assert wrap_settings(override)(fn)(None, Settings(old)) == new -@pytest.mark.parametrize('return_value, command, called, result', [ - ('ls -lah', 'sudo ls', 'ls', 'sudo ls -lah'), - ('ls -lah', 'ls', 'ls', 'ls -lah'), - (['ls -lah'], 'sudo ls', 'ls', ['sudo ls -lah']), - (True, 'sudo ls', 'ls', True), - (True, 'ls', 'ls', True), - (False, 'sudo ls', 'ls', False), - (False, 'ls', 'ls', False)]) -def test_sudo_support(return_value, command, called, result): - fn = Mock(return_value=return_value, __name__='') - assert sudo_support(fn)(Command(command), None) == result - 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 - - -@pytest.mark.parametrize('command, is_git', [ - ('git pull', True), - ('hub pull', True), - ('git push --set-upstream origin foo', True), - ('hub push --set-upstream origin foo', True), - ('ls', False), - ('cat git', False), - ('cat hub', False)]) -def test_git_support_match(command, is_git): - @git_support - def fn(command, settings): return True - assert fn(Command(script=command), None) == is_git - - def test_memoize(): fn = Mock(__name__='fn') memoized = memoize(fn) diff --git a/thefuck/rules/cd_correction.py b/thefuck/rules/cd_correction.py index 81c5ef7c..1567ff09 100644 --- a/thefuck/rules/cd_correction.py +++ b/thefuck/rules/cd_correction.py @@ -2,7 +2,7 @@ import os from difflib import get_close_matches -from thefuck.utils import sudo_support +from thefuck.specific.sudo import sudo_support from thefuck.rules import cd_mkdir __author__ = "mmussomele" diff --git a/thefuck/rules/cd_mkdir.py b/thefuck/rules/cd_mkdir.py index 168a2ce0..c9ad1f7e 100644 --- a/thefuck/rules/cd_mkdir.py +++ b/thefuck/rules/cd_mkdir.py @@ -1,6 +1,6 @@ import re from thefuck import shells -from thefuck.utils import sudo_support +from thefuck.specific.sudo import sudo_support @sudo_support diff --git a/thefuck/rules/cp_omitting_directory.py b/thefuck/rules/cp_omitting_directory.py index fa6f3e12..9a110e0c 100644 --- a/thefuck/rules/cp_omitting_directory.py +++ b/thefuck/rules/cp_omitting_directory.py @@ -1,5 +1,5 @@ import re -from thefuck.utils import sudo_support +from thefuck.specific.sudo import sudo_support @sudo_support diff --git a/thefuck/rules/docker_not_command.py b/thefuck/rules/docker_not_command.py index 1c7e84c6..73cb8611 100644 --- a/thefuck/rules/docker_not_command.py +++ b/thefuck/rules/docker_not_command.py @@ -1,7 +1,8 @@ from itertools import dropwhile, takewhile, islice import re import subprocess -from thefuck.utils import sudo_support, replace_command +from thefuck.utils import replace_command +from thefuck.specific.sudo import sudo_support @sudo_support diff --git a/thefuck/rules/fix_alt_space.py b/thefuck/rules/fix_alt_space.py index 3c74ab31..f807c198 100644 --- a/thefuck/rules/fix_alt_space.py +++ b/thefuck/rules/fix_alt_space.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- import re -from thefuck.utils import sudo_support +from thefuck.specific.sudo import sudo_support @sudo_support diff --git a/thefuck/rules/git_add.py b/thefuck/rules/git_add.py index cb92e804..f90f2836 100644 --- a/thefuck/rules/git_add.py +++ b/thefuck/rules/git_add.py @@ -1,14 +1,15 @@ import re from thefuck import utils, shells +from thefuck.specific.git import git_support -@utils.git_support +@git_support def match(command, settings): return ('did not match any file(s) known to git.' in command.stderr and "Did you forget to 'git add'?" in command.stderr) -@utils.git_support +@git_support def get_new_command(command, settings): missing_file = re.findall( r"error: pathspec '([^']*)' " diff --git a/thefuck/rules/git_branch_delete.py b/thefuck/rules/git_branch_delete.py index 781aad37..14a96855 100644 --- a/thefuck/rules/git_branch_delete.py +++ b/thefuck/rules/git_branch_delete.py @@ -1,13 +1,14 @@ from thefuck import utils from thefuck.utils import replace_argument +from thefuck.specific.git import git_support -@utils.git_support +@git_support def match(command, settings): return ('branch -d' in command.script and 'If you are sure you want to delete it' in command.stderr) -@utils.git_support +@git_support def get_new_command(command, settings): return replace_argument(command.script, '-d', '-D') diff --git a/thefuck/rules/git_branch_list.py b/thefuck/rules/git_branch_list.py index b3975408..07fb81ee 100644 --- a/thefuck/rules/git_branch_list.py +++ b/thefuck/rules/git_branch_list.py @@ -1,12 +1,13 @@ from thefuck import utils, shells +from thefuck.specific.git import git_support -@utils.git_support +@git_support def match(command, settings): # catches "git branch list" in place of "git branch" return command.script.split()[1:] == 'branch list'.split() -@utils.git_support +@git_support def get_new_command(command, settings): return shells.and_('git branch --delete list', 'git branch') diff --git a/thefuck/rules/git_checkout.py b/thefuck/rules/git_checkout.py index b883fca6..de165fa5 100644 --- a/thefuck/rules/git_checkout.py +++ b/thefuck/rules/git_checkout.py @@ -2,9 +2,10 @@ import re import subprocess from thefuck import shells, utils from thefuck.utils import replace_argument +from thefuck.specific.git import git_support -@utils.git_support +@git_support def match(command, settings): return ('did not match any file(s) known to git.' in command.stderr and "Did you forget to 'git add'?" not in command.stderr) @@ -23,7 +24,7 @@ def get_branches(): yield line.strip() -@utils.git_support +@git_support def get_new_command(command, settings): missing_file = re.findall( r"error: pathspec '([^']*)' " diff --git a/thefuck/rules/git_diff_staged.py b/thefuck/rules/git_diff_staged.py index 91b46e0e..d755a5c6 100644 --- a/thefuck/rules/git_diff_staged.py +++ b/thefuck/rules/git_diff_staged.py @@ -1,13 +1,14 @@ from thefuck import utils from thefuck.utils import replace_argument +from thefuck.specific.git import git_support -@utils.git_support +@git_support def match(command, settings): return ('diff' in command.script and '--staged' not in command.script) -@utils.git_support +@git_support def get_new_command(command, settings): return replace_argument(command.script, 'diff', 'diff --staged') diff --git a/thefuck/rules/git_fix_stash.py b/thefuck/rules/git_fix_stash.py index cedfcaf5..b83b539e 100644 --- a/thefuck/rules/git_fix_stash.py +++ b/thefuck/rules/git_fix_stash.py @@ -1,8 +1,9 @@ from thefuck import utils from thefuck.utils import replace_argument +from thefuck.specific.git import git_support -@utils.git_support +@git_support def match(command, settings): return (command.script.split()[1] == 'stash' and 'usage:' in command.stderr) @@ -19,7 +20,7 @@ stash_commands = ( 'show') -@utils.git_support +@git_support def get_new_command(command, settings): stash_cmd = command.script.split()[2] fixed = utils.get_closest(stash_cmd, stash_commands, fallback_to_first=False) diff --git a/thefuck/rules/git_not_command.py b/thefuck/rules/git_not_command.py index 65df0a97..6c6675ff 100644 --- a/thefuck/rules/git_not_command.py +++ b/thefuck/rules/git_not_command.py @@ -1,6 +1,6 @@ import re -from thefuck.utils import (git_support, - get_all_matched_commands, replace_command) +from thefuck.utils import get_all_matched_commands, replace_command +from thefuck.specific.git import git_support @git_support diff --git a/thefuck/rules/git_pull.py b/thefuck/rules/git_pull.py index 773cfa31..9c2d8284 100644 --- a/thefuck/rules/git_pull.py +++ b/thefuck/rules/git_pull.py @@ -1,13 +1,14 @@ from thefuck import shells, utils +from thefuck.specific.git import git_support -@utils.git_support +@git_support def match(command, settings): return ('pull' in command.script and 'set-upstream' in command.stderr) -@utils.git_support +@git_support def get_new_command(command, settings): line = command.stderr.split('\n')[-3].strip() branch = line.split(' ')[-1] diff --git a/thefuck/rules/git_pull_clone.py b/thefuck/rules/git_pull_clone.py index a62f941c..a5c27f17 100644 --- a/thefuck/rules/git_pull_clone.py +++ b/thefuck/rules/git_pull_clone.py @@ -1,13 +1,14 @@ from thefuck import utils from thefuck.utils import replace_argument +from thefuck.specific.git import git_support -@utils.git_support +@git_support def match(command, settings): return ('fatal: Not a git repository' in command.stderr and "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)." in command.stderr) -@utils.git_support +@git_support def get_new_command(command, settings): return replace_argument(command.script, 'pull', 'clone') diff --git a/thefuck/rules/git_push.py b/thefuck/rules/git_push.py index 34b16d21..adea0175 100644 --- a/thefuck/rules/git_push.py +++ b/thefuck/rules/git_push.py @@ -1,12 +1,13 @@ from thefuck import utils +from thefuck.specific.git import git_support -@utils.git_support +@git_support def match(command, settings): return ('push' in command.script and 'set-upstream' in command.stderr) -@utils.git_support +@git_support def get_new_command(command, settings): return command.stderr.split('\n')[-3].strip() diff --git a/thefuck/rules/git_push_force.py b/thefuck/rules/git_push_force.py index 5016545c..52ecfe32 100644 --- a/thefuck/rules/git_push_force.py +++ b/thefuck/rules/git_push_force.py @@ -1,8 +1,9 @@ from thefuck import utils from thefuck.utils import replace_argument +from thefuck.specific.git import git_support -@utils.git_support +@git_support def match(command, settings): return ('push' in command.script and '! [rejected]' in command.stderr @@ -10,7 +11,7 @@ def match(command, settings): and 'Updates were rejected because the tip of your current branch is behind' in command.stderr) -@utils.git_support +@git_support def get_new_command(command, settings): return replace_argument(command.script, 'push', 'push --force') diff --git a/thefuck/rules/git_push_pull.py b/thefuck/rules/git_push_pull.py index f2174bee..85ec7cb6 100644 --- a/thefuck/rules/git_push_pull.py +++ b/thefuck/rules/git_push_pull.py @@ -1,8 +1,9 @@ from thefuck import utils, shells from thefuck.utils import replace_argument +from thefuck.specific.git import git_support -@utils.git_support +@git_support def match(command, settings): return ('push' in command.script and '! [rejected]' in command.stderr @@ -10,7 +11,7 @@ def match(command, settings): and 'Updates were rejected because the tip of your current branch is behind' in command.stderr) -@utils.git_support +@git_support def get_new_command(command, settings): return shells.and_(replace_argument(command.script, 'push', 'pull'), command.script) diff --git a/thefuck/rules/git_stash.py b/thefuck/rules/git_stash.py index 1fb0286e..ee92a049 100644 --- a/thefuck/rules/git_stash.py +++ b/thefuck/rules/git_stash.py @@ -1,14 +1,15 @@ from thefuck import shells, utils +from thefuck.specific.git import git_support -@utils.git_support +@git_support def match(command, settings): # catches "Please commit or stash them" and "Please, commit your changes or # stash them before you can switch branches." return 'or stash them' in command.stderr -@utils.git_support +@git_support def get_new_command(command, settings): formatme = shells.and_('git stash', '{}') return formatme.format(command.script) diff --git a/thefuck/rules/has_exists_script.py b/thefuck/rules/has_exists_script.py index 57a12fd5..3413237f 100644 --- a/thefuck/rules/has_exists_script.py +++ b/thefuck/rules/has_exists_script.py @@ -1,5 +1,5 @@ import os -from thefuck.utils import sudo_support +from thefuck.specific.sudo import sudo_support @sudo_support diff --git a/thefuck/rules/lein_not_task.py b/thefuck/rules/lein_not_task.py index 34e46fe3..db98c951 100644 --- a/thefuck/rules/lein_not_task.py +++ b/thefuck/rules/lein_not_task.py @@ -1,6 +1,6 @@ import re -from thefuck.utils import sudo_support,\ - replace_command, get_all_matched_commands +from thefuck.utils import replace_command, get_all_matched_commands +from thefuck.specific.sudo import sudo_support @sudo_support diff --git a/thefuck/rules/mkdir_p.py b/thefuck/rules/mkdir_p.py index a62b4474..013bfc16 100644 --- a/thefuck/rules/mkdir_p.py +++ b/thefuck/rules/mkdir_p.py @@ -1,5 +1,5 @@ import re -from thefuck.utils import sudo_support +from thefuck.specific.sudo import sudo_support @sudo_support diff --git a/thefuck/rules/no_command.py b/thefuck/rules/no_command.py index a8258ce0..2e77594f 100644 --- a/thefuck/rules/no_command.py +++ b/thefuck/rules/no_command.py @@ -1,5 +1,6 @@ from difflib import get_close_matches -from thefuck.utils import sudo_support, get_all_executables +from thefuck.utils import get_all_executables +from thefuck.specific.sudo import sudo_support @sudo_support diff --git a/thefuck/rules/pacman.py b/thefuck/rules/pacman.py index 65a50ef4..94257797 100644 --- a/thefuck/rules/pacman.py +++ b/thefuck/rules/pacman.py @@ -1,4 +1,4 @@ -from thefuck.utils import get_pkgfile, archlinux_env +from thefuck.specific.archlinux import get_pkgfile, archlinux_env from thefuck import shells diff --git a/thefuck/rules/pacman_not_found.py b/thefuck/rules/pacman_not_found.py index d71b74d2..d8159b26 100644 --- a/thefuck/rules/pacman_not_found.py +++ b/thefuck/rules/pacman_not_found.py @@ -6,7 +6,8 @@ should be: yaourt -S llvm """ -from thefuck.utils import replace_command, get_pkgfile, archlinux_env +from thefuck.utils import replace_command +from thefuck.specific.archlinux import get_pkgfile, archlinux_env def match(command, settings): diff --git a/thefuck/rules/python_command.py b/thefuck/rules/python_command.py index f2bc8dce..42cf18db 100644 --- a/thefuck/rules/python_command.py +++ b/thefuck/rules/python_command.py @@ -1,4 +1,4 @@ -from thefuck.utils import sudo_support +from thefuck.specific.sudo import sudo_support # add 'python' suffix to the command if # 1) The script does not have execute permission or # 2) is interpreted as shell script diff --git a/thefuck/rules/rm_dir.py b/thefuck/rules/rm_dir.py index 05be3710..9a8baa77 100644 --- a/thefuck/rules/rm_dir.py +++ b/thefuck/rules/rm_dir.py @@ -1,5 +1,5 @@ import re -from thefuck.utils import sudo_support +from thefuck.specific.sudo import sudo_support @sudo_support diff --git a/thefuck/rules/rm_root.py b/thefuck/rules/rm_root.py index ed0121f5..9c89f3a7 100644 --- a/thefuck/rules/rm_root.py +++ b/thefuck/rules/rm_root.py @@ -1,5 +1,4 @@ -from thefuck.utils import sudo_support - +from thefuck.specific.sudo import sudo_support enabled_by_default = False diff --git a/thefuck/rules/systemctl.py b/thefuck/rules/systemctl.py index 9bd791c3..ef8c0ca1 100644 --- a/thefuck/rules/systemctl.py +++ b/thefuck/rules/systemctl.py @@ -1,7 +1,7 @@ """ The confusion in systemctl's param order is massive. """ -from thefuck.utils import sudo_support +from thefuck.specific.sudo import sudo_support @sudo_support diff --git a/thefuck/specific/__init__.py b/thefuck/specific/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/thefuck/specific/archlinux.py b/thefuck/specific/archlinux.py new file mode 100644 index 00000000..04b97149 --- /dev/null +++ b/thefuck/specific/archlinux.py @@ -0,0 +1,41 @@ +""" This file provide some utility functions for Arch Linux specific rules.""" +import thefuck.utils +import subprocess + + +@thefuck.utils.memoize +def get_pkgfile(command): + """ Gets the packages that provide the given command using `pkgfile`. + + If the command is of the form `sudo foo`, searches for the `foo` command + instead. + """ + try: + command = command.strip() + + if command.startswith('sudo '): + command = command[5:] + + command = command.split(" ")[0] + + packages = subprocess.check_output( + ['pkgfile', '-b', '-v', command], + universal_newlines=True, stderr=thefuck.utils.DEVNULL + ).splitlines() + + return [package.split()[0] for package in packages] + except subprocess.CalledProcessError: + return None + + +def archlinux_env(): + if thefuck.utils.which('yaourt'): + pacman = 'yaourt' + elif thefuck.utils.which('pacman'): + pacman = 'sudo pacman' + else: + return False, None + + enabled_by_default = thefuck.utils.which('pkgfile') + + return enabled_by_default, pacman diff --git a/thefuck/specific/git.py b/thefuck/specific/git.py new file mode 100644 index 00000000..b6cd22ff --- /dev/null +++ b/thefuck/specific/git.py @@ -0,0 +1,37 @@ +from functools import wraps +import re +from shlex import split +from ..types import Command +from ..utils import quote + + +def git_support(fn): + """Resolves git aliases and supports testing for both git and hub.""" + @wraps(fn) + 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 + if 'trace: alias expansion:' in command.stderr: + search = re.search("trace: alias expansion: ([^ ]*) => ([^\n]*)", + command.stderr) + alias = search.group(1) + + # by default git quotes everything, 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 diff --git a/thefuck/specific/sudo.py b/thefuck/specific/sudo.py new file mode 100644 index 00000000..88a6cb07 --- /dev/null +++ b/thefuck/specific/sudo.py @@ -0,0 +1,24 @@ +from functools import wraps +import six +from ..types import Command + + +def sudo_support(fn): + """Removes sudo before calling fn and adds it after.""" + @wraps(fn) + def wrapper(command, settings): + if not command.script.startswith('sudo '): + return fn(command, settings) + + result = fn(Command(command.script[5:], + command.stdout, + command.stderr), + settings) + + if result and isinstance(result, six.string_types): + return u'sudo {}'.format(result) + elif isinstance(result, list): + return [u'sudo {}'.format(x) for x in result] + else: + return result + return wrapper \ No newline at end of file diff --git a/thefuck/utils.py b/thefuck/utils.py index 9f29590f..8dd777b7 100644 --- a/thefuck/utils.py +++ b/thefuck/utils.py @@ -1,14 +1,12 @@ -from subprocess import CalledProcessError -import subprocess from difflib import get_close_matches from functools import wraps -from pathlib import Path -from shlex import split + import os import pickle import re + +from pathlib import Path import six -from .types import Command DEVNULL = open(os.devnull, 'w') @@ -57,59 +55,6 @@ def wrap_settings(params): return decorator -def sudo_support(fn): - """Removes sudo before calling fn and adds it after.""" - @wraps(fn) - def wrapper(command, settings): - if not command.script.startswith('sudo '): - return fn(command, settings) - - result = fn(Command(command.script[5:], - command.stdout, - command.stderr), - settings) - - if result and isinstance(result, six.string_types): - return u'sudo {}'.format(result) - elif isinstance(result, list): - return [u'sudo {}'.format(x) for x in result] - else: - return result - return wrapper - - -def git_support(fn): - """Resolves git aliases and supports testing for both git and hub.""" - @wraps(fn) - 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 - if 'trace: alias expansion:' in command.stderr: - search = re.search("trace: alias expansion: ([^ ]*) => ([^\n]*)", - command.stderr) - alias = search.group(1) - - # by default git quotes everything, 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): """Caches previous calls to the function.""" memo = {} @@ -187,41 +132,3 @@ def replace_command(command, broken, matched): new_cmds = get_close_matches(broken, matched, cutoff=0.1) return [replace_argument(command.script, broken, new_cmd.strip()) for new_cmd in new_cmds] - - -@memoize -def get_pkgfile(command): - """ Gets the packages that provide the given command using `pkgfile`. - - If the command is of the form `sudo foo`, searches for the `foo` command - instead. - """ - try: - command = command.strip() - - if command.startswith('sudo '): - command = command[5:] - - command = command.split(" ")[0] - - packages = subprocess.check_output( - ['pkgfile', '-b', '-v', command], - universal_newlines=True, stderr=DEVNULL - ).splitlines() - - return [package.split()[0] for package in packages] - except CalledProcessError: - return None - - -def archlinux_env(): - if which('yaourt'): - pacman = 'yaourt' - elif which('pacman'): - pacman = 'sudo pacman' - else: - return False, None - - enabled_by_default = which('pkgfile') - - return enabled_by_default, pacman \ No newline at end of file