diff --git a/tests/rules/test_composer_not_command.py b/tests/rules/test_composer_not_command.py index 518b97a5..4d0a9458 100644 --- a/tests/rules/test_composer_not_command.py +++ b/tests/rules/test_composer_not_command.py @@ -5,45 +5,87 @@ from thefuck.types import Command # tested with composer version 1.9.0 # command: composer udpate -case_single_command_with_one_suggestion = ("composer udpate", r'\n' - ' ''\n' - r' [Symfony\Component\Console\Exception\CommandNotFoundException] ''\n' - ' Command "udpate" is not defined. ''\n' - ' ''\n' - ' Did you mean this? ''\n' - ' update ''\n' - ' ''\n' - '\n' - ) +case_single_command_with_one_suggestion = ( + "composer udpate", + r"\n" + " " + "\n" + r" [Symfony\Component\Console\Exception\CommandNotFoundException] " + "\n" + ' Command "udpate" is not defined. ' + "\n" + " " + "\n" + " Did you mean this? " + "\n" + " update " + "\n" + " " + "\n" + "\n", +) case_single_command_with_one_suggestion_expected = "composer update" # command: composer selupdate -case_single_command_with_many_suggestions = ("composer selupdate", r'\n' - ' ''\n' - r' [Symfony\Component\Console\Exception\CommandNotFoundException] ''\n' - ' Command "selupdate" is not defined. ''\n' - ' ''\n' - ' Did you mean one of these? ''\n' - ' update ''\n' - ' self-update ''\n' - ' selfupdate ''\n' - ' ''\n' - '\n' - ) -case_single_command_with_many_suggesitons_expected = ["composer update", "composer self-update", "composer selfupdate"] +case_single_command_with_many_suggestions = ( + "composer selupdate", + r"\n" + " " + "\n" + r" [Symfony\Component\Console\Exception\CommandNotFoundException] " + "\n" + ' Command "selupdate" is not defined. ' + "\n" + " " + "\n" + " Did you mean one of these? " + "\n" + " update " + "\n" + " self-update " + "\n" + " selfupdate " + "\n" + " " + "\n" + "\n", +) +case_single_command_with_many_suggesitons_expected = [ + "composer update", + "composer self-update", + "composer selfupdate", +] -@pytest.mark.parametrize('command', [Command(*v) for v in [ - case_single_command_with_one_suggestion, - case_single_command_with_many_suggestions -]]) +@pytest.mark.parametrize( + "command", + [ + Command(*v) + for v in [ + case_single_command_with_one_suggestion, + case_single_command_with_many_suggestions, + ] + ], +) def test_match(command): assert match(command) -@pytest.mark.parametrize('command, new_command', [(Command(*t[0]), t[1]) for t in [ - (case_single_command_with_one_suggestion, case_single_command_with_one_suggestion_expected), - (case_single_command_with_many_suggestions, case_single_command_with_many_suggesitons_expected) -]]) +@pytest.mark.parametrize( + "command, new_command", + [ + (Command(*t[0]), t[1]) + for t in [ + ( + case_single_command_with_one_suggestion, + case_single_command_with_one_suggestion_expected, + ), + ( + case_single_command_with_many_suggestions, + case_single_command_with_many_suggesitons_expected, + ), + ] + ], +) def test_get_new_command(command, new_command): assert get_new_command(command) == new_command diff --git a/tests/rules/test_composer_not_package.py b/tests/rules/test_composer_not_package.py index 51a32c44..bf82bfc6 100644 --- a/tests/rules/test_composer_not_package.py +++ b/tests/rules/test_composer_not_package.py @@ -7,112 +7,196 @@ from thefuck.types import Command # command: # composer require laravel-nova-csv-import # the one that started it all -case_original = ("composer require laravel-nova-csv-import", '\n' - ' ''\n' - ' [InvalidArgumentException] ''\n' - ' Could not find package laravel-nova-csv-import. ''\n' - ' ''\n' - ' Did you mean this? ''\n' - ' simonhamp/laravel-nova-csv-import ''\n' - ' ''\n' - 'require [--dev] [--prefer-source] [--prefer-dist] [--no-progress] [--no-suggest] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--update-with-all-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--] []...''\n' - '\n') +case_original = ( + "composer require laravel-nova-csv-import", + "\n" + " " + "\n" + " [InvalidArgumentException] " + "\n" + " Could not find package laravel-nova-csv-import. " + "\n" + " " + "\n" + " Did you mean this? " + "\n" + " simonhamp/laravel-nova-csv-import " + "\n" + " " + "\n" + "require [--dev] [--prefer-source] [--prefer-dist] [--no-progress] [--no-suggest] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--update-with-all-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--] []..." + "\n" + "\n", +) case_original_expected = "composer require simonhamp/laravel-nova-csv-import" # command: # composer require datrack/elasticroute -case_single_suggestion = ("composer require datrack/elasticroute", '\n' - ' ''\n' - ' [InvalidArgumentException] ''\n' - ' Could not find package datrack/elasticroute. ''\n' - ' ''\n' - ' Did you mean this? ''\n' - ' detrack/elasticroute ''\n' - ' ''\n' - 'require [--dev] [--prefer-source] [--prefer-dist] [--no-progress] [--no-suggest] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--update-with-all-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--] []...''\n' - '\n') +case_single_suggestion = ( + "composer require datrack/elasticroute", + "\n" + " " + "\n" + " [InvalidArgumentException] " + "\n" + " Could not find package datrack/elasticroute. " + "\n" + " " + "\n" + " Did you mean this? " + "\n" + " detrack/elasticroute " + "\n" + " " + "\n" + "require [--dev] [--prefer-source] [--prefer-dist] [--no-progress] [--no-suggest] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--update-with-all-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--] []..." + "\n" + "\n", +) case_single_suggestion_expected = "composer require detrack/elasticroute" # command: # composer require potato -case_many_suggestions = ("composer require potato", '\n' - ' ''\n' - ' [InvalidArgumentException] ''\n' - ' Could not find package potato. ''\n' - ' ''\n' - ' Did you mean one of these? ''\n' - ' drteam/potato ''\n' - ' florence/potato ''\n' - ' kola/potato-orm ''\n' - ' jsyqw/potato-bot ''\n' - ' vundi/potato-orm ''\n' - ' ''\n\n' - 'require [--dev] [--prefer-source] [--prefer-dist] [--no-progress] [--no-suggest] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--update-with-all-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--] []...''\n' - '\n') -case_many_suggestions_expected = ["composer require drteam/potato", - "composer require florence/potato", - "composer require kola/potato-orm", - "composer require jsyqw/potato-bot", - "composer require vundi/potato-orm"] +case_many_suggestions = ( + "composer require potato", + "\n" + " " + "\n" + " [InvalidArgumentException] " + "\n" + " Could not find package potato. " + "\n" + " " + "\n" + " Did you mean one of these? " + "\n" + " drteam/potato " + "\n" + " florence/potato " + "\n" + " kola/potato-orm " + "\n" + " jsyqw/potato-bot " + "\n" + " vundi/potato-orm " + "\n" + " " + "\n\n" + "require [--dev] [--prefer-source] [--prefer-dist] [--no-progress] [--no-suggest] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--update-with-all-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--] []..." + "\n" + "\n", +) +case_many_suggestions_expected = [ + "composer require drteam/potato", + "composer require florence/potato", + "composer require kola/potato-orm", + "composer require jsyqw/potato-bot", + "composer require vundi/potato-orm", +] # command: # composer require datrack/elasticroute:* -case_single_package_with_version_constraint = ("composer require datrack/elasticroute:*", '\n' - ' ''\n' - ' [InvalidArgumentException] ''\n' - ' Could not find package datrack/elasticroute. ''\n' - ' ''\n' - ' Did you mean this? ''\n' - ' detrack/elasticroute ''\n' - ' ''\n\n' - 'require [--dev] [--prefer-source] [--prefer-dist] [--no-progress] [--no-suggest] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--update-with-all-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--] []...''\n' - '\n') -case_single_package_with_version_constraint_expected = "composer require detrack/elasticroute:*" +case_single_package_with_version_constraint = ( + "composer require datrack/elasticroute:*", + "\n" + " " + "\n" + " [InvalidArgumentException] " + "\n" + " Could not find package datrack/elasticroute. " + "\n" + " " + "\n" + " Did you mean this? " + "\n" + " detrack/elasticroute " + "\n" + " " + "\n\n" + "require [--dev] [--prefer-source] [--prefer-dist] [--no-progress] [--no-suggest] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--update-with-all-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--] []..." + "\n" + "\n", +) +case_single_package_with_version_constraint_expected = ( + "composer require detrack/elasticroute:*" +) # command: # composer require potato:* -case_single_package_with_version_constraint_many_suggestions = ("composer require potato:1.2.3", '\n' - ' ''\n' - ' [InvalidArgumentException] ''\n' - ' Could not find package potato. ''\n' - ' ''\n' - ' Did you mean one of these? ''\n' - ' drteam/potato ''\n' - ' florence/potato ''\n' - ' kola/potato-orm ''\n' - ' jsyqw/potato-bot ''\n' - ' vundi/potato-orm ''\n' - ' ''\n\n' - 'require [--dev] [--prefer-source] [--prefer-dist] [--no-progress] [--no-suggest] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--update-with-all-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--] []...''\n' - - '\n' - ) -case_single_package_with_version_constraint_many_suggestions_expected = ["composer require drteam/potato:1.2.3", - "composer require florence/potato:1.2.3", - "composer require kola/potato-orm:1.2.3", - "composer require jsyqw/potato-bot:1.2.3", - "composer require vundi/potato-orm:1.2.3"] +case_single_package_with_version_constraint_many_suggestions = ( + "composer require potato:1.2.3", + "\n" + " " + "\n" + " [InvalidArgumentException] " + "\n" + " Could not find package potato. " + "\n" + " " + "\n" + " Did you mean one of these? " + "\n" + " drteam/potato " + "\n" + " florence/potato " + "\n" + " kola/potato-orm " + "\n" + " jsyqw/potato-bot " + "\n" + " vundi/potato-orm " + "\n" + " " + "\n\n" + "require [--dev] [--prefer-source] [--prefer-dist] [--no-progress] [--no-suggest] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--update-with-all-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--] []..." + "\n" + "\n", +) +case_single_package_with_version_constraint_many_suggestions_expected = [ + "composer require drteam/potato:1.2.3", + "composer require florence/potato:1.2.3", + "composer require kola/potato-orm:1.2.3", + "composer require jsyqw/potato-bot:1.2.3", + "composer require vundi/potato-orm:1.2.3", +] -@pytest.mark.parametrize('command', [Command(*v) for v in [ - case_original, - case_single_suggestion, - case_many_suggestions, - case_single_package_with_version_constraint, - case_single_package_with_version_constraint_many_suggestions -]]) +@pytest.mark.parametrize( + "command", + [ + Command(*v) + for v in [ + case_original, + case_single_suggestion, + case_many_suggestions, + case_single_package_with_version_constraint, + case_single_package_with_version_constraint_many_suggestions, + ] + ], +) def test_match(command): assert match(command) -@pytest.mark.parametrize('command, new_command', [(Command(*t[0]), t[1]) for t in [ - (case_original, case_original_expected), - (case_single_suggestion, case_single_suggestion_expected), - (case_many_suggestions, case_many_suggestions_expected), - (case_single_package_with_version_constraint, case_single_package_with_version_constraint_expected), - (case_single_package_with_version_constraint_many_suggestions, - case_single_package_with_version_constraint_many_suggestions_expected), -]]) +@pytest.mark.parametrize( + "command, new_command", + [ + (Command(*t[0]), t[1]) + for t in [ + (case_original, case_original_expected), + (case_single_suggestion, case_single_suggestion_expected), + (case_many_suggestions, case_many_suggestions_expected), + ( + case_single_package_with_version_constraint, + case_single_package_with_version_constraint_expected, + ), + ( + case_single_package_with_version_constraint_many_suggestions, + case_single_package_with_version_constraint_many_suggestions_expected, + ), + ] + ], +) def test_get_new_command(command, new_command): assert get_new_command(command) == new_command diff --git a/thefuck/rules/composer_not_command.py b/thefuck/rules/composer_not_command.py index 6addd15f..bfdaeaef 100644 --- a/thefuck/rules/composer_not_command.py +++ b/thefuck/rules/composer_not_command.py @@ -1,37 +1,35 @@ import re -from thefuck.utils import replace_argument, for_app +from thefuck.utils import for_app -@for_app('composer') +@for_app("composer") def match(command): # determine error type # matching "did you mean this" is not enough as composer also gives spelling suggestions for mistakes other than mispelled commands - is_undefined_command_error = r"[Symfony\Component\Console\Exception\CommandNotFoundException]" in command.output - suggestions_present = (('did you mean this?' in command.output.lower() - or 'did you mean one of these?' in command.output.lower())) + is_undefined_command_error = "CommandNotFoundException" in command.output + suggestions_present = "Did you mean" in command.output return is_undefined_command_error and suggestions_present def get_new_command(command): # since the command class already tells us the original argument, we need not resort to regex broken_cmd = command.script_parts[1] - one_suggestion_only = 'did you mean this?' in command.output.lower() + one_suggestion_only = "Did you mean this?" in command.output if one_suggestion_only: - new_cmd = re.findall(r'Did you mean this\?[^\n]*\n\s*([^\n]*)', command.output) - return replace_argument(command.script, broken_cmd, new_cmd[0].strip()) - else: - # there are multiple suggestions - # trim output text to make it more digestable by regex - trim_start_index = command.output.find("Did you mean one of these?") - short_output = command.output[trim_start_index:] - stripped_lines = [line.strip() for line in short_output.split("\n")] - # each of the suggested commands can be found from index 1 to the first occurence of blank string - try: - end_index = stripped_lines.index('') - except ValueError: - end_index = None - suggested_commands = stripped_lines[1:end_index] - return [ - replace_argument(command.script, broken_cmd, cmd.strip()) - for cmd in suggested_commands - ] + new_cmd = ( + re.search(r"Did you mean this\?[^\n]*\n\s*([^\n]*)", command.output) + .group(1) + .strip() + ) + return command.script.replace(broken_cmd, new_cmd) + # else there are multiple suggestions + # trim output text to make it more digestable by regex + trim_start_index = command.output.find("Did you mean") + short_output = command.output[trim_start_index:] + stripped_lines = [line.strip() for line in short_output.split("\n")] + # each of the suggested commands can be found from index 1 to the first occurrence of a blank string + end_index = stripped_lines.index("") + suggested_commands = stripped_lines[1:end_index] + return [ + command.script.replace(broken_cmd, cmd.strip()) for cmd in suggested_commands + ] diff --git a/thefuck/rules/composer_not_package.py b/thefuck/rules/composer_not_package.py index 75f2bb68..89d757e2 100644 --- a/thefuck/rules/composer_not_package.py +++ b/thefuck/rules/composer_not_package.py @@ -1,42 +1,53 @@ import re -from thefuck.utils import replace_argument, for_app +from thefuck.utils import for_app -@for_app('composer') +@for_app("composer") def match(command): # determine error type # matching "did you mean this" is not enough as composer also gives spelling suggestions for mistakes other than mispelled commands is_invalid_argument_exception = r"[InvalidArgumentException]" in command.output - is_unable_to_find_package = re.search(r"Could not find package (.*)\.", command.output) is not None - suggestions_present = (('did you mean this?' in command.output.lower() - or 'did you mean one of these?' in command.output.lower())) - return is_invalid_argument_exception and is_unable_to_find_package and suggestions_present + is_unable_to_find_package = ( + re.search(r"Could not find package (.*)\.", command.output) is not None + ) + suggestions_present = "Did you mean" in command.output + return ( + is_invalid_argument_exception + and is_unable_to_find_package + and suggestions_present + ) def get_new_command(command): # because composer lets you install many packages at once, must look at output to determine the erroneous package name - wrong_package_name = re.search(r"Could not find package (.*)\.", command.output).group(1) - offending_script_param = wrong_package_name if (wrong_package_name in command.script_parts) else re.findall( - r"{}:[^ ]+".format(wrong_package_name), command.script)[0] - version_constraint = offending_script_param[len(wrong_package_name):] - one_suggestion_only = 'did you mean this?' in command.output.lower() + wrong_package_name = re.search( + r"Could not find package (.*)\.", command.output + ).group(1) + offending_script_param = ( + wrong_package_name + if (wrong_package_name in command.script_parts) + else re.findall(r"{}:[^ ]+".format(wrong_package_name), command.script)[0] + ) + version_constraint = offending_script_param[len(wrong_package_name) :] + one_suggestion_only = "Did you mean this?" in command.output if one_suggestion_only: - # wrong regex?? - new_cmd = re.findall(r'Did you mean this\?[^\n]*\n\s*([^\n]*)', command.output) - return replace_argument(command.script, offending_script_param, new_cmd[0].strip() + version_constraint) - else: - # there are multiple suggestions - # trim output text to make it more digestable by regex - trim_start_index = command.output.find("Did you mean one of these?") - short_output = command.output[trim_start_index:] - stripped_lines = [line.strip() for line in short_output.split("\n")] - # each of the suggested commands can be found from index 1 to the first occurence of blank string - try: - end_index = stripped_lines.index('') - except ValueError: - end_index = None - suggested_commands = stripped_lines[1:end_index] - return [ - replace_argument(command.script, offending_script_param, cmd + version_constraint) - for cmd in suggested_commands - ] + new_pkg = ( + re.search(r"Did you mean this\?[^\n]*\n\s*([^\n]*)", command.output) + .group(1) + .strip() + ) + return command.script.replace( + offending_script_param, new_pkg + version_constraint + ) + # else there are multiple suggestions + # trim output text to make it more digestable by regex + trim_start_index = command.output.find("Did you mean") + short_output = command.output[trim_start_index:] + stripped_lines = [line.strip() for line in short_output.split("\n")] + # each of the suggested packages can be found from index 1 to the first occurrence of a blank string + end_index = stripped_lines.index("") + suggested_packages = stripped_lines[1:end_index] + return [ + command.script.replace(offending_script_param, pkg + version_constraint) + for pkg in suggested_packages + ]