mirror of
				https://github.com/nvbn/thefuck.git
				synced 2025-10-31 07:04:12 +00:00 
			
		
		
		
	Merge pull request #335 from mcarton/pacman
Add a new rule for pacman/yaourt and fix the apt_get rule
This commit is contained in:
		| @@ -189,7 +189,7 @@ using the matched rule and runs it. Rules enabled by default are as follows: | ||||
| * `systemctl` – correctly orders parameters of confusing `systemctl`; | ||||
| * `test.py` – runs `py.test` instead of `test.py`; | ||||
| * `tsuru_login` – runs `tsuru login` if not authenticated or session expired; | ||||
| * `tsuru_not_command` – fixes wrong tsuru commands like `tsuru shell`; | ||||
| * `tsuru_not_command` – fixes wrong `tsuru` commands like `tsuru shell`; | ||||
| * `tmux` – fixes `tmux` commands; | ||||
| * `whois` – fixes `whois` command. | ||||
|  | ||||
| @@ -199,7 +199,7 @@ Enabled by default only on specific platforms: | ||||
| * `brew_install` – fixes formula name for `brew install`; | ||||
| * `brew_unknown_command` – fixes wrong brew commands, for example `brew docto/brew doctor`; | ||||
| * `brew_upgrade` – appends `--all` to `brew upgrade` as per Homebrew's new behaviour; | ||||
| * `pacman` – installs app with `pacman` or `yaourt` if it is not installed. | ||||
| * `pacman` – installs app with `pacman` if it is not installed (uses `yaourt` if available). | ||||
|  | ||||
| Bundled, but not enabled by default: | ||||
|  | ||||
|   | ||||
| @@ -16,6 +16,8 @@ def test_match(command): | ||||
|  | ||||
| @pytest.mark.parametrize('command, return_value', [ | ||||
|     (Command(script='vim', stderr='vim: command not found'), | ||||
|      [('vim', 'main'), ('vim-tiny', 'main')]), | ||||
|     (Command(script='sudo vim', stderr='vim: command not found'), | ||||
|      [('vim', 'main'), ('vim-tiny', 'main')])]) | ||||
| @patch('thefuck.rules.apt_get.CommandNotFound', create=True) | ||||
| @patch.multiple(apt_get, create=True, apt_get='apt_get') | ||||
| @@ -38,7 +40,9 @@ def test_not_match(command): | ||||
|                     reason='Skip if python-commandnotfound is not available') | ||||
| @pytest.mark.parametrize('command, new_command', [ | ||||
|     (Command('vim'), 'sudo apt-get install vim && vim'), | ||||
|     (Command('convert'), 'sudo apt-get install imagemagick && convert')]) | ||||
|     (Command('convert'), 'sudo apt-get install imagemagick && convert'), | ||||
|     (Command('sudo vim'), 'sudo apt-get install vim && sudo vim'), | ||||
|     (Command('sudo convert'), 'sudo apt-get install imagemagick && sudo convert')]) | ||||
| def test_get_new_command(command, new_command): | ||||
|     assert get_new_command(command, None) == new_command | ||||
|  | ||||
| @@ -47,6 +51,11 @@ def test_get_new_command(command, new_command): | ||||
|     (Command('vim'), 'sudo apt-get install vim && vim', | ||||
|      [('vim', 'main'), ('vim-tiny', 'main')]), | ||||
|     (Command('convert'), 'sudo apt-get install imagemagick && convert', | ||||
|      [('imagemagick', 'main'), | ||||
|       ('graphicsmagick-imagemagick-compat', 'universe')]), | ||||
|     (Command('sudo vim'), 'sudo apt-get install vim && sudo vim', | ||||
|      [('vim', 'main'), ('vim-tiny', 'main')]), | ||||
|     (Command('sudo convert'), 'sudo apt-get install imagemagick && sudo convert', | ||||
|      [('imagemagick', 'main'), | ||||
|       ('graphicsmagick-imagemagick-compat', 'universe')])]) | ||||
| @patch('thefuck.rules.apt_get.CommandNotFound', create=True) | ||||
| @@ -55,5 +64,3 @@ def test_get_new_command_mocked(cmdnf_mock, command, new_command, return_value): | ||||
|     get_packages = Mock(return_value=return_value) | ||||
|     cmdnf_mock.CommandNotFound.return_value = Mock(getPackages=get_packages) | ||||
|     assert get_new_command(command, None) == new_command | ||||
|     assert cmdnf_mock.CommandNotFound.called | ||||
|     assert get_packages.called | ||||
|   | ||||
| @@ -7,6 +7,7 @@ from tests.utils import Command | ||||
|  | ||||
| pacman_cmd = getattr(pacman, 'pacman', 'pacman') | ||||
|  | ||||
| PKGFILE_OUTPUT_SUDO = 'core/sudo 1.8.13-13/usr/bin/sudo' | ||||
| PKGFILE_OUTPUT_CONVERT = 'extra/imagemagick 6.9.1.0-1\t/usr/bin/convert' | ||||
|  | ||||
| PKGFILE_OUTPUT_VIM = '''extra/gvim 7.4.712-1        \t/usr/bin/vim | ||||
| @@ -28,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.rules.pacman.subprocess') | ||||
| @patch('thefuck.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 | ||||
| @@ -72,8 +73,9 @@ def test_get_new_command(command, new_command, mocker): | ||||
|     (Command('vim'), vim_possibilities, PKGFILE_OUTPUT_VIM), | ||||
|     (Command('sudo vim'), sudo_vim_possibilities, PKGFILE_OUTPUT_VIM), | ||||
|     (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.rules.pacman.subprocess') | ||||
| @patch('thefuck.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 | ||||
|   | ||||
							
								
								
									
										48
									
								
								tests/rules/test_pacman_not_found.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								tests/rules/test_pacman_not_found.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| import pytest | ||||
| from mock import patch | ||||
| from thefuck.rules import pacman_not_found | ||||
| from thefuck.rules.pacman_not_found import match, get_new_command | ||||
| from tests.utils import Command | ||||
|  | ||||
| PKGFILE_OUTPUT_LLC = '''extra/llvm 3.6.0-5      /usr/bin/llc | ||||
| extra/llvm35 3.5.2-13/usr/bin/llc''' | ||||
|  | ||||
|  | ||||
| @pytest.mark.skipif(not getattr(pacman_not_found, 'enabled_by_default', True), | ||||
|                     reason='Skip if pacman is not available') | ||||
| @pytest.mark.parametrize('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')]) | ||||
| def test_match(command): | ||||
|     assert match(command, None) | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize('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.archlinux.subprocess') | ||||
| def test_match_mocked(subp_mock, command): | ||||
|     subp_mock.check_output.return_value = PKGFILE_OUTPUT_LLC | ||||
|     assert match(command, None) | ||||
|  | ||||
|  | ||||
| @pytest.mark.skipif(not getattr(pacman_not_found, 'enabled_by_default', True), | ||||
|                     reason='Skip if pacman is not available') | ||||
| @pytest.mark.parametrize('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'])]) | ||||
| def test_get_new_command(command, fixed): | ||||
|     assert get_new_command(command, None) == fixed | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize('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.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 | ||||
							
								
								
									
										41
									
								
								thefuck/archlinux.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								thefuck/archlinux.py
									
									
									
									
									
										Normal 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 | ||||
| @@ -1,27 +1,30 @@ | ||||
| from thefuck import shells | ||||
| from thefuck.utils import sudo_support | ||||
| from thefuck.utils import memoize | ||||
|  | ||||
| try: | ||||
|     import CommandNotFound | ||||
| except ImportError: | ||||
|     enabled_by_default = False | ||||
|  | ||||
| @sudo_support | ||||
| def match(command, settings): | ||||
|     if 'not found' in command.stderr: | ||||
|         try: | ||||
|             c = CommandNotFound.CommandNotFound() | ||||
|             pkgs = c.getPackages(command.script.split(" ")[0]) | ||||
|             name, _ = pkgs[0] | ||||
|             return True | ||||
|         except IndexError: | ||||
|             # IndexError is thrown when no matching package is found | ||||
|             return False | ||||
|  | ||||
| @sudo_support | ||||
| @memoize | ||||
| def get_package(command): | ||||
|     try: | ||||
|         c = CommandNotFound.CommandNotFound() | ||||
|         cmd = command.split(' ') | ||||
|         pkgs = c.getPackages(cmd[0] if cmd[0] != 'sudo' else cmd[1]) | ||||
|         name, _ = pkgs[0] | ||||
|         return name | ||||
|     except IndexError: | ||||
|         # IndexError is thrown when no matching package is found | ||||
|         return None | ||||
|  | ||||
|  | ||||
| def match(command, settings): | ||||
|     return 'not found' in command.stderr and get_package(command.script) | ||||
|  | ||||
|  | ||||
| def get_new_command(command, settings): | ||||
|     c = CommandNotFound.CommandNotFound() | ||||
|     pkgs = c.getPackages(command.script.split(" ")[0]) | ||||
|     name, _ = pkgs[0] | ||||
|     name = get_package(command.script) | ||||
|     formatme = shells.and_('sudo apt-get install {}', '{}') | ||||
|     return formatme.format(name, command.script) | ||||
|   | ||||
| @@ -1,46 +1,16 @@ | ||||
| import subprocess | ||||
| from thefuck.utils import DEVNULL, which | ||||
| from thefuck.archlinux import archlinux_env, get_pkgfile | ||||
| from thefuck import shells | ||||
| from thefuck.utils import memoize | ||||
|  | ||||
|  | ||||
| @memoize | ||||
| def __get_pkgfile(command): | ||||
|     try: | ||||
|         command = command.script | ||||
|  | ||||
|         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 subprocess.CalledProcessError: | ||||
|         return None | ||||
|  | ||||
|  | ||||
| def match(command, settings): | ||||
|     return 'not found' in command.stderr and __get_pkgfile(command) | ||||
|     return 'not found' in command.stderr and get_pkgfile(command.script) | ||||
|  | ||||
|  | ||||
| def get_new_command(command, settings): | ||||
|     packages = __get_pkgfile(command) | ||||
|     packages = get_pkgfile(command.script) | ||||
|  | ||||
|     formatme = shells.and_('{} -S {}', '{}') | ||||
|     return [formatme.format(pacman, package, command.script) | ||||
|             for package in packages] | ||||
|  | ||||
|  | ||||
| if not which('pkgfile'): | ||||
|     enabled_by_default = False | ||||
| elif which('yaourt'): | ||||
|     pacman = 'yaourt' | ||||
| elif which('pacman'): | ||||
|     pacman = 'sudo pacman' | ||||
| else: | ||||
|     enabled_by_default = False | ||||
| enabled_by_default, pacman = archlinux_env() | ||||
|   | ||||
							
								
								
									
										24
									
								
								thefuck/rules/pacman_not_found.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								thefuck/rules/pacman_not_found.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| """ Fixes wrong package names with pacman or yaourt. | ||||
|  | ||||
| For example the `llc` program is in package `llvm` so this: | ||||
|     yaourt -S llc | ||||
| should be: | ||||
|     yaourt -S llvm | ||||
| """ | ||||
|  | ||||
| from thefuck.utils import replace_command | ||||
| from thefuck.archlinux import archlinux_env, get_pkgfile | ||||
|  | ||||
|  | ||||
| def match(command, settings): | ||||
|     return (command.script.startswith(('pacman', 'sudo pacman', 'yaourt')) | ||||
|             and 'error: target not found:' in command.stderr) | ||||
|  | ||||
|  | ||||
| def get_new_command(command, settings): | ||||
|     pgr = command.script.split()[-1] | ||||
|  | ||||
|     return replace_command(command, pgr, get_pkgfile(pgr)) | ||||
|  | ||||
|  | ||||
| enabled_by_default, _ = archlinux_env() | ||||
| @@ -1,3 +1,4 @@ | ||||
| from .types import Command | ||||
| from difflib import get_close_matches | ||||
| from functools import wraps | ||||
| from pathlib import Path | ||||
| @@ -6,7 +7,6 @@ import os | ||||
| import pickle | ||||
| import re | ||||
| import six | ||||
| from .types import Command | ||||
|  | ||||
|  | ||||
| DEVNULL = open(os.devnull, 'w') | ||||
|   | ||||
		Reference in New Issue
	
	Block a user