1
0
mirror of https://github.com/nvbn/thefuck.git synced 2025-01-31 02:01:13 +00:00

Move all app/os specific utils to specific package

This commit is contained in:
nvbn 2015-08-25 14:09:47 +03:00
parent 2e002f666b
commit b21c9ebb43
39 changed files with 214 additions and 182 deletions

View File

@ -29,7 +29,7 @@ def test_match(command):
@pytest.mark.parametrize('command, return_value', [ @pytest.mark.parametrize('command, return_value', [
(Command(script='vim', stderr='vim: command not found'), PKGFILE_OUTPUT_VIM), (Command(script='vim', stderr='vim: command not found'), PKGFILE_OUTPUT_VIM),
(Command(script='sudo vim', stderr='sudo: 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) @patch.multiple(pacman, create=True, pacman=pacman_cmd)
def test_match_mocked(subp_mock, command, return_value): def test_match_mocked(subp_mock, command, return_value):
subp_mock.check_output.return_value = 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('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'), ['{} -S core/sudo && sudo'.format(pacman_cmd)], PKGFILE_OUTPUT_SUDO),
(Command('sudo convert'), ['{} -S extra/imagemagick && sudo convert'.format(pacman_cmd)], PKGFILE_OUTPUT_CONVERT)]) (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) @patch.multiple(pacman, create=True, pacman=pacman_cmd)
def test_get_new_command_mocked(subp_mock, command, new_command, return_value): def test_get_new_command_mocked(subp_mock, command, new_command, return_value):
subp_mock.check_output.return_value = return_value subp_mock.check_output.return_value = return_value

View File

@ -22,7 +22,7 @@ def test_match(command):
Command(script='yaourt -S llc', stderr='error: target not found: llc'), Command(script='yaourt -S llc', stderr='error: target not found: llc'),
Command(script='pacman 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')]) 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): def test_match_mocked(subp_mock, command):
subp_mock.check_output.return_value = PKGFILE_OUTPUT_LLC subp_mock.check_output.return_value = PKGFILE_OUTPUT_LLC
assert match(command, None) 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='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='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'])]) (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): def test_get_new_command_mocked(subp_mock, command, fixed):
subp_mock.check_output.return_value = PKGFILE_OUTPUT_LLC subp_mock.check_output.return_value = PKGFILE_OUTPUT_LLC
assert get_new_command(command, None) == fixed assert get_new_command(command, None) == fixed

View File

View File

@ -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

View File

@ -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)

View File

