1
0
mirror of https://github.com/nvbn/thefuck.git synced 2025-03-20 01:28:56 +00:00

amend PR following code review

This commit is contained in:
chesnutcase 2019-11-23 02:05:00 +08:00
parent 84bbd76630
commit 838c422776
No known key found for this signature in database
GPG Key ID: 9F5CAB4AD73A031D
4 changed files with 306 additions and 171 deletions

View File

@ -5,45 +5,87 @@ from thefuck.types import Command
# tested with composer version 1.9.0 # tested with composer version 1.9.0
# command: composer udpate # command: composer udpate
case_single_command_with_one_suggestion = ("composer udpate", r'\n' case_single_command_with_one_suggestion = (
' ''\n' "composer udpate",
r' [Symfony\Component\Console\Exception\CommandNotFoundException] ''\n' r"\n"
' Command "udpate" is not defined. ''\n' " "
' ''\n' "\n"
' Did you mean this? ''\n' r" [Symfony\Component\Console\Exception\CommandNotFoundException] "
' update ''\n' "\n"
' ''\n' ' Command "udpate" is not defined. '
'\n' "\n"
) " "
"\n"
" Did you mean this? "
"\n"
" update "
"\n"
" "
"\n"
"\n",
)
case_single_command_with_one_suggestion_expected = "composer update" case_single_command_with_one_suggestion_expected = "composer update"
# command: composer selupdate # command: composer selupdate
case_single_command_with_many_suggestions = ("composer selupdate", r'\n' case_single_command_with_many_suggestions = (
' ''\n' "composer selupdate",
r' [Symfony\Component\Console\Exception\CommandNotFoundException] ''\n' r"\n"
' Command "selupdate" is not defined. ''\n' " "
' ''\n' "\n"
' Did you mean one of these? ''\n' r" [Symfony\Component\Console\Exception\CommandNotFoundException] "
' update ''\n' "\n"
' self-update ''\n' ' Command "selupdate" is not defined. '
' selfupdate ''\n' "\n"
' ''\n' " "
'\n' "\n"
) " Did you mean one of these? "
case_single_command_with_many_suggesitons_expected = ["composer update", "composer self-update", "composer selfupdate"] "\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 [ @pytest.mark.parametrize(
case_single_command_with_one_suggestion, "command",
case_single_command_with_many_suggestions [
]]) Command(*v)
for v in [
case_single_command_with_one_suggestion,
case_single_command_with_many_suggestions,
]
],
)
def test_match(command): def test_match(command):
assert match(command) assert match(command)
@pytest.mark.parametrize('command, new_command', [(Command(*t[0]), t[1]) for t in [ @pytest.mark.parametrize(
(case_single_command_with_one_suggestion, case_single_command_with_one_suggestion_expected), "command, new_command",
(case_single_command_with_many_suggestions, case_single_command_with_many_suggesitons_expected) [
]]) (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): def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command assert get_new_command(command) == new_command

View File

@ -7,112 +7,196 @@ from thefuck.types import Command
# command: # command:
# composer require laravel-nova-csv-import # composer require laravel-nova-csv-import
# the one that started it all # the one that started it all
case_original = ("composer require laravel-nova-csv-import", '\n' case_original = (
' ''\n' "composer require laravel-nova-csv-import",
' [InvalidArgumentException] ''\n' "\n"
' Could not find package laravel-nova-csv-import. ''\n' " "
' ''\n' "\n"
' Did you mean this? ''\n' " [InvalidArgumentException] "
' simonhamp/laravel-nova-csv-import ''\n' "\n"
' ''\n' " Could not find package laravel-nova-csv-import. "
'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] [--] [<packages>]...''\n' "\n"
'\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] [--] [<packages>]..."
"\n"
"\n",
)
case_original_expected = "composer require simonhamp/laravel-nova-csv-import" case_original_expected = "composer require simonhamp/laravel-nova-csv-import"
# command: # command:
# composer require datrack/elasticroute # composer require datrack/elasticroute
case_single_suggestion = ("composer require datrack/elasticroute", '\n' case_single_suggestion = (
' ''\n' "composer require datrack/elasticroute",
' [InvalidArgumentException] ''\n' "\n"
' Could not find package datrack/elasticroute. ''\n' " "
' ''\n' "\n"
' Did you mean this? ''\n' " [InvalidArgumentException] "
' detrack/elasticroute ''\n' "\n"
' ''\n' " Could not find package datrack/elasticroute. "
'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] [--] [<packages>]...''\n' "\n"
'\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] [--] [<packages>]..."
"\n"
"\n",
)
case_single_suggestion_expected = "composer require detrack/elasticroute" case_single_suggestion_expected = "composer require detrack/elasticroute"
# command: # command:
# composer require potato # composer require potato
case_many_suggestions = ("composer require potato", '\n' case_many_suggestions = (
' ''\n' "composer require potato",
' [InvalidArgumentException] ''\n' "\n"
' Could not find package potato. ''\n' " "
' ''\n' "\n"
' Did you mean one of these? ''\n' " [InvalidArgumentException] "
' drteam/potato ''\n' "\n"
' florence/potato ''\n' " Could not find package potato. "
' kola/potato-orm ''\n' "\n"
' jsyqw/potato-bot ''\n' " "
' vundi/potato-orm ''\n' "\n"
' ''\n\n' " Did you mean one of these? "
'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] [--] [<packages>]...''\n' "\n"
'\n') " drteam/potato "
case_many_suggestions_expected = ["composer require drteam/potato", "\n"
"composer require florence/potato", " florence/potato "
"composer require kola/potato-orm", "\n"
"composer require jsyqw/potato-bot", " kola/potato-orm "
"composer require vundi/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] [--] [<packages>]..."
"\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: # command:
# composer require datrack/elasticroute:* # composer require datrack/elasticroute:*
case_single_package_with_version_constraint = ("composer require datrack/elasticroute:*", '\n' case_single_package_with_version_constraint = (
' ''\n' "composer require datrack/elasticroute:*",
' [InvalidArgumentException] ''\n' "\n"
' Could not find package datrack/elasticroute. ''\n' " "
' ''\n' "\n"
' Did you mean this? ''\n' " [InvalidArgumentException] "
' detrack/elasticroute ''\n' "\n"
' ''\n\n' " Could not find package datrack/elasticroute. "
'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] [--] [<packages>]...''\n' "\n"
'\n') " "
case_single_package_with_version_constraint_expected = "composer require detrack/elasticroute:*" "\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] [--] [<packages>]..."
"\n"
"\n",
)
case_single_package_with_version_constraint_expected = (
"composer require detrack/elasticroute:*"
)
# command: # command:
# composer require potato:* # composer require potato:*
case_single_package_with_version_constraint_many_suggestions = ("composer require potato:1.2.3", '\n' case_single_package_with_version_constraint_many_suggestions = (
' ''\n' "composer require potato:1.2.3",
' [InvalidArgumentException] ''\n' "\n"
' Could not find package potato. ''\n' " "
' ''\n' "\n"
' Did you mean one of these? ''\n' " [InvalidArgumentException] "
' drteam/potato ''\n' "\n"
' florence/potato ''\n' " Could not find package potato. "
' kola/potato-orm ''\n' "\n"
' jsyqw/potato-bot ''\n' " "
' vundi/potato-orm ''\n' "\n"
' ''\n\n' " Did you mean one of these? "
'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] [--] [<packages>]...''\n' "\n"
" drteam/potato "
'\n' "\n"
) " florence/potato "
case_single_package_with_version_constraint_many_suggestions_expected = ["composer require drteam/potato:1.2.3", "\n"
"composer require florence/potato:1.2.3", " kola/potato-orm "
"composer require kola/potato-orm:1.2.3", "\n"
"composer require jsyqw/potato-bot:1.2.3", " jsyqw/potato-bot "
"composer require vundi/potato-orm:1.2.3"] "\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] [--] [<packages>]..."
"\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 [ @pytest.mark.parametrize(
case_original, "command",
case_single_suggestion, [
case_many_suggestions, Command(*v)
case_single_package_with_version_constraint, for v in [
case_single_package_with_version_constraint_many_suggestions 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): def test_match(command):
assert match(command) assert match(command)
@pytest.mark.parametrize('command, new_command', [(Command(*t[0]), t[1]) for t in [ @pytest.mark.parametrize(
(case_original, case_original_expected), "command, new_command",
(case_single_suggestion, case_single_suggestion_expected), [
(case_many_suggestions, case_many_suggestions_expected), (Command(*t[0]), t[1])
(case_single_package_with_version_constraint, case_single_package_with_version_constraint_expected), for t in [
(case_single_package_with_version_constraint_many_suggestions, (case_original, case_original_expected),
case_single_package_with_version_constraint_many_suggestions_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): def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command assert get_new_command(command) == new_command

View File

@ -1,37 +1,35 @@
import re 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): def match(command):
# determine error type # determine error type
# matching "did you mean this" is not enough as composer also gives spelling suggestions for mistakes other than mispelled commands # 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 is_undefined_command_error = "CommandNotFoundException" in command.output
suggestions_present = (('did you mean this?' in command.output.lower() suggestions_present = "Did you mean" in command.output
or 'did you mean one of these?' in command.output.lower()))
return is_undefined_command_error and suggestions_present return is_undefined_command_error and suggestions_present
def get_new_command(command): def get_new_command(command):
# since the command class already tells us the original argument, we need not resort to regex # since the command class already tells us the original argument, we need not resort to regex
broken_cmd = command.script_parts[1] 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: if one_suggestion_only:
new_cmd = re.findall(r'Did you mean this\?[^\n]*\n\s*([^\n]*)', command.output) new_cmd = (
return replace_argument(command.script, broken_cmd, new_cmd[0].strip()) re.search(r"Did you mean this\?[^\n]*\n\s*([^\n]*)", command.output)
else: .group(1)
# there are multiple suggestions .strip()
# trim output text to make it more digestable by regex )
trim_start_index = command.output.find("Did you mean one of these?") return command.script.replace(broken_cmd, new_cmd)
short_output = command.output[trim_start_index:] # else there are multiple suggestions
stripped_lines = [line.strip() for line in short_output.split("\n")] # trim output text to make it more digestable by regex
# each of the suggested commands can be found from index 1 to the first occurence of blank string trim_start_index = command.output.find("Did you mean")
try: short_output = command.output[trim_start_index:]
end_index = stripped_lines.index('') stripped_lines = [line.strip() for line in short_output.split("\n")]
except ValueError: # each of the suggested commands can be found from index 1 to the first occurrence of a blank string
end_index = None end_index = stripped_lines.index("")
suggested_commands = stripped_lines[1:end_index] suggested_commands = stripped_lines[1:end_index]
return [ return [
replace_argument(command.script, broken_cmd, cmd.strip()) command.script.replace(broken_cmd, cmd.strip()) for cmd in suggested_commands
for cmd in suggested_commands ]
]

View File

@ -1,42 +1,53 @@
import re 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): def match(command):
# determine error type # determine error type
# matching "did you mean this" is not enough as composer also gives spelling suggestions for mistakes other than mispelled commands # 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_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 is_unable_to_find_package = (
suggestions_present = (('did you mean this?' in command.output.lower() re.search(r"Could not find package (.*)\.", command.output) is not None
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 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): def get_new_command(command):
# because composer lets you install many packages at once, must look at output to determine the erroneous package name # 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) wrong_package_name = re.search(
offending_script_param = wrong_package_name if (wrong_package_name in command.script_parts) else re.findall( r"Could not find package (.*)\.", command.output
r"{}:[^ ]+".format(wrong_package_name), command.script)[0] ).group(1)
version_constraint = offending_script_param[len(wrong_package_name):] offending_script_param = (
one_suggestion_only = 'did you mean this?' in command.output.lower() 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: if one_suggestion_only:
# wrong regex?? new_pkg = (
new_cmd = re.findall(r'Did you mean this\?[^\n]*\n\s*([^\n]*)', command.output) re.search(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) .group(1)
else: .strip()
# there are multiple suggestions )
# trim output text to make it more digestable by regex return command.script.replace(
trim_start_index = command.output.find("Did you mean one of these?") offending_script_param, new_pkg + version_constraint
short_output = command.output[trim_start_index:] )
stripped_lines = [line.strip() for line in short_output.split("\n")] # else there are multiple suggestions
# each of the suggested commands can be found from index 1 to the first occurence of blank string # trim output text to make it more digestable by regex
try: trim_start_index = command.output.find("Did you mean")
end_index = stripped_lines.index('') short_output = command.output[trim_start_index:]
except ValueError: stripped_lines = [line.strip() for line in short_output.split("\n")]
end_index = None # each of the suggested packages can be found from index 1 to the first occurrence of a blank string
suggested_commands = stripped_lines[1:end_index] end_index = stripped_lines.index("")
return [ suggested_packages = stripped_lines[1:end_index]
replace_argument(command.script, offending_script_param, cmd + version_constraint) return [
for cmd in suggested_commands command.script.replace(offending_script_param, pkg + version_constraint)
] for pkg in suggested_packages
]