From 1d5e40a7c9314ef647d0c04b62cae2a76e688368 Mon Sep 17 00:00:00 2001 From: Josh Date: Sat, 29 Feb 2020 20:22:30 -0600 Subject: [PATCH 1/2] #962: Add the new apt_unable_to_locate rule Fix #962 --- README.md | 1 + tests/rules/test_apt_unable_to_locate.py | 153 +++++++++++++++++++++++ thefuck/rules/apt_unable_to_locate.py | 55 ++++++++ 3 files changed, 209 insertions(+) create mode 100644 tests/rules/test_apt_unable_to_locate.py create mode 100644 thefuck/rules/apt_unable_to_locate.py diff --git a/README.md b/README.md index 4ff50cd..3aeca8d 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,7 @@ The following rules are enabled by default on specific platforms only: * `apt_get_search` – changes trying to search using `apt-get` with searching using `apt-cache`; * `apt_invalid_operation` – fixes invalid `apt` and `apt-get` calls, like `apt-get isntall vim`; * `apt_list_upgradable` – helps you run `apt list --upgradable` after `apt update`; +* `apt_unable_to_locate rule` – search for packages similar to the one intended with `apt-get` or `apt`; * `apt_upgrade` – helps you run `apt upgrade` after `apt list --upgradable`; * `brew_cask_dependency` – installs cask dependencies; * `brew_install` – fixes formula name for `brew install`; diff --git a/tests/rules/test_apt_unable_to_locate.py b/tests/rules/test_apt_unable_to_locate.py new file mode 100644 index 0000000..7ed99d2 --- /dev/null +++ b/tests/rules/test_apt_unable_to_locate.py @@ -0,0 +1,153 @@ +from io import BytesIO + +import pytest +from thefuck.rules.apt_unable_to_locate import match, get_new_command, _get_search_results +from thefuck.types import Command + +invalid_operation = 'E: Unable to locate package {}'.format +apt_rabbitmq_search_results = b''' kamailio-rabbitmq-modules/bionic 5.1.2-1ubuntu2 amd64 + RabbitMQ and AMQP integration modules for the Kamailio SIP server + +libanyevent-rabbitmq-perl/bionic 1.19+dfsg-1 all + asynchronous and multi channel Perl AMQP client + +libmojo-rabbitmq-client-perl/bionic 0.1.0-1 all + Mojo::IOLoop based RabbitMQ client + +libmono-messaging-rabbitmq4.0-cil/bionic 4.6.2.7+dfsg-1ubuntu1 all + Mono Messaging RabbitMQ library (for CLI 4.0) + +libmono-rabbitmq4.0-cil/bionic 4.6.2.7+dfsg-1ubuntu1 all + Mono RabbitMQ.Client library (for CLI 4.0) + +librabbitmq-client-java/bionic 5.0.0-1 all + RabbitMQ Java client + +librabbitmq-dbg/bionic-updates,bionic-security 0.8.0-1ubuntu0.18.04.2 amd64 + AMQP client library written in C - Debug Files + +librabbitmq-dev/bionic-updates,bionic-security 0.8.0-1ubuntu0.18.04.2 amd64 + AMQP client library written in C - Dev Files + +librabbitmq4/bionic-updates,bionic-security 0.8.0-1ubuntu0.18.04.2 amd64 + AMQP client library written in C + +nagios-plugins-rabbitmq/bionic-updates 1:1.2.0-2.2ubuntu0.18.04.1 all + Set of Nagios checks useful for monitoring a RabbitMQ server + +opensips-rabbitmq-module/bionic 2.2.2-3build4 amd64 + Interface module to interact with a RabbitMQ server + +puppet-module-puppetlabs-rabbitmq/bionic 5.3.1-2 all + Puppet module for rabbitmq, manage everything from vhosts to exchanges + +rabbitmq-server/bionic 3.6.10-1 all + AMQP server written in Erlang + +''' +apt_get_rabbitmq_search_results = b''' +kamailio-rabbitmq-modules - RabbitMQ and AMQP integration modules for the Kamailio SIP server +libanyevent-rabbitmq-perl - asynchronous and multi channel Perl AMQP client +libmojo-rabbitmq-client-perl - Mojo::IOLoop based RabbitMQ client +libmono-messaging-rabbitmq4.0-cil - Mono Messaging RabbitMQ library (for CLI 4.0) +libmono-rabbitmq4.0-cil - Mono RabbitMQ.Client library (for CLI 4.0) +librabbitmq-client-java - RabbitMQ Java client +librabbitmq-dbg - AMQP client library written in C - Debug Files +librabbitmq-dev - AMQP client library written in C - Dev Files +librabbitmq4 - AMQP client library written in C +nagios-plugins-rabbitmq - Set of Nagios checks useful for monitoring a RabbitMQ server +opensips-rabbitmq-module - Interface module to interact with a RabbitMQ server +puppet-module-puppetlabs-rabbitmq - Puppet module for rabbitmq, manage everything from vhosts to exchanges +rabbitmq-server - AMQP server written in Erlang +''' +rabbitmq_search_search_results = [ + 'kamailio-rabbitmq-modules', + 'libanyevent-rabbitmq-perl', + 'libmojo-rabbitmq-client-perl', + 'libmono-messaging-rabbitmq4.0-cil', + 'libmono-rabbitmq4.0-cil', + 'librabbitmq-client-java', + 'librabbitmq-dbg', + 'librabbitmq-dev', + 'librabbitmq4', + 'nagios-plugins-rabbitmq', + 'opensips-rabbitmq-module', + 'puppet-module-puppetlabs-rabbitmq', + 'rabbitmq-server' +] + + +@pytest.mark.parametrize( + 'command', + [ + ( + Command('apt install rabbitmq', invalid_operation('rabbitmq')) + ), + ( + Command('apt-get install rabbitmq', invalid_operation('rabbitmq')) + ) + ] +) +def test_match(command): + assert match(command) + + +@pytest.mark.parametrize( + 'command', + [ + ( + Command('yarn install reactjs', 'a_bad_cmd: command not found') + ), + ( + Command('npm install reactjs', 'a_bad_cmd: command not found') + ), + ( + Command('apt upgrade', 'a_bad_cmd: command not found') + ) + ] +) +def test_not_match(command): + + assert not match(command) + + +@pytest.fixture +def set_search(mocker): + mock = mocker.patch('subprocess.Popen') + + def _set_text(text): + mock.return_value.stdout = BytesIO(text) + + return _set_text + + +@pytest.mark.parametrize( + 'app, command, search_text, search_results', + [ + ('apt', 'rabbitmq', apt_rabbitmq_search_results, rabbitmq_search_search_results), + ('apt-get', 'rabbitmq', apt_get_rabbitmq_search_results, rabbitmq_search_search_results), + ] +) +def test_get_search_results(set_search, app, command, search_text, search_results): + set_search(search_text) + assert _get_search_results(app, command) == search_results + + +@pytest.mark.parametrize( + 'command, expected_command, search_text', + [ + ( + Command('sudo apt install rabbitmq', invalid_operation('rabbitmq')), + [ + 'sudo apt install librabbitmq4', + 'sudo apt install rabbitmq-server', + 'sudo apt install librabbitmq-dev' + ], + apt_rabbitmq_search_results, + ) + ] +) +def test_get_new_command(set_search, command, expected_command, search_text): + set_search(search_text) + actual_command = get_new_command(command) + assert actual_command == expected_command diff --git a/thefuck/rules/apt_unable_to_locate.py b/thefuck/rules/apt_unable_to_locate.py new file mode 100644 index 0000000..fd68eec --- /dev/null +++ b/thefuck/rules/apt_unable_to_locate.py @@ -0,0 +1,55 @@ +import subprocess + +from thefuck.specific.sudo import sudo_support +from thefuck.utils import for_app, replace_command + + +@sudo_support +@for_app('apt', 'apt-get') +def match(command): + return "E: Unable to locate package" in command.output + + +def _parse_apt_search_results(search_text_lines): + search_results = [] + + for line in search_text_lines: + line = line.decode().strip() + if line.find('/') > 0: + search_results.append(line.split('/')[0]) + + return search_results + + +def _parse_apt_cache_search_results(search_text_lines): + search_results = [] + + for line in search_text_lines: + line = line.decode().strip() + if line.find(' - ') > 0: # spaces are important + search_results.append(line.split(' - ')[0]) + + return search_results + + +def _get_search_results(app, command): + _parser = _parse_apt_search_results + + if app == 'apt-get': + app = 'apt-cache' + _parser = _parse_apt_cache_search_results + + proc = subprocess.Popen([app, 'search', command], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + lines = proc.stdout.readlines() + + return _parser(lines) + + +@sudo_support +def get_new_command(command): + invalid_operation = command.script_parts[-1] + search_results = _get_search_results(command.script_parts[0], invalid_operation) + + return replace_command(command, invalid_operation, search_results) From 26b7f6299214881467e941aff2bab7195f7b9546 Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 1 Mar 2020 12:40:10 -0600 Subject: [PATCH 2/2] Updated formatting using `black` --- tests/rules/test_apt_unable_to_locate.py | 106 ++++++++++++----------- thefuck/rules/apt_unable_to_locate.py | 20 ++--- 2 files changed, 64 insertions(+), 62 deletions(-) diff --git a/tests/rules/test_apt_unable_to_locate.py b/tests/rules/test_apt_unable_to_locate.py index 7ed99d2..5795f64 100644 --- a/tests/rules/test_apt_unable_to_locate.py +++ b/tests/rules/test_apt_unable_to_locate.py @@ -1,11 +1,15 @@ from io import BytesIO import pytest -from thefuck.rules.apt_unable_to_locate import match, get_new_command, _get_search_results +from thefuck.rules.apt_unable_to_locate import ( + match, + get_new_command, + _get_search_results, +) from thefuck.types import Command -invalid_operation = 'E: Unable to locate package {}'.format -apt_rabbitmq_search_results = b''' kamailio-rabbitmq-modules/bionic 5.1.2-1ubuntu2 amd64 +invalid_operation = "E: Unable to locate package {}".format +apt_rabbitmq_search_results = b""" kamailio-rabbitmq-modules/bionic 5.1.2-1ubuntu2 amd64 RabbitMQ and AMQP integration modules for the Kamailio SIP server libanyevent-rabbitmq-perl/bionic 1.19+dfsg-1 all @@ -44,8 +48,8 @@ puppet-module-puppetlabs-rabbitmq/bionic 5.3.1-2 all rabbitmq-server/bionic 3.6.10-1 all AMQP server written in Erlang -''' -apt_get_rabbitmq_search_results = b''' +""" +apt_get_rabbitmq_search_results = b""" kamailio-rabbitmq-modules - RabbitMQ and AMQP integration modules for the Kamailio SIP server libanyevent-rabbitmq-perl - asynchronous and multi channel Perl AMQP client libmojo-rabbitmq-client-perl - Mojo::IOLoop based RabbitMQ client @@ -59,61 +63,50 @@ nagios-plugins-rabbitmq - Set of Nagios checks useful for monitoring a RabbitMQ opensips-rabbitmq-module - Interface module to interact with a RabbitMQ server puppet-module-puppetlabs-rabbitmq - Puppet module for rabbitmq, manage everything from vhosts to exchanges rabbitmq-server - AMQP server written in Erlang -''' +""" rabbitmq_search_search_results = [ - 'kamailio-rabbitmq-modules', - 'libanyevent-rabbitmq-perl', - 'libmojo-rabbitmq-client-perl', - 'libmono-messaging-rabbitmq4.0-cil', - 'libmono-rabbitmq4.0-cil', - 'librabbitmq-client-java', - 'librabbitmq-dbg', - 'librabbitmq-dev', - 'librabbitmq4', - 'nagios-plugins-rabbitmq', - 'opensips-rabbitmq-module', - 'puppet-module-puppetlabs-rabbitmq', - 'rabbitmq-server' + "kamailio-rabbitmq-modules", + "libanyevent-rabbitmq-perl", + "libmojo-rabbitmq-client-perl", + "libmono-messaging-rabbitmq4.0-cil", + "libmono-rabbitmq4.0-cil", + "librabbitmq-client-java", + "librabbitmq-dbg", + "librabbitmq-dev", + "librabbitmq4", + "nagios-plugins-rabbitmq", + "opensips-rabbitmq-module", + "puppet-module-puppetlabs-rabbitmq", + "rabbitmq-server", ] @pytest.mark.parametrize( - 'command', + "command", [ - ( - Command('apt install rabbitmq', invalid_operation('rabbitmq')) - ), - ( - Command('apt-get install rabbitmq', invalid_operation('rabbitmq')) - ) - ] + (Command("apt install rabbitmq", invalid_operation("rabbitmq"))), + (Command("apt-get install rabbitmq", invalid_operation("rabbitmq"))), + ], ) def test_match(command): assert match(command) @pytest.mark.parametrize( - 'command', + "command", [ - ( - Command('yarn install reactjs', 'a_bad_cmd: command not found') - ), - ( - Command('npm install reactjs', 'a_bad_cmd: command not found') - ), - ( - Command('apt upgrade', 'a_bad_cmd: command not found') - ) - ] + (Command("yarn install reactjs", "a_bad_cmd: command not found")), + (Command("npm install reactjs", "a_bad_cmd: command not found")), + (Command("apt upgrade", "a_bad_cmd: command not found")), + ], ) def test_not_match(command): - assert not match(command) @pytest.fixture def set_search(mocker): - mock = mocker.patch('subprocess.Popen') + mock = mocker.patch("subprocess.Popen") def _set_text(text): mock.return_value.stdout = BytesIO(text) @@ -122,11 +115,21 @@ def set_search(mocker): @pytest.mark.parametrize( - 'app, command, search_text, search_results', + "app, command, search_text, search_results", [ - ('apt', 'rabbitmq', apt_rabbitmq_search_results, rabbitmq_search_search_results), - ('apt-get', 'rabbitmq', apt_get_rabbitmq_search_results, rabbitmq_search_search_results), - ] + ( + "apt", + "rabbitmq", + apt_rabbitmq_search_results, + rabbitmq_search_search_results, + ), + ( + "apt-get", + "rabbitmq", + apt_get_rabbitmq_search_results, + rabbitmq_search_search_results, + ), + ], ) def test_get_search_results(set_search, app, command, search_text, search_results): set_search(search_text) @@ -134,20 +137,19 @@ def test_get_search_results(set_search, app, command, search_text, search_result @pytest.mark.parametrize( - 'command, expected_command, search_text', + "command, expected_command, search_text", [ ( - Command('sudo apt install rabbitmq', invalid_operation('rabbitmq')), + Command("sudo apt install rabbitmq", invalid_operation("rabbitmq")), [ - 'sudo apt install librabbitmq4', - 'sudo apt install rabbitmq-server', - 'sudo apt install librabbitmq-dev' + "sudo apt install librabbitmq4", + "sudo apt install rabbitmq-server", + "sudo apt install librabbitmq-dev", ], apt_rabbitmq_search_results, ) - ] + ], ) def test_get_new_command(set_search, command, expected_command, search_text): set_search(search_text) - actual_command = get_new_command(command) - assert actual_command == expected_command + assert get_new_command(command) == expected_command diff --git a/thefuck/rules/apt_unable_to_locate.py b/thefuck/rules/apt_unable_to_locate.py index fd68eec..30231ea 100644 --- a/thefuck/rules/apt_unable_to_locate.py +++ b/thefuck/rules/apt_unable_to_locate.py @@ -5,7 +5,7 @@ from thefuck.utils import for_app, replace_command @sudo_support -@for_app('apt', 'apt-get') +@for_app("apt", "apt-get") def match(command): return "E: Unable to locate package" in command.output @@ -15,8 +15,8 @@ def _parse_apt_search_results(search_text_lines): for line in search_text_lines: line = line.decode().strip() - if line.find('/') > 0: - search_results.append(line.split('/')[0]) + if line.find("/") > 0: + search_results.append(line.split("/")[0]) return search_results @@ -26,8 +26,8 @@ def _parse_apt_cache_search_results(search_text_lines): for line in search_text_lines: line = line.decode().strip() - if line.find(' - ') > 0: # spaces are important - search_results.append(line.split(' - ')[0]) + if line.find(" - ") > 0: # spaces are important + search_results.append(line.split(" - ")[0]) return search_results @@ -35,13 +35,13 @@ def _parse_apt_cache_search_results(search_text_lines): def _get_search_results(app, command): _parser = _parse_apt_search_results - if app == 'apt-get': - app = 'apt-cache' + if app == "apt-get": + app = "apt-cache" _parser = _parse_apt_cache_search_results - proc = subprocess.Popen([app, 'search', command], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + proc = subprocess.Popen( + [app, "search", command], stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) lines = proc.stdout.readlines() return _parser(lines)