@ -1,10 +1,9 @@
import pytest import pytest
from mock import Mock 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, \ memoize, get_closest, get_all_executables, replace_argument, \
get_all_matched_commands get_all_matched_commands
from thefuck.types import Settings from thefuck.types import Settings
from tests.utils import Command
@pytest.mark.parametrize('override, old, new', [ @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 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(): def test_memoize():
fn = Mock(__name__='fn') fn = Mock(__name__='fn')
memoized = memoize(fn) memoized = memoize(fn)

View File

@ -2,7 +2,7 @@
import os import os
from difflib import get_close_matches 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 from thefuck.rules import cd_mkdir
__author__ = "mmussomele" __author__ = "mmussomele"

View File

@ -1,6 +1,6 @@
import re import re
from thefuck import shells from thefuck import shells
from thefuck.utils import sudo_support from thefuck.specific.sudo import sudo_support
@sudo_support @sudo_support

View File

@ -1,5 +1,5 @@
import re import re
from thefuck.utils import sudo_support from thefuck.specific.sudo import sudo_support
@sudo_support @sudo_support

View File

@ -1,7 +1,8 @@
from itertools import dropwhile, takewhile, islice from itertools import dropwhile, takewhile, islice
import re import re
import subprocess 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 @sudo_support

View File

@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
import re import re
from thefuck.utils import sudo_support from thefuck.specific.sudo import sudo_support
@sudo_support @sudo_support

View File

@ -1,14 +1,15 @@
import re import re
from thefuck import utils, shells from thefuck import utils, shells
from thefuck.specific.git import git_support
@utils.git_support @git_support
def match(command, settings): def match(command, settings):
return ('did not match any file(s) known to git.' in command.stderr return ('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 @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,13 +1,14 @@
from thefuck import utils from thefuck import utils
from thefuck.utils import replace_argument from thefuck.utils import replace_argument
from thefuck.specific.git import git_support
@utils.git_support @git_support
def match(command, settings): def match(command, settings):
return ('branch -d' in command.script return ('branch -d' in command.script
and 'If you are sure you want to delete it' in command.stderr) and 'If you are sure you want to delete it' in command.stderr)
@utils.git_support @git_support
def get_new_command(command, settings): def get_new_command(command, settings):
return replace_argument(command.script, '-d', '-D') return replace_argument(command.script, '-d', '-D')

View File

@ -1,12 +1,13 @@
from thefuck import utils, shells from thefuck import utils, shells
from thefuck.specific.git import git_support
@utils.git_support @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()[1:] == 'branch list'.split() return command.script.split()[1:] == 'branch list'.split()
@utils.git_support @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

@ -2,9 +2,10 @@ import re
import subprocess import subprocess
from thefuck import shells, utils from thefuck import shells, utils
from thefuck.utils import replace_argument from thefuck.utils import replace_argument
from thefuck.specific.git import git_support
@utils.git_support @git_support
def match(command, settings): def match(command, settings):
return ('did not match any file(s) known to git.' in command.stderr return ('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)
@ -23,7 +24,7 @@ def get_branches():
yield line.strip() yield line.strip()
@utils.git_support @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,13 +1,14 @@
from thefuck import utils from thefuck import utils
from thefuck.utils import replace_argument from thefuck.utils import replace_argument
from thefuck.specific.git import git_support
@utils.git_support @git_support
def match(command, settings): def match(command, settings):
return ('diff' in command.script and return ('diff' in command.script and
'--staged' not in command.script) '--staged' not in command.script)
@utils.git_support @git_support
def get_new_command(command, settings): def get_new_command(command, settings):
return replace_argument(command.script, 'diff', 'diff --staged') return replace_argument(command.script, 'diff', 'diff --staged')

View File

@ -1,8 +1,9 @@
from thefuck import utils from thefuck import utils
from thefuck.utils import replace_argument from thefuck.utils import replace_argument
from thefuck.specific.git import git_support
@utils.git_support @git_support
def match(command, settings): def match(command, settings):
return (command.script.split()[1] == 'stash' return (command.script.split()[1] == 'stash'
and 'usage:' in command.stderr) and 'usage:' in command.stderr)
@ -19,7 +20,7 @@ stash_commands = (
'show') 'show')
@utils.git_support @git_support
def get_new_command(command, settings): def get_new_command(command, settings):
stash_cmd = command.script.split()[2] stash_cmd = command.script.split()[2]
fixed = utils.get_closest(stash_cmd, stash_commands, fallback_to_first=False) fixed = utils.get_closest(stash_cmd, stash_commands, fallback_to_first=False)

View File

@ -1,6 +1,6 @@
import re import re
from thefuck.utils import (git_support, from thefuck.utils import get_all_matched_commands, replace_command
get_all_matched_commands, replace_command) from thefuck.specific.git import git_support
@git_support @git_support

View File

@ -1,13 +1,14 @@
from thefuck import shells, utils from thefuck import shells, utils
from thefuck.specific.git import git_support
@utils.git_support @git_support
def match(command, settings): def match(command, settings):
return ('pull' in command.script return ('pull' in command.script
and 'set-upstream' in command.stderr) and 'set-upstream' in command.stderr)
@utils.git_support @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,13 +1,14 @@
from thefuck import utils from thefuck import utils
from thefuck.utils import replace_argument from thefuck.utils import replace_argument
from thefuck.specific.git import git_support
@utils.git_support @git_support
def match(command, settings): def match(command, settings):
return ('fatal: Not a git repository' in command.stderr return ('fatal: Not a git repository' in command.stderr
and "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)." 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): def get_new_command(command, settings):
return replace_argument(command.script, 'pull', 'clone') return replace_argument(command.script, 'pull', 'clone')

View File

@ -1,12 +1,13 @@
from thefuck import utils from thefuck import utils
from thefuck.specific.git import git_support
@utils.git_support @git_support
def match(command, settings): def match(command, settings):
return ('push' in command.script return ('push' in command.script
and 'set-upstream' in command.stderr) and 'set-upstream' in command.stderr)
@utils.git_support @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,8 +1,9 @@
from thefuck import utils from thefuck import utils
from thefuck.utils import replace_argument from thefuck.utils import replace_argument
from thefuck.specific.git import git_support
@utils.git_support @git_support
def match(command, settings): def match(command, settings):
return ('push' in command.script return ('push' in command.script
and '! [rejected]' in command.stderr 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) 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): def get_new_command(command, settings):
return replace_argument(command.script, 'push', 'push --force') return replace_argument(command.script, 'push', 'push --force')

View File

@ -1,8 +1,9 @@
from thefuck import utils, shells from thefuck import utils, shells
from thefuck.utils import replace_argument from thefuck.utils import replace_argument
from thefuck.specific.git import git_support
@utils.git_support @git_support
def match(command, settings): def match(command, settings):
return ('push' in command.script return ('push' in command.script
and '! [rejected]' in command.stderr 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) 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): def get_new_command(command, settings):
return shells.and_(replace_argument(command.script, 'push', 'pull'), return shells.and_(replace_argument(command.script, 'push', 'pull'),
command.script) command.script)

View File

@ -1,14 +1,15 @@
from thefuck import shells, utils from thefuck import shells, utils
from thefuck.specific.git import git_support
@utils.git_support @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 'or stash them' in command.stderr return 'or stash them' in command.stderr
@utils.git_support @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,5 +1,5 @@
import os import os
from thefuck.utils import sudo_support from thefuck.specific.sudo import sudo_support
@sudo_support @sudo_support

View File

@ -1,6 +1,6 @@
import re import re
from thefuck.utils import sudo_support,\ from thefuck.utils import replace_command, get_all_matched_commands
replace_command, get_all_matched_commands from thefuck.specific.sudo import sudo_support
@sudo_support @sudo_support

View File

@ -1,5 +1,5 @@
import re import re
from thefuck.utils import sudo_support from thefuck.specific.sudo import sudo_support
@sudo_support @sudo_support

View File

@ -1,5 +1,6 @@
from difflib import get_close_matches 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 @sudo_support

View File

@ -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 from thefuck import shells

View File

@ -6,7 +6,8 @@ should be:
yaourt -S llvm 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): def match(command, settings):

View File

@ -1,4 +1,4 @@
from thefuck.utils import sudo_support from thefuck.specific.sudo import sudo_support
# add 'python' suffix to the command if # add 'python' suffix to the command if
# 1) The script does not have execute permission or # 1) The script does not have execute permission or
# 2) is interpreted as shell script # 2) is interpreted as shell script

View File

@ -1,5 +1,5 @@
import re import re
from thefuck.utils import sudo_support from thefuck.specific.sudo import sudo_support
@sudo_support @sudo_support

View File

@ -1,5 +1,4 @@
from thefuck.utils import sudo_support from thefuck.specific.sudo import sudo_support
enabled_by_default = False enabled_by_default = False

View File

@ -1,7 +1,7 @@
""" """
The confusion in systemctl's param order is massive. The confusion in systemctl's param order is massive.
""" """
from thefuck.utils import sudo_support from thefuck.specific.sudo import sudo_support
@sudo_support @sudo_support

View File

View File

@ -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

37
thefuck/specific/git.py Normal file
View File

@ -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

24
thefuck/specific/sudo.py Normal file
View File

@ -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

View File

@ -1,14 +1,12 @@
from subprocess import CalledProcessError
import subprocess
from difflib import get_close_matches from difflib import get_close_matches
from functools import wraps from functools import wraps
from pathlib import Path
from shlex import split
import os import os
import pickle import pickle
import re import re
from pathlib import Path
import six import six
from .types import Command
DEVNULL = open(os.devnull, 'w') DEVNULL = open(os.devnull, 'w')
@ -57,59 +55,6 @@ def wrap_settings(params):
return decorator 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): def memoize(fn):
"""Caches previous calls to the function.""" """Caches previous calls to the function."""
memo = {} memo = {}
@ -187,41 +132,3 @@ def replace_command(command, broken, matched):
new_cmds = get_close_matches(broken, matched, cutoff=0.1) new_cmds = get_close_matches(broken, matched, cutoff=0.1)
return [replace_argument(command.script, broken, new_cmd.strip()) return [replace_argument(command.script, broken, new_cmd.strip())
for new_cmd in new_cmds] 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