thefuck-leeguoo 3.41__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- thefuck/__init__.py +0 -0
- thefuck/ai.py +765 -0
- thefuck/argument_parser.py +96 -0
- thefuck/conf.py +141 -0
- thefuck/const.py +111 -0
- thefuck/corrector.py +92 -0
- thefuck/entrypoints/__init__.py +0 -0
- thefuck/entrypoints/alias.py +28 -0
- thefuck/entrypoints/fix_command.py +105 -0
- thefuck/entrypoints/main.py +50 -0
- thefuck/entrypoints/not_configured.py +201 -0
- thefuck/entrypoints/setup.py +227 -0
- thefuck/entrypoints/shell_logger.py +79 -0
- thefuck/exceptions.py +10 -0
- thefuck/logs.py +255 -0
- thefuck/output_readers/__init__.py +20 -0
- thefuck/output_readers/read_log.py +108 -0
- thefuck/output_readers/rerun.py +72 -0
- thefuck/output_readers/shell_logger.py +60 -0
- thefuck/rules/__init__.py +0 -0
- thefuck/rules/adb_unknown_command.py +54 -0
- thefuck/rules/ag_literal.py +10 -0
- thefuck/rules/apt_get.py +50 -0
- thefuck/rules/apt_get_search.py +14 -0
- thefuck/rules/apt_invalid_operation.py +63 -0
- thefuck/rules/apt_list_upgradable.py +16 -0
- thefuck/rules/apt_upgrade.py +16 -0
- thefuck/rules/aws_cli.py +17 -0
- thefuck/rules/az_cli.py +17 -0
- thefuck/rules/brew_cask_dependency.py +33 -0
- thefuck/rules/brew_install.py +24 -0
- thefuck/rules/brew_link.py +15 -0
- thefuck/rules/brew_reinstall.py +19 -0
- thefuck/rules/brew_uninstall.py +14 -0
- thefuck/rules/brew_unknown_command.py +82 -0
- thefuck/rules/brew_update_formula.py +12 -0
- thefuck/rules/cargo.py +6 -0
- thefuck/rules/cargo_no_command.py +15 -0
- thefuck/rules/cat_dir.py +14 -0
- thefuck/rules/cd_correction.py +61 -0
- thefuck/rules/cd_cs.py +21 -0
- thefuck/rules/cd_mkdir.py +21 -0
- thefuck/rules/cd_parent.py +16 -0
- thefuck/rules/chmod_x.py +15 -0
- thefuck/rules/choco_install.py +25 -0
- thefuck/rules/composer_not_command.py +22 -0
- thefuck/rules/conda_mistype.py +17 -0
- thefuck/rules/cp_create_destination.py +15 -0
- thefuck/rules/cp_omitting_directory.py +15 -0
- thefuck/rules/cpp11.py +12 -0
- thefuck/rules/dirty_untar.py +53 -0
- thefuck/rules/dirty_unzip.py +60 -0
- thefuck/rules/django_south_ghost.py +8 -0
- thefuck/rules/django_south_merge.py +8 -0
- thefuck/rules/dnf_no_such_command.py +37 -0
- thefuck/rules/docker_image_being_used_by_container.py +20 -0
- thefuck/rules/docker_login.py +13 -0
- thefuck/rules/docker_not_command.py +49 -0
- thefuck/rules/dry.py +15 -0
- thefuck/rules/fab_command_not_found.py +38 -0
- thefuck/rules/fix_alt_space.py +15 -0
- thefuck/rules/fix_file.py +80 -0
- thefuck/rules/gem_unknown_command.py +36 -0
- thefuck/rules/git_add.py +27 -0
- thefuck/rules/git_add_force.py +13 -0
- thefuck/rules/git_bisect_usage.py +16 -0
- thefuck/rules/git_branch_0flag.py +24 -0
- thefuck/rules/git_branch_delete.py +13 -0
- thefuck/rules/git_branch_delete_checked_out.py +19 -0
- thefuck/rules/git_branch_exists.py +25 -0
- thefuck/rules/git_branch_list.py +14 -0
- thefuck/rules/git_checkout.py +49 -0
- thefuck/rules/git_clone_git_clone.py +12 -0
- thefuck/rules/git_clone_missing.py +42 -0
- thefuck/rules/git_commit_add.py +17 -0
- thefuck/rules/git_commit_amend.py +11 -0
- thefuck/rules/git_commit_reset.py +11 -0
- thefuck/rules/git_diff_no_index.py +16 -0
- thefuck/rules/git_diff_staged.py +13 -0
- thefuck/rules/git_fix_stash.py +37 -0
- thefuck/rules/git_flag_after_filename.py +31 -0
- thefuck/rules/git_help_aliased.py +12 -0
- thefuck/rules/git_hook_bypass.py +27 -0
- thefuck/rules/git_lfs_mistype.py +18 -0
- thefuck/rules/git_main_master.py +16 -0
- thefuck/rules/git_merge.py +18 -0
- thefuck/rules/git_merge_unrelated.py +12 -0
- thefuck/rules/git_not_command.py +18 -0
- thefuck/rules/git_pull.py +16 -0
- thefuck/rules/git_pull_clone.py +13 -0
- thefuck/rules/git_pull_uncommitted_changes.py +14 -0
- thefuck/rules/git_push.py +44 -0
- thefuck/rules/git_push_different_branch_names.py +12 -0
- thefuck/rules/git_push_force.py +18 -0
- thefuck/rules/git_push_pull.py +20 -0
- thefuck/rules/git_push_without_commits.py +12 -0
- thefuck/rules/git_rebase_merge_dir.py +17 -0
- thefuck/rules/git_rebase_no_changes.py +13 -0
- thefuck/rules/git_remote_delete.py +13 -0
- thefuck/rules/git_remote_seturl_add.py +12 -0
- thefuck/rules/git_rm_local_modifications.py +19 -0
- thefuck/rules/git_rm_recursive.py +16 -0
- thefuck/rules/git_rm_staged.py +19 -0
- thefuck/rules/git_stash.py +15 -0
- thefuck/rules/git_stash_pop.py +18 -0
- thefuck/rules/git_tag_force.py +13 -0
- thefuck/rules/git_two_dashes.py +14 -0
- thefuck/rules/go_run.py +16 -0
- thefuck/rules/go_unknown_command.py +28 -0
- thefuck/rules/gradle_no_task.py +34 -0
- thefuck/rules/gradle_wrapper.py +13 -0
- thefuck/rules/grep_arguments_order.py +23 -0
- thefuck/rules/grep_recursive.py +10 -0
- thefuck/rules/grunt_task_not_found.py +37 -0
- thefuck/rules/gulp_not_task.py +22 -0
- thefuck/rules/has_exists_script.py +13 -0
- thefuck/rules/heroku_multiple_apps.py +12 -0
- thefuck/rules/heroku_not_command.py +11 -0
- thefuck/rules/history.py +15 -0
- thefuck/rules/hostscli.py +27 -0
- thefuck/rules/ifconfig_device_not_found.py +23 -0
- thefuck/rules/java.py +17 -0
- thefuck/rules/javac.py +18 -0
- thefuck/rules/lein_not_task.py +19 -0
- thefuck/rules/ln_no_hard_link.py +23 -0
- thefuck/rules/ln_s_order.py +26 -0
- thefuck/rules/long_form_help.py +27 -0
- thefuck/rules/ls_all.py +10 -0
- thefuck/rules/ls_lah.py +12 -0
- thefuck/rules/man.py +33 -0
- thefuck/rules/man_no_space.py +10 -0
- thefuck/rules/mercurial.py +27 -0
- thefuck/rules/missing_space_before_subcommand.py +21 -0
- thefuck/rules/mkdir_p.py +13 -0
- thefuck/rules/mvn_no_command.py +11 -0
- thefuck/rules/mvn_unknown_lifecycle_phase.py +30 -0
- thefuck/rules/nixos_cmd_not_found.py +15 -0
- thefuck/rules/no_command.py +41 -0
- thefuck/rules/no_such_file.py +30 -0
- thefuck/rules/npm_missing_script.py +17 -0
- thefuck/rules/npm_run_script.py +17 -0
- thefuck/rules/npm_wrong_command.py +42 -0
- thefuck/rules/omnienv_no_such_command.py +35 -0
- thefuck/rules/open.py +40 -0
- thefuck/rules/pacman.py +17 -0
- thefuck/rules/pacman_invalid_option.py +20 -0
- thefuck/rules/pacman_not_found.py +26 -0
- thefuck/rules/path_from_history.py +53 -0
- thefuck/rules/php_s.py +11 -0
- thefuck/rules/pip_install.py +15 -0
- thefuck/rules/pip_unknown_command.py +19 -0
- thefuck/rules/port_already_in_use.py +40 -0
- thefuck/rules/prove_recursively.py +27 -0
- thefuck/rules/python_command.py +17 -0
- thefuck/rules/python_execute.py +15 -0
- thefuck/rules/python_module_error.py +13 -0
- thefuck/rules/quotation_marks.py +12 -0
- thefuck/rules/rails_migrations_pending.py +14 -0
- thefuck/rules/react_native_command_unrecognized.py +34 -0
- thefuck/rules/remove_shell_prompt_literal.py +23 -0
- thefuck/rules/remove_trailing_cedilla.py +11 -0
- thefuck/rules/rm_dir.py +16 -0
- thefuck/rules/rm_root.py +16 -0
- thefuck/rules/scm_correction.py +32 -0
- thefuck/rules/sed_unterminated_s.py +18 -0
- thefuck/rules/sl_ls.py +14 -0
- thefuck/rules/ssh_known_hosts.py +37 -0
- thefuck/rules/sudo.py +47 -0
- thefuck/rules/sudo_command_from_user_path.py +21 -0
- thefuck/rules/switch_lang.py +117 -0
- thefuck/rules/systemctl.py +22 -0
- thefuck/rules/terraform_init.py +13 -0
- thefuck/rules/terraform_no_command.py +16 -0
- thefuck/rules/test.py.py +10 -0
- thefuck/rules/tmux.py +18 -0
- thefuck/rules/touch.py +14 -0
- thefuck/rules/tsuru_login.py +12 -0
- thefuck/rules/tsuru_not_command.py +15 -0
- thefuck/rules/unknown_command.py +13 -0
- thefuck/rules/unsudo.py +15 -0
- thefuck/rules/vagrant_up.py +21 -0
- thefuck/rules/whois.py +34 -0
- thefuck/rules/workon_doesnt_exists.py +32 -0
- thefuck/rules/wrong_hyphen_before_subcommand.py +20 -0
- thefuck/rules/yarn_alias.py +14 -0
- thefuck/rules/yarn_command_not_found.py +43 -0
- thefuck/rules/yarn_command_replaced.py +13 -0
- thefuck/rules/yarn_help.py +17 -0
- thefuck/rules/yum_invalid_operation.py +39 -0
- thefuck/shells/__init__.py +52 -0
- thefuck/shells/bash.py +94 -0
- thefuck/shells/fish.py +131 -0
- thefuck/shells/generic.py +154 -0
- thefuck/shells/powershell.py +43 -0
- thefuck/shells/tcsh.py +44 -0
- thefuck/shells/zsh.py +98 -0
- thefuck/specific/__init__.py +0 -0
- thefuck/specific/apt.py +3 -0
- thefuck/specific/archlinux.py +48 -0
- thefuck/specific/brew.py +15 -0
- thefuck/specific/dnf.py +3 -0
- thefuck/specific/git.py +32 -0
- thefuck/specific/nix.py +3 -0
- thefuck/specific/npm.py +21 -0
- thefuck/specific/sudo.py +18 -0
- thefuck/specific/yum.py +3 -0
- thefuck/system/__init__.py +7 -0
- thefuck/system/unix.py +57 -0
- thefuck/system/win32.py +43 -0
- thefuck/types.py +261 -0
- thefuck/ui.py +116 -0
- thefuck/utils.py +385 -0
- thefuck_leeguoo-3.41.dist-info/METADATA +681 -0
- thefuck_leeguoo-3.41.dist-info/RECORD +218 -0
- thefuck_leeguoo-3.41.dist-info/WHEEL +6 -0
- thefuck_leeguoo-3.41.dist-info/entry_points.txt +3 -0
- thefuck_leeguoo-3.41.dist-info/licenses/LICENSE.md +22 -0
- thefuck_leeguoo-3.41.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import tarfile
|
|
2
|
+
import os
|
|
3
|
+
from thefuck.utils import for_app
|
|
4
|
+
from thefuck.shells import shell
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
tar_extensions = ('.tar', '.tar.Z', '.tar.bz2', '.tar.gz', '.tar.lz',
|
|
8
|
+
'.tar.lzma', '.tar.xz', '.taz', '.tb2', '.tbz', '.tbz2',
|
|
9
|
+
'.tgz', '.tlz', '.txz', '.tz')
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _is_tar_extract(cmd):
|
|
13
|
+
if '--extract' in cmd:
|
|
14
|
+
return True
|
|
15
|
+
|
|
16
|
+
cmd = cmd.split()
|
|
17
|
+
|
|
18
|
+
return len(cmd) > 1 and 'x' in cmd[1]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _tar_file(cmd):
|
|
22
|
+
for c in cmd:
|
|
23
|
+
for ext in tar_extensions:
|
|
24
|
+
if c.endswith(ext):
|
|
25
|
+
return (c, c[0:len(c) - len(ext)])
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@for_app('tar')
|
|
29
|
+
def match(command):
|
|
30
|
+
return ('-C' not in command.script
|
|
31
|
+
and _is_tar_extract(command.script)
|
|
32
|
+
and _tar_file(command.script_parts) is not None)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_new_command(command):
|
|
36
|
+
dir = shell.quote(_tar_file(command.script_parts)[1])
|
|
37
|
+
return shell.and_('mkdir -p {dir}', '{cmd} -C {dir}') \
|
|
38
|
+
.format(dir=dir, cmd=command.script)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def side_effect(old_cmd, command):
|
|
42
|
+
with tarfile.TarFile(_tar_file(old_cmd.script_parts)[0]) as archive:
|
|
43
|
+
for file in archive.getnames():
|
|
44
|
+
if not os.path.abspath(file).startswith(os.getcwd()):
|
|
45
|
+
# it's unsafe to overwrite files outside of the current directory
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
os.remove(file)
|
|
50
|
+
except OSError:
|
|
51
|
+
# does not try to remove directories as we cannot know if they
|
|
52
|
+
# already existed before
|
|
53
|
+
pass
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import zipfile
|
|
3
|
+
from thefuck.utils import for_app
|
|
4
|
+
from thefuck.shells import shell
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _is_bad_zip(file):
|
|
8
|
+
try:
|
|
9
|
+
with zipfile.ZipFile(file, 'r') as archive:
|
|
10
|
+
return len(archive.namelist()) > 1
|
|
11
|
+
except Exception:
|
|
12
|
+
return False
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _zip_file(command):
|
|
16
|
+
# unzip works that way:
|
|
17
|
+
# unzip [-flags] file[.zip] [file(s) ...] [-x file(s) ...]
|
|
18
|
+
# ^ ^ files to unzip from the archive
|
|
19
|
+
# archive to unzip
|
|
20
|
+
for c in command.script_parts[1:]:
|
|
21
|
+
if not c.startswith('-'):
|
|
22
|
+
if c.endswith('.zip'):
|
|
23
|
+
return c
|
|
24
|
+
else:
|
|
25
|
+
return u'{}.zip'.format(c)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@for_app('unzip')
|
|
29
|
+
def match(command):
|
|
30
|
+
if '-d' in command.script:
|
|
31
|
+
return False
|
|
32
|
+
|
|
33
|
+
zip_file = _zip_file(command)
|
|
34
|
+
if zip_file:
|
|
35
|
+
return _is_bad_zip(zip_file)
|
|
36
|
+
else:
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_new_command(command):
|
|
41
|
+
return u'{} -d {}'.format(
|
|
42
|
+
command.script, shell.quote(_zip_file(command)[:-4]))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def side_effect(old_cmd, command):
|
|
46
|
+
with zipfile.ZipFile(_zip_file(old_cmd), 'r') as archive:
|
|
47
|
+
for file in archive.namelist():
|
|
48
|
+
if not os.path.abspath(file).startswith(os.getcwd()):
|
|
49
|
+
# it's unsafe to overwrite files outside of the current directory
|
|
50
|
+
continue
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
os.remove(file)
|
|
54
|
+
except OSError:
|
|
55
|
+
# does not try to remove directories as we cannot know if they
|
|
56
|
+
# already existed before
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
requires_output = False
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import re
|
|
3
|
+
from thefuck.specific.sudo import sudo_support
|
|
4
|
+
from thefuck.utils import for_app, replace_command
|
|
5
|
+
from thefuck.specific.dnf import dnf_available
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
regex = re.compile(r'No such command: (.*)\.')
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@sudo_support
|
|
12
|
+
@for_app('dnf')
|
|
13
|
+
def match(command):
|
|
14
|
+
return 'no such command' in command.output.lower()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _parse_operations(help_text_lines):
|
|
18
|
+
operation_regex = re.compile(r'^([a-z-]+) +', re.MULTILINE)
|
|
19
|
+
return operation_regex.findall(help_text_lines)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _get_operations():
|
|
23
|
+
proc = subprocess.Popen(["dnf", '--help'],
|
|
24
|
+
stdout=subprocess.PIPE,
|
|
25
|
+
stderr=subprocess.PIPE)
|
|
26
|
+
lines = proc.stdout.read().decode("utf-8")
|
|
27
|
+
|
|
28
|
+
return _parse_operations(lines)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@sudo_support
|
|
32
|
+
def get_new_command(command):
|
|
33
|
+
misspelled_command = regex.findall(command.output)[0]
|
|
34
|
+
return replace_command(command, misspelled_command, _get_operations())
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
enabled_by_default = dnf_available
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from thefuck.utils import for_app
|
|
2
|
+
from thefuck.shells import shell
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@for_app('docker')
|
|
6
|
+
def match(command):
|
|
7
|
+
'''
|
|
8
|
+
Matches a command's output with docker's output
|
|
9
|
+
warning you that you need to remove a container before removing an image.
|
|
10
|
+
'''
|
|
11
|
+
return 'image is being used by running container' in command.output
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_new_command(command):
|
|
15
|
+
'''
|
|
16
|
+
Prepends docker container rm -f {container ID} to
|
|
17
|
+
the previous docker image rm {image ID} command
|
|
18
|
+
'''
|
|
19
|
+
container_id = command.output.strip().split(' ')
|
|
20
|
+
return shell.and_('docker container rm -f {}', '{}').format(container_id[-1], command.script)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from thefuck.utils import for_app
|
|
2
|
+
from thefuck.shells import shell
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@for_app('docker')
|
|
6
|
+
def match(command):
|
|
7
|
+
return ('docker' in command.script
|
|
8
|
+
and "access denied" in command.output
|
|
9
|
+
and "may require 'docker login'" in command.output)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_new_command(command):
|
|
13
|
+
return shell.and_('docker login', command.script)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from itertools import dropwhile, takewhile, islice
|
|
2
|
+
import re
|
|
3
|
+
import subprocess
|
|
4
|
+
from thefuck.utils import replace_command, for_app, which, cache
|
|
5
|
+
from thefuck.specific.sudo import sudo_support
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@sudo_support
|
|
9
|
+
@for_app('docker')
|
|
10
|
+
def match(command):
|
|
11
|
+
return 'is not a docker command' in command.output or 'Usage: docker' in command.output
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _parse_commands(lines, starts_with):
|
|
15
|
+
lines = dropwhile(lambda line: not line.startswith(starts_with), lines)
|
|
16
|
+
lines = islice(lines, 1, None)
|
|
17
|
+
lines = list(takewhile(lambda line: line.strip(), lines))
|
|
18
|
+
return [line.strip().split(' ')[0] for line in lines]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_docker_commands():
|
|
22
|
+
proc = subprocess.Popen('docker', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
23
|
+
|
|
24
|
+
# Old version docker returns its output to stdout, while newer version returns to stderr.
|
|
25
|
+
lines = proc.stdout.readlines() or proc.stderr.readlines()
|
|
26
|
+
lines = [line.decode('utf-8') for line in lines]
|
|
27
|
+
|
|
28
|
+
# Only newer versions of docker have management commands in the help text.
|
|
29
|
+
if 'Management Commands:\n' in lines:
|
|
30
|
+
management_commands = _parse_commands(lines, 'Management Commands:')
|
|
31
|
+
else:
|
|
32
|
+
management_commands = []
|
|
33
|
+
regular_commands = _parse_commands(lines, 'Commands:')
|
|
34
|
+
return management_commands + regular_commands
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
if which('docker'):
|
|
38
|
+
get_docker_commands = cache(which('docker'))(get_docker_commands)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@sudo_support
|
|
42
|
+
def get_new_command(command):
|
|
43
|
+
if 'Usage:' in command.output and len(command.script_parts) > 1:
|
|
44
|
+
management_subcommands = _parse_commands(command.output.split('\n'), 'Commands:')
|
|
45
|
+
return replace_command(command, command.script_parts[2], management_subcommands)
|
|
46
|
+
|
|
47
|
+
wrong_command = re.findall(
|
|
48
|
+
r"docker: '(\w+)' is not a docker command.", command.output)[0]
|
|
49
|
+
return replace_command(command, wrong_command, get_docker_commands())
|
thefuck/rules/dry.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
def match(command):
|
|
2
|
+
split_command = command.script_parts
|
|
3
|
+
|
|
4
|
+
return (split_command
|
|
5
|
+
and len(split_command) >= 2
|
|
6
|
+
and split_command[0] == split_command[1])
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_new_command(command):
|
|
10
|
+
return ' '.join(command.script_parts[1:])
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# it should be rare enough to actually have to type twice the same word, so
|
|
14
|
+
# this rule can have a higher priority to come before things like "cd cd foo"
|
|
15
|
+
priority = 900
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from thefuck.utils import eager, get_closest, for_app
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@for_app('fab')
|
|
5
|
+
def match(command):
|
|
6
|
+
return 'Warning: Command(s) not found:' in command.output
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# We need different behavior then in get_all_matched_commands.
|
|
10
|
+
@eager
|
|
11
|
+
def _get_between(content, start, end=None):
|
|
12
|
+
should_yield = False
|
|
13
|
+
for line in content.split('\n'):
|
|
14
|
+
if start in line:
|
|
15
|
+
should_yield = True
|
|
16
|
+
continue
|
|
17
|
+
|
|
18
|
+
if end and end in line:
|
|
19
|
+
return
|
|
20
|
+
|
|
21
|
+
if should_yield and line:
|
|
22
|
+
yield line.strip().split(' ')[0]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_new_command(command):
|
|
26
|
+
not_found_commands = _get_between(
|
|
27
|
+
command.output, 'Warning: Command(s) not found:',
|
|
28
|
+
'Available commands:')
|
|
29
|
+
possible_commands = _get_between(
|
|
30
|
+
command.output, 'Available commands:')
|
|
31
|
+
|
|
32
|
+
script = command.script
|
|
33
|
+
for not_found in not_found_commands:
|
|
34
|
+
fix = get_closest(not_found, possible_commands)
|
|
35
|
+
script = script.replace(' {}'.format(not_found),
|
|
36
|
+
' {}'.format(fix))
|
|
37
|
+
|
|
38
|
+
return script
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from thefuck.specific.sudo import sudo_support
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@sudo_support
|
|
8
|
+
def match(command):
|
|
9
|
+
return ('command not found' in command.output.lower()
|
|
10
|
+
and u' ' in command.script)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@sudo_support
|
|
14
|
+
def get_new_command(command):
|
|
15
|
+
return re.sub(u' ', ' ', command.script)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import os
|
|
3
|
+
from thefuck.utils import memoize, default_settings
|
|
4
|
+
from thefuck.conf import settings
|
|
5
|
+
from thefuck.shells import shell
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# order is important: only the first match is considered
|
|
9
|
+
patterns = (
|
|
10
|
+
# js, node:
|
|
11
|
+
'^ at {file}:{line}:{col}',
|
|
12
|
+
# cargo:
|
|
13
|
+
'^ {file}:{line}:{col}',
|
|
14
|
+
# python, thefuck:
|
|
15
|
+
'^ File "{file}", line {line}',
|
|
16
|
+
# awk:
|
|
17
|
+
'^awk: {file}:{line}:',
|
|
18
|
+
# git
|
|
19
|
+
'^fatal: bad config file line {line} in {file}',
|
|
20
|
+
# llc:
|
|
21
|
+
'^llc: {file}:{line}:{col}:',
|
|
22
|
+
# lua:
|
|
23
|
+
'^lua: {file}:{line}:',
|
|
24
|
+
# fish:
|
|
25
|
+
'^{file} \\(line {line}\\):',
|
|
26
|
+
# bash, sh, ssh:
|
|
27
|
+
'^{file}: line {line}: ',
|
|
28
|
+
# cargo, clang, gcc, go, pep8, rustc:
|
|
29
|
+
'^{file}:{line}:{col}',
|
|
30
|
+
# ghc, make, ruby, zsh:
|
|
31
|
+
'^{file}:{line}:',
|
|
32
|
+
# perl:
|
|
33
|
+
'at {file} line {line}',
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# for the sake of readability do not use named groups above
|
|
38
|
+
def _make_pattern(pattern):
|
|
39
|
+
pattern = pattern.replace('{file}', '(?P<file>[^:\n]+)') \
|
|
40
|
+
.replace('{line}', '(?P<line>[0-9]+)') \
|
|
41
|
+
.replace('{col}', '(?P<col>[0-9]+)')
|
|
42
|
+
return re.compile(pattern, re.MULTILINE)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
patterns = [_make_pattern(p).search for p in patterns]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@memoize
|
|
49
|
+
def _search(output):
|
|
50
|
+
for pattern in patterns:
|
|
51
|
+
m = pattern(output)
|
|
52
|
+
if m and os.path.isfile(m.group('file')):
|
|
53
|
+
return m
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def match(command):
|
|
57
|
+
if 'EDITOR' not in os.environ:
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
return _search(command.output)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@default_settings({'fixlinecmd': u'{editor} {file} +{line}',
|
|
64
|
+
'fixcolcmd': None})
|
|
65
|
+
def get_new_command(command):
|
|
66
|
+
m = _search(command.output)
|
|
67
|
+
|
|
68
|
+
# Note: there does not seem to be a standard for columns, so they are just
|
|
69
|
+
# ignored by default
|
|
70
|
+
if settings.fixcolcmd and 'col' in m.groupdict():
|
|
71
|
+
editor_call = settings.fixcolcmd.format(editor=os.environ['EDITOR'],
|
|
72
|
+
file=m.group('file'),
|
|
73
|
+
line=m.group('line'),
|
|
74
|
+
col=m.group('col'))
|
|
75
|
+
else:
|
|
76
|
+
editor_call = settings.fixlinecmd.format(editor=os.environ['EDITOR'],
|
|
77
|
+
file=m.group('file'),
|
|
78
|
+
line=m.group('line'))
|
|
79
|
+
|
|
80
|
+
return shell.and_(editor_call, command.script)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import subprocess
|
|
3
|
+
from thefuck.utils import for_app, eager, replace_command, cache, which
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@for_app('gem')
|
|
7
|
+
def match(command):
|
|
8
|
+
return ('ERROR: While executing gem ... (Gem::CommandLineError)'
|
|
9
|
+
in command.output
|
|
10
|
+
and 'Unknown command' in command.output)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _get_unknown_command(command):
|
|
14
|
+
return re.findall(r'Unknown command (.*)$', command.output)[0]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@eager
|
|
18
|
+
def _get_all_commands():
|
|
19
|
+
proc = subprocess.Popen(['gem', 'help', 'commands'],
|
|
20
|
+
stdout=subprocess.PIPE)
|
|
21
|
+
|
|
22
|
+
for line in proc.stdout.readlines():
|
|
23
|
+
line = line.decode()
|
|
24
|
+
|
|
25
|
+
if line.startswith(' '):
|
|
26
|
+
yield line.strip().split(' ')[0]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if which('gem'):
|
|
30
|
+
_get_all_commands = cache(which('gem'))(_get_all_commands)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def get_new_command(command):
|
|
34
|
+
unknown_command = _get_unknown_command(command)
|
|
35
|
+
all_commands = _get_all_commands()
|
|
36
|
+
return replace_command(command, unknown_command, all_commands)
|
thefuck/rules/git_add.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from thefuck.shells import shell
|
|
3
|
+
from thefuck.specific.git import git_support
|
|
4
|
+
from thefuck.system import Path
|
|
5
|
+
from thefuck.utils import memoize
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@memoize
|
|
9
|
+
def _get_missing_file(command):
|
|
10
|
+
pathspec = re.findall(
|
|
11
|
+
r"error: pathspec '([^']*)' "
|
|
12
|
+
r'did not match any file\(s\) known to git.', command.output)[0]
|
|
13
|
+
if Path(pathspec).exists():
|
|
14
|
+
return pathspec
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@git_support
|
|
18
|
+
def match(command):
|
|
19
|
+
return ('did not match any file(s) known to git.' in command.output
|
|
20
|
+
and _get_missing_file(command))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@git_support
|
|
24
|
+
def get_new_command(command):
|
|
25
|
+
missing_file = _get_missing_file(command)
|
|
26
|
+
formatme = shell.and_('git add -- {}', '{}')
|
|
27
|
+
return formatme.format(missing_file, command.script)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from thefuck.utils import replace_argument
|
|
2
|
+
from thefuck.specific.git import git_support
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@git_support
|
|
6
|
+
def match(command):
|
|
7
|
+
return ('add' in command.script_parts
|
|
8
|
+
and 'Use -f if you really want to add them.' in command.output)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@git_support
|
|
12
|
+
def get_new_command(command):
|
|
13
|
+
return replace_argument(command.script, 'add', 'add --force')
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from thefuck.utils import replace_command
|
|
3
|
+
from thefuck.specific.git import git_support
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@git_support
|
|
7
|
+
def match(command):
|
|
8
|
+
return ('bisect' in command.script_parts and
|
|
9
|
+
'usage: git bisect' in command.output)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@git_support
|
|
13
|
+
def get_new_command(command):
|
|
14
|
+
broken = re.findall(r'git bisect ([^ $]*).*', command.script)[0]
|
|
15
|
+
usage = re.findall(r'usage: git bisect \[([^\]]+)\]', command.output)[0]
|
|
16
|
+
return replace_command(command, broken, usage.split('|'))
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from thefuck.shells import shell
|
|
2
|
+
from thefuck.specific.git import git_support
|
|
3
|
+
from thefuck.utils import memoize
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@memoize
|
|
7
|
+
def first_0flag(script_parts):
|
|
8
|
+
return next((p for p in script_parts if len(p) == 2 and p.startswith("0")), None)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@git_support
|
|
12
|
+
def match(command):
|
|
13
|
+
return command.script_parts[1] == "branch" and first_0flag(command.script_parts)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@git_support
|
|
17
|
+
def get_new_command(command):
|
|
18
|
+
branch_name = first_0flag(command.script_parts)
|
|
19
|
+
fixed_flag = branch_name.replace("0", "-")
|
|
20
|
+
fixed_script = command.script.replace(branch_name, fixed_flag)
|
|
21
|
+
if "A branch named '" in command.output and "' already exists." in command.output:
|
|
22
|
+
delete_branch = u"git branch -D {}".format(branch_name)
|
|
23
|
+
return shell.and_(delete_branch, fixed_script)
|
|
24
|
+
return fixed_script
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from thefuck.utils import replace_argument
|
|
2
|
+
from thefuck.specific.git import git_support
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@git_support
|
|
6
|
+
def match(command):
|
|
7
|
+
return ('branch -d' in command.script
|
|
8
|
+
and 'If you are sure you want to delete it' in command.output)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@git_support
|
|
12
|
+
def get_new_command(command):
|
|
13
|
+
return replace_argument(command.script, '-d', '-D')
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from thefuck.shells import shell
|
|
2
|
+
from thefuck.specific.git import git_support
|
|
3
|
+
from thefuck.utils import replace_argument
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@git_support
|
|
7
|
+
def match(command):
|
|
8
|
+
return (
|
|
9
|
+
("branch -d" in command.script or "branch -D" in command.script)
|
|
10
|
+
and "error: Cannot delete branch '" in command.output
|
|
11
|
+
and "' checked out at '" in command.output
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@git_support
|
|
16
|
+
def get_new_command(command):
|
|
17
|
+
return shell.and_("git checkout master", "{}").format(
|
|
18
|
+
replace_argument(command.script, "-d", "-D")
|
|
19
|
+
)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from thefuck.shells import shell
|
|
3
|
+
from thefuck.specific.git import git_support
|
|
4
|
+
from thefuck.utils import eager
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@git_support
|
|
8
|
+
def match(command):
|
|
9
|
+
return ("fatal: A branch named '" in command.output
|
|
10
|
+
and "' already exists." in command.output)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@git_support
|
|
14
|
+
@eager
|
|
15
|
+
def get_new_command(command):
|
|
16
|
+
branch_name = re.findall(
|
|
17
|
+
r"fatal: A branch named '(.+)' already exists.", command.output)[0]
|
|
18
|
+
branch_name = branch_name.replace("'", r"\'")
|
|
19
|
+
new_command_templates = [['git branch -d {0}', 'git branch {0}'],
|
|
20
|
+
['git branch -d {0}', 'git checkout -b {0}'],
|
|
21
|
+
['git branch -D {0}', 'git branch {0}'],
|
|
22
|
+
['git branch -D {0}', 'git checkout -b {0}'],
|
|
23
|
+
['git checkout {0}']]
|
|
24
|
+
for new_command_template in new_command_templates:
|
|
25
|
+
yield shell.and_(*new_command_template).format(branch_name)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from thefuck.shells import shell
|
|
2
|
+
from thefuck.specific.git import git_support
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@git_support
|
|
6
|
+
def match(command):
|
|
7
|
+
# catches "git branch list" in place of "git branch"
|
|
8
|
+
return (command.script_parts
|
|
9
|
+
and command.script_parts[1:] == 'branch list'.split())
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@git_support
|
|
13
|
+
def get_new_command(command):
|
|
14
|
+
return shell.and_('git branch --delete list', 'git branch')
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import subprocess
|
|
3
|
+
from thefuck import utils
|
|
4
|
+
from thefuck.utils import replace_argument
|
|
5
|
+
from thefuck.specific.git import git_support
|
|
6
|
+
from thefuck.shells import shell
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@git_support
|
|
10
|
+
def match(command):
|
|
11
|
+
return ('did not match any file(s) known to git' in command.output
|
|
12
|
+
and "Did you forget to 'git add'?" not in command.output)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_branches():
|
|
16
|
+
proc = subprocess.Popen(
|
|
17
|
+
['git', 'branch', '-a', '--no-color', '--no-column'],
|
|
18
|
+
stdout=subprocess.PIPE)
|
|
19
|
+
for line in proc.stdout.readlines():
|
|
20
|
+
line = line.decode('utf-8')
|
|
21
|
+
if '->' in line: # Remote HEAD like b' remotes/origin/HEAD -> origin/master'
|
|
22
|
+
continue
|
|
23
|
+
if line.startswith('*'):
|
|
24
|
+
line = line.split(' ')[1]
|
|
25
|
+
if line.strip().startswith('remotes/'):
|
|
26
|
+
line = '/'.join(line.split('/')[2:])
|
|
27
|
+
yield line.strip()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@git_support
|
|
31
|
+
def get_new_command(command):
|
|
32
|
+
missing_file = re.findall(
|
|
33
|
+
r"error: pathspec '([^']*)' "
|
|
34
|
+
r"did not match any file\(s\) known to git", command.output)[0]
|
|
35
|
+
closest_branch = utils.get_closest(missing_file, get_branches(),
|
|
36
|
+
fallback_to_first=False)
|
|
37
|
+
|
|
38
|
+
new_commands = []
|
|
39
|
+
|
|
40
|
+
if closest_branch:
|
|
41
|
+
new_commands.append(replace_argument(command.script, missing_file, closest_branch))
|
|
42
|
+
if command.script_parts[1] == 'checkout':
|
|
43
|
+
new_commands.append(replace_argument(command.script, 'checkout', 'checkout -b'))
|
|
44
|
+
|
|
45
|
+
if not new_commands:
|
|
46
|
+
new_commands.append(shell.and_('git branch {}', '{}').format(
|
|
47
|
+
missing_file, command.script))
|
|
48
|
+
|
|
49
|
+
return new_commands
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from thefuck.specific.git import git_support
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@git_support
|
|
5
|
+
def match(command):
|
|
6
|
+
return (' git clone ' in command.script
|
|
7
|
+
and 'fatal: Too many arguments.' in command.output)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@git_support
|
|
11
|
+
def get_new_command(command):
|
|
12
|
+
return command.script.replace(' git clone ', ' ', 1)
|