mirror of
				https://github.com/nvbn/thefuck.git
				synced 2025-10-31 15:12:20 +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`; | * `systemctl` – correctly orders parameters of confusing `systemctl`; | ||||||
| * `test.py` – runs `py.test` instead of `test.py`; | * `test.py` – runs `py.test` instead of `test.py`; | ||||||
| * `tsuru_login` – runs `tsuru login` if not authenticated or session expired; | * `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; | * `tmux` – fixes `tmux` commands; | ||||||
| * `whois` – fixes `whois` command. | * `whois` – fixes `whois` command. | ||||||
|  |  | ||||||
| @@ -199,7 +199,7 @@ Enabled by default only on specific platforms: | |||||||
| * `brew_install` – fixes formula name for `brew install`; | * `brew_install` – fixes formula name for `brew install`; | ||||||
| * `brew_unknown_command` – fixes wrong brew commands, for example `brew docto/brew doctor`; | * `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; | * `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: | Bundled, but not enabled by default: | ||||||
|  |  | ||||||
|   | |||||||
| @@ -16,6 +16,8 @@ def test_match(command): | |||||||
|  |  | ||||||
| @pytest.mark.parametrize('command, return_value', [ | @pytest.mark.parametrize('command, return_value', [ | ||||||
|     (Command(script='vim', stderr='vim: command not found'), |     (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')])]) |      [('vim', 'main'), ('vim-tiny', 'main')])]) | ||||||
| @patch('thefuck.rules.apt_get.CommandNotFound', create=True) | @patch('thefuck.rules.apt_get.CommandNotFound', create=True) | ||||||
| @patch.multiple(apt_get, create=True, apt_get='apt_get') | @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') |                     reason='Skip if python-commandnotfound is not available') | ||||||
| @pytest.mark.parametrize('command, new_command', [ | @pytest.mark.parametrize('command, new_command', [ | ||||||
|     (Command('vim'), 'sudo apt-get install vim && vim'), |     (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): | def test_get_new_command(command, new_command): | ||||||
|     assert get_new_command(command, None) == 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', |     (Command('vim'), 'sudo apt-get install vim && vim', | ||||||
|      [('vim', 'main'), ('vim-tiny', 'main')]), |      [('vim', 'main'), ('vim-tiny', 'main')]), | ||||||
|     (Command('convert'), 'sudo apt-get install imagemagick && convert', |     (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'), |      [('imagemagick', 'main'), | ||||||
|       ('graphicsmagick-imagemagick-compat', 'universe')])]) |       ('graphicsmagick-imagemagick-compat', 'universe')])]) | ||||||
| @patch('thefuck.rules.apt_get.CommandNotFound', create=True) | @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) |     get_packages = Mock(return_value=return_value) | ||||||
|     cmdnf_mock.CommandNotFound.return_value = Mock(getPackages=get_packages) |     cmdnf_mock.CommandNotFound.return_value = Mock(getPackages=get_packages) | ||||||
|     assert get_new_command(command, None) == new_command |     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') | 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_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 | 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', [ | @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.rules.pacman.subprocess') | @patch('thefuck.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 | ||||||
| @@ -72,8 +73,9 @@ def test_get_new_command(command, new_command, mocker): | |||||||
|     (Command('vim'), vim_possibilities, PKGFILE_OUTPUT_VIM), |     (Command('vim'), vim_possibilities, PKGFILE_OUTPUT_VIM), | ||||||
|     (Command('sudo vim'), sudo_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('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)]) |     (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) | @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 | ||||||
|   | |||||||
							
								
								
									
										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 import shells | ||||||
| from thefuck.utils import sudo_support | from thefuck.utils import memoize | ||||||
|  |  | ||||||
| try: | try: | ||||||
|     import CommandNotFound |     import CommandNotFound | ||||||
| except ImportError: | except ImportError: | ||||||
|     enabled_by_default = False |     enabled_by_default = False | ||||||
|  |  | ||||||
| @sudo_support |  | ||||||
| def match(command, settings): | @memoize | ||||||
|     if 'not found' in command.stderr: | def get_package(command): | ||||||
|     try: |     try: | ||||||
|         c = CommandNotFound.CommandNotFound() |         c = CommandNotFound.CommandNotFound() | ||||||
|             pkgs = c.getPackages(command.script.split(" ")[0]) |         cmd = command.split(' ') | ||||||
|  |         pkgs = c.getPackages(cmd[0] if cmd[0] != 'sudo' else cmd[1]) | ||||||
|         name, _ = pkgs[0] |         name, _ = pkgs[0] | ||||||
|             return True |         return name | ||||||
|     except IndexError: |     except IndexError: | ||||||
|         # IndexError is thrown when no matching package is found |         # IndexError is thrown when no matching package is found | ||||||
|             return False |         return None | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def match(command, settings): | ||||||
|  |     return 'not found' in command.stderr and get_package(command.script) | ||||||
|  |  | ||||||
|  |  | ||||||
| @sudo_support |  | ||||||
| def get_new_command(command, settings): | def get_new_command(command, settings): | ||||||
|     c = CommandNotFound.CommandNotFound() |     name = get_package(command.script) | ||||||
|     pkgs = c.getPackages(command.script.split(" ")[0]) |  | ||||||
|     name, _ = pkgs[0] |  | ||||||
|     formatme = shells.and_('sudo apt-get install {}', '{}') |     formatme = shells.and_('sudo apt-get install {}', '{}') | ||||||
|     return formatme.format(name, command.script) |     return formatme.format(name, command.script) | ||||||
|   | |||||||
| @@ -1,46 +1,16 @@ | |||||||
| import subprocess | from thefuck.archlinux import archlinux_env, get_pkgfile | ||||||
| from thefuck.utils import DEVNULL, which |  | ||||||
| from thefuck import shells | 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): | 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): | def get_new_command(command, settings): | ||||||
|     packages = __get_pkgfile(command) |     packages = get_pkgfile(command.script) | ||||||
|  |  | ||||||
|     formatme = shells.and_('{} -S {}', '{}') |     formatme = shells.and_('{} -S {}', '{}') | ||||||
|     return [formatme.format(pacman, package, command.script) |     return [formatme.format(pacman, package, command.script) | ||||||
|             for package in packages] |             for package in packages] | ||||||
|  |  | ||||||
|  | enabled_by_default, pacman = archlinux_env() | ||||||
| if not which('pkgfile'): |  | ||||||
|     enabled_by_default = False |  | ||||||
| elif which('yaourt'): |  | ||||||
|     pacman = 'yaourt' |  | ||||||
| elif which('pacman'): |  | ||||||
|     pacman = 'sudo pacman' |  | ||||||
| else: |  | ||||||
|     enabled_by_default = False |  | ||||||
|   | |||||||
							
								
								
									
										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 difflib import get_close_matches | ||||||
| from functools import wraps | from functools import wraps | ||||||
| from pathlib import Path | from pathlib import Path | ||||||
| @@ -6,7 +7,6 @@ import os | |||||||
| import pickle | import pickle | ||||||
| import re | import re | ||||||
| import six | import six | ||||||
| from .types import Command |  | ||||||
|  |  | ||||||
|  |  | ||||||
| DEVNULL = open(os.devnull, 'w') | DEVNULL = open(os.devnull, 'w') | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user