mirror of
				https://github.com/nvbn/thefuck.git
				synced 2025-10-31 07:04:12 +00:00 
			
		
		
		
	Merge branch 'master' of github.com:nvbn/thefuck
This commit is contained in:
		
							
								
								
									
										37
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | <!-- If you have any issue with The Fuck, sorry about that, but we will do what we | ||||||
|  | can to fix that. Actually, maybe we already have, so first thing to do is to | ||||||
|  | update The Fuck and see if the bug is still there. --> | ||||||
|  |  | ||||||
|  | <!-- If it is (sorry again), check if the problem has not already been reported and | ||||||
|  | if not, just open an issue on [GitHub](https://github.com/nvbn/thefuck) with | ||||||
|  | the following basic information: --> | ||||||
|  |  | ||||||
|  | The output of `thefuck --version` (something like `The Fuck 3.1 using Python 3.5.0`): | ||||||
|  |  | ||||||
|  |     FILL THIS IN | ||||||
|  |  | ||||||
|  | Your shell and its version (`bash`, `zsh`, *Windows PowerShell*, etc.): | ||||||
|  |  | ||||||
|  |     FILL THIS IN | ||||||
|  |  | ||||||
|  | Your system (Debian 7, ArchLinux, Windows, etc.): | ||||||
|  |  | ||||||
|  | <!-- FILL THIS IN --> | ||||||
|  |  | ||||||
|  | How to reproduce the bug: | ||||||
|  |  | ||||||
|  |     FILL THIS IN | ||||||
|  |  | ||||||
|  | The output of The Fuck with `THEFUCK_DEBUG=true` exported (typically execute `export THEFUCK_DEBUG=true` in your shell before The Fuck): | ||||||
|  |  | ||||||
|  |     FILL THIS IN | ||||||
|  |  | ||||||
|  | If the bug only appears with a specific application, the output of that application and its version: | ||||||
|  |  | ||||||
|  |     FILL THIS IN | ||||||
|  |  | ||||||
|  | Anything else you think is relevant: | ||||||
|  |  | ||||||
|  | <!-- FILL THIS IN --> | ||||||
|  |  | ||||||
|  | <!-- It's only with enough information that we can do something to fix the problem. --> | ||||||
| @@ -11,9 +11,6 @@ matrix: | |||||||
|     - os: linux |     - os: linux | ||||||
|       dist: trusty |       dist: trusty | ||||||
|       python: "3.4" |       python: "3.4" | ||||||
|     - os: linux |  | ||||||
|       dist: trusty |  | ||||||
|       python: "3.3" |  | ||||||
|     - os: linux |     - os: linux | ||||||
|       dist: trusty |       dist: trusty | ||||||
|       python: "2.7" |       python: "2.7" | ||||||
|   | |||||||
| @@ -23,3 +23,37 @@ It's only with enough information that we can do something to fix the problem. | |||||||
| We gladly accept pull request on the [official | We gladly accept pull request on the [official | ||||||
| repository](https://github.com/nvbn/thefuck) for new rules, new features, bug | repository](https://github.com/nvbn/thefuck) for new rules, new features, bug | ||||||
| fixes, etc. | fixes, etc. | ||||||
|  |  | ||||||
|  | # Developing | ||||||
|  |  | ||||||
|  | Install `The Fuck` for development: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | pip install -r requirements.txt | ||||||
|  | python setup.py develop | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Run code style checks: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | flake8 | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Run unit tests: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | py.test | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Run unit and functional tests (requires docker): | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | py.test --enable-functional | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | For sending package to pypi: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | sudo apt-get install pandoc | ||||||
|  | ./release.py | ||||||
|  | ``` | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| The MIT License (MIT) | The MIT License (MIT) | ||||||
| ===================== | ===================== | ||||||
|  |  | ||||||
| Copyright (c) 2015 Vladimir Iakovlev | Copyright (c) 2015-2018 Vladimir Iakovlev | ||||||
|  |  | ||||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
| of this software and associated documentation files (the "Software"), to deal | of this software and associated documentation files (the "Software"), to deal | ||||||
|   | |||||||
							
								
								
									
										50
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								README.md
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ Magnificent app which corrects your previous console command, | |||||||
| inspired by a [@liamosaur](https://twitter.com/liamosaur/) | inspired by a [@liamosaur](https://twitter.com/liamosaur/) | ||||||
| [tweet](https://twitter.com/liamosaur/status/506975850596536320). | [tweet](https://twitter.com/liamosaur/status/506975850596536320). | ||||||
|  |  | ||||||
| The Fuck is too slow? [Try experimental instant mode!](#experimental-instant-mode)  | The Fuck is too slow? [Try experimental instant mode!](#experimental-instant-mode) | ||||||
|  |  | ||||||
| [![gif with examples][examples-link]][examples-link] | [![gif with examples][examples-link]][examples-link] | ||||||
|  |  | ||||||
| @@ -92,7 +92,7 @@ Reading package lists... Done | |||||||
|  |  | ||||||
| ## Requirements | ## Requirements | ||||||
|  |  | ||||||
| - python (3.3+) | - python (3.4+) | ||||||
| - pip | - pip | ||||||
| - python-dev | - python-dev | ||||||
|  |  | ||||||
| @@ -111,6 +111,12 @@ sudo apt install python3-dev python3-pip | |||||||
| sudo pip3 install thefuck | sudo pip3 install thefuck | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | On FreeBSD you can install `The Fuck` with: | ||||||
|  | ```bash | ||||||
|  | sudo portsnap fetch update | ||||||
|  | cd /usr/ports/misc/thefuck && sudo make install clean | ||||||
|  | ``` | ||||||
|  |  | ||||||
| On other systems you can install `The Fuck` with `pip`: | On other systems you can install `The Fuck` with `pip`: | ||||||
|  |  | ||||||
| ```bash | ```bash | ||||||
| @@ -148,7 +154,7 @@ fuck -r | |||||||
| ## Update | ## Update | ||||||
|  |  | ||||||
| ```bash | ```bash | ||||||
| pip install thefuck --upgrade | pip3 install thefuck --upgrade | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| **Aliases changed in 1.34.** | **Aliases changed in 1.34.** | ||||||
| @@ -158,6 +164,7 @@ pip install thefuck --upgrade | |||||||
| The Fuck tries to match a rule for the previous command, creates a new command | The Fuck tries to match a rule for the previous command, creates a new command | ||||||
| using the matched rule and runs it. Rules enabled by default are as follows: | using the matched rule and runs it. Rules enabled by default are as follows: | ||||||
|  |  | ||||||
|  | * `adb_unknown_command` – fixes misspelled commands like `adb logcta`; | ||||||
| * `ag_literal` – adds `-Q` to `ag` when suggested; | * `ag_literal` – adds `-Q` to `ag` when suggested; | ||||||
| * `aws_cli` – fixes misspelled commands like `aws dynamdb scan`; | * `aws_cli` – fixes misspelled commands like `aws dynamdb scan`; | ||||||
| * `cargo` – runs `cargo build` instead of `cargo`; | * `cargo` – runs `cargo build` instead of `cargo`; | ||||||
| @@ -186,11 +193,14 @@ using the matched rule and runs it. Rules enabled by default are as follows: | |||||||
| * `git_branch_exists` – offers `git branch -d foo`, `git branch -D foo` or `git checkout foo` when creating a branch that already exists; | * `git_branch_exists` – offers `git branch -d foo`, `git branch -D foo` or `git checkout foo` when creating a branch that already exists; | ||||||
| * `git_branch_list` – catches `git branch list` in place of `git branch` and removes created branch; | * `git_branch_list` – catches `git branch list` in place of `git branch` and removes created branch; | ||||||
| * `git_checkout` – fixes branch name or creates new branch; | * `git_checkout` – fixes branch name or creates new branch; | ||||||
|  | * `git_commit_amend` – offers `git commit --amend` after previous commit; | ||||||
| * `git_diff_no_index` – adds `--no-index` to previous `git diff` on untracked files; | * `git_diff_no_index` – adds `--no-index` to previous `git diff` on untracked files; | ||||||
| * `git_diff_staged` – adds `--staged` to previous `git diff` with unexpected output; | * `git_diff_staged` – adds `--staged` to previous `git diff` with unexpected output; | ||||||
| * `git_fix_stash` – fixes `git stash` commands (misspelled subcommand and missing `save`); | * `git_fix_stash` – fixes `git stash` commands (misspelled subcommand and missing `save`); | ||||||
| * `git_flag_after_filename` – fixes `fatal: bad flag '...' after filename` | * `git_flag_after_filename` – fixes `fatal: bad flag '...' after filename` | ||||||
| * `git_help_aliased` – fixes `git help <alias>` commands replacing <alias> with the aliased command; | * `git_help_aliased` – fixes `git help <alias>` commands replacing <alias> with the aliased command; | ||||||
|  | * `git_merge` – adds remote to branch names; | ||||||
|  | * `git_merge_unrelated` – adds `--allow-unrelated-histories` when required | ||||||
| * `git_not_command` – fixes wrong git commands like `git brnch`; | * `git_not_command` – fixes wrong git commands like `git brnch`; | ||||||
| * `git_pull` – sets upstream before executing previous `git pull`; | * `git_pull` – sets upstream before executing previous `git pull`; | ||||||
| * `git_pull_clone` – clones instead of pulling when the repo does not exist; | * `git_pull_clone` – clones instead of pulling when the repo does not exist; | ||||||
| @@ -268,6 +278,7 @@ using the matched rule and runs it. Rules enabled by default are as follows: | |||||||
| * `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; | ||||||
| * `unknown_command` – fixes hadoop hdfs-style "unknown command", for example adds missing '-' to the command on `hdfs dfs ls`; | * `unknown_command` – fixes hadoop hdfs-style "unknown command", for example adds missing '-' to the command on `hdfs dfs ls`; | ||||||
|  | * `unsudo` – removes `sudo` from previous command if a process refuses to run on super user privilege. | ||||||
| * `vagrant_up` – starts up the vagrant instance; | * `vagrant_up` – starts up the vagrant instance; | ||||||
| * `whois` – fixes `whois` command; | * `whois` – fixes `whois` command; | ||||||
| * `workon_doesnt_exists` – fixes `virtualenvwrapper` env name os suggests to create new. | * `workon_doesnt_exists` – fixes `virtualenvwrapper` env name os suggests to create new. | ||||||
| @@ -282,6 +293,7 @@ Enabled by default only on specific platforms: | |||||||
| * `apt_get_search` – changes trying to search using `apt-get` with searching using `apt-cache`; | * `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_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_list_upgradable` – helps you run `apt list --upgradable` after `apt update`; | ||||||
|  | * `apt_upgrade` – helps you run `apt upgrade` after `apt list --upgradable`; | ||||||
| * `brew_cask_dependency` – installs cask dependencies; | * `brew_cask_dependency` – installs cask dependencies; | ||||||
| * `brew_install` – fixes formula name for `brew install`; | * `brew_install` – fixes formula name for `brew install`; | ||||||
| * `brew_link` – adds `--overwrite --dry-run` if linking fails; | * `brew_link` – adds `--overwrite --dry-run` if linking fails; | ||||||
| @@ -443,37 +455,7 @@ eval $(thefuck --alias --enable-experimental-instant-mode) | |||||||
|  |  | ||||||
| ## Developing | ## Developing | ||||||
|  |  | ||||||
| Install `The Fuck` for development: | See [CONTRIBUTING.md](CONTRIBUTING.md) | ||||||
|  |  | ||||||
| ```bash |  | ||||||
| pip install -r requirements.txt |  | ||||||
| python setup.py develop |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| Run code style checks: |  | ||||||
|  |  | ||||||
| ```bash |  | ||||||
| flake8 |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| Run unit tests: |  | ||||||
|  |  | ||||||
| ```bash |  | ||||||
| py.test |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| Run unit and functional tests (requires docker): |  | ||||||
|  |  | ||||||
| ```bash |  | ||||||
| py.test --enable-functional |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| For sending package to pypi: |  | ||||||
|  |  | ||||||
| ```bash |  | ||||||
| sudo apt-get install pandoc |  | ||||||
| ./release.py |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ## License MIT | ## License MIT | ||||||
| Project License can be found [here](LICENSE.md). | Project License can be found [here](LICENSE.md). | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ build: false | |||||||
| environment: | environment: | ||||||
|   matrix: |   matrix: | ||||||
|     - PYTHON: "C:/Python27" |     - PYTHON: "C:/Python27" | ||||||
|     - PYTHON: "C:/Python33" |  | ||||||
|     - PYTHON: "C:/Python34" |     - PYTHON: "C:/Python34" | ||||||
|     - PYTHON: "C:/Python35" |     - PYTHON: "C:/Python35" | ||||||
|     - PYTHON: "C:/Python36" |     - PYTHON: "C:/Python36" | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								setup.py
									
									
									
									
									
								
							| @@ -26,8 +26,8 @@ if version < (2, 7): | |||||||
|     print('thefuck requires Python version 2.7 or later' + |     print('thefuck requires Python version 2.7 or later' + | ||||||
|           ' ({}.{} detected).'.format(*version)) |           ' ({}.{} detected).'.format(*version)) | ||||||
|     sys.exit(-1) |     sys.exit(-1) | ||||||
| elif (3, 0) < version < (3, 3): | elif (3, 0) < version < (3, 4): | ||||||
|     print('thefuck requires Python version 3.3 or later' + |     print('thefuck requires Python version 3.4 or later' + | ||||||
|           ' ({}.{} detected).'.format(*version)) |           ' ({}.{} detected).'.format(*version)) | ||||||
|     sys.exit(-1) |     sys.exit(-1) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										41
									
								
								tests/rules/test_adb_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								tests/rules/test_adb_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.adb_unknown_command import match, get_new_command | ||||||
|  | from thefuck.types import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture | ||||||
|  | def output(): | ||||||
|  |     return '''Android Debug Bridge version 1.0.31 | ||||||
|  |  | ||||||
|  |  -d                            - directs command to the only connected USB device | ||||||
|  |                                  returns an error if more than one USB device is present. | ||||||
|  |  -e                            - directs command to the only running emulator. | ||||||
|  |                                  returns an error if more than one emulator is running. | ||||||
|  |  -s <specific device>          - directs command to the device or emulator with the given | ||||||
|  |                                  serial number or qualifier. Overrides ANDROID_SERIAL | ||||||
|  |                                  environment variable. | ||||||
|  | ''' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script', [ | ||||||
|  |     ('adb lgcat'), | ||||||
|  |     ('adb puhs')]) | ||||||
|  | def test_match(output, script): | ||||||
|  |     assert match(Command(script, output)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script', [ | ||||||
|  |     'git branch foo', | ||||||
|  |     'abd push']) | ||||||
|  | def test_not_match(script): | ||||||
|  |     assert not match(Command(script, '')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, new_command', [ | ||||||
|  |     ('adb puhs test.bin /sdcard/test.bin', 'adb push test.bin /sdcard/test.bin'), | ||||||
|  |     ('adb -s 1111 logcta', 'adb -s 1111 logcat'), | ||||||
|  |     ('adb -P 666 pulll /sdcard/test.bin', 'adb -P 666 pull /sdcard/test.bin'), | ||||||
|  |     ('adb -d logcatt', 'adb -d logcat'), | ||||||
|  |     ('adb -e reboott', 'adb -e reboot')]) | ||||||
|  | def test_get_new_command(script, output, new_command): | ||||||
|  |     assert get_new_command(Command(script, output)) == new_command | ||||||
| @@ -69,4 +69,7 @@ def test_not_match(command): | |||||||
|  |  | ||||||
| def test_get_new_command(): | def test_get_new_command(): | ||||||
|     new_command = get_new_command(Command('sudo apt update', match_output)) |     new_command = get_new_command(Command('sudo apt update', match_output)) | ||||||
|  |     assert new_command == 'sudo apt list --upgradable' | ||||||
|  |  | ||||||
|  |     new_command = get_new_command(Command('apt update', match_output)) | ||||||
|     assert new_command == 'apt list --upgradable' |     assert new_command == 'apt list --upgradable' | ||||||
|   | |||||||
							
								
								
									
										36
									
								
								tests/rules/test_apt_upgrade.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								tests/rules/test_apt_upgrade.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.apt_upgrade import get_new_command, match | ||||||
|  | from thefuck.types import Command | ||||||
|  |  | ||||||
|  | match_output = ''' | ||||||
|  | Listing... Done | ||||||
|  | heroku/stable 6.15.2-1 amd64 [upgradable from: 6.14.43-1] | ||||||
|  | resolvconf/zesty-updates,zesty-updates 1.79ubuntu4.1 all [upgradable from: 1.79ubuntu4] | ||||||
|  | squashfs-tools/zesty-updates 1:4.3-3ubuntu2.17.04.1 amd64 [upgradable from: 1:4.3-3ubuntu2] | ||||||
|  | unattended-upgrades/zesty-updates,zesty-updates 0.93.1ubuntu2.4 all [upgradable from: 0.93.1ubuntu2.3] | ||||||
|  | ''' | ||||||
|  |  | ||||||
|  | no_match_output = ''' | ||||||
|  | Listing... Done | ||||||
|  | ''' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_match(): | ||||||
|  |     assert match(Command('apt list --upgradable', match_output)) | ||||||
|  |     assert match(Command('sudo apt list --upgradable', match_output)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('command', [ | ||||||
|  |     Command('apt list --upgradable', no_match_output), | ||||||
|  |     Command('sudo apt list --upgradable', no_match_output) | ||||||
|  | ]) | ||||||
|  | def test_not_match(command): | ||||||
|  |     assert not match(command) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_get_new_command(): | ||||||
|  |     new_command = get_new_command(Command('apt list --upgradable', match_output)) | ||||||
|  |     assert new_command == 'apt upgrade' | ||||||
|  |  | ||||||
|  |     new_command = get_new_command(Command('sudo apt list --upgradable', match_output)) | ||||||
|  |     assert new_command == 'sudo apt upgrade' | ||||||
| @@ -4,8 +4,8 @@ from thefuck.types import Command | |||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.fixture | @pytest.fixture | ||||||
| def output(branch_name): | def output(src_branch_name): | ||||||
|     return "fatal: A branch named '{}' already exists.".format(branch_name) |     return "fatal: A branch named '{}' already exists.".format(src_branch_name) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.fixture | @pytest.fixture | ||||||
| @@ -17,18 +17,25 @@ def new_command(branch_name): | |||||||
|         'git branch -D {0} && git checkout -b {0}', 'git checkout {0}']] |         'git branch -D {0} && git checkout -b {0}', 'git checkout {0}']] | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize('script, branch_name', [ | @pytest.mark.parametrize('script, src_branch_name, branch_name', [ | ||||||
|     ('git branch foo', 'foo'), ('git checkout bar', 'bar')]) |     ('git branch foo', 'foo', 'foo'), | ||||||
|  |     ('git checkout bar', 'bar', 'bar'), | ||||||
|  |     ('git checkout -b "let\'s-push-this"', '"let\'s-push-this"', '"let\'s-push-this"')]) | ||||||
| def test_match(output, script, branch_name): | def test_match(output, script, branch_name): | ||||||
|     assert match(Command(script, output)) |     assert match(Command(script, output)) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize('script', ['git branch foo', 'git checkout bar']) | @pytest.mark.parametrize('script', [ | ||||||
|  |     'git branch foo', | ||||||
|  |     'git checkout bar', | ||||||
|  |     'git checkout -b "let\'s-push-this"']) | ||||||
| def test_not_match(script): | def test_not_match(script): | ||||||
|     assert not match(Command(script, '')) |     assert not match(Command(script, '')) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize('script, branch_name, ', [ | @pytest.mark.parametrize('script, src_branch_name, branch_name', [ | ||||||
|     ('git branch foo', 'foo'), ('git checkout bar', 'bar')]) |     ('git branch foo', 'foo', 'foo'), | ||||||
| def test_get_new_command(output, new_command, script, branch_name): |     ('git checkout bar', 'bar', 'bar'), | ||||||
|  |     ('git checkout -b "let\'s-push-this"', "let's-push-this", "let\\'s-push-this")]) | ||||||
|  | def test_get_new_command(output, new_command, script, src_branch_name, branch_name): | ||||||
|     assert get_new_command(Command(script, output)) == new_command |     assert get_new_command(Command(script, output)) == new_command | ||||||
|   | |||||||
| @@ -52,7 +52,7 @@ def test_get_branches(branches, branch_list, git_branch): | |||||||
| @pytest.mark.parametrize('branches, command, new_command', [ | @pytest.mark.parametrize('branches, command, new_command', [ | ||||||
|     (b'', |     (b'', | ||||||
|      Command('git checkout unknown', did_not_match('unknown')), |      Command('git checkout unknown', did_not_match('unknown')), | ||||||
|      'git branch unknown && git checkout unknown'), |      'git checkout -b unknown'), | ||||||
|     (b'', |     (b'', | ||||||
|      Command('git commit unknown', did_not_match('unknown')), |      Command('git commit unknown', did_not_match('unknown')), | ||||||
|      'git branch unknown && git commit unknown'), |      'git branch unknown && git commit unknown'), | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								tests/rules/test_git_commit_amend.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/rules/test_git_commit_amend.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.git_commit_amend import match, get_new_command | ||||||
|  | from thefuck.types import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script, output', [ | ||||||
|  |     ('git commit -m "test"', 'test output'), | ||||||
|  |     ('git commit', '')]) | ||||||
|  | def test_match(output, script): | ||||||
|  |     assert match(Command(script, output)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script', [ | ||||||
|  |     'git branch foo', | ||||||
|  |     'git checkout feature/test_commit', | ||||||
|  |     'git push']) | ||||||
|  | def test_not_match(script): | ||||||
|  |     assert not match(Command(script, '')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('script', [ | ||||||
|  |     ('git commit -m "test commit"'), | ||||||
|  |     ('git commit')]) | ||||||
|  | def test_get_new_command(script): | ||||||
|  |     assert get_new_command(Command(script, '')) == 'git commit --amend' | ||||||
							
								
								
									
										26
									
								
								tests/rules/test_git_merge.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								tests/rules/test_git_merge.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.git_merge import match, get_new_command | ||||||
|  | from thefuck.types import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture | ||||||
|  | def output(): | ||||||
|  |     return 'merge: local - not something we can merge\n\n' \ | ||||||
|  |         'Did you mean this?\n\tremote/local' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_match(output): | ||||||
|  |     assert match(Command('git merge test', output)) | ||||||
|  |     assert not match(Command('git merge master', '')) | ||||||
|  |     assert not match(Command('ls', output)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('command, new_command', [ | ||||||
|  |     (Command('git merge local', output()), | ||||||
|  |      'git merge remote/local'), | ||||||
|  |     (Command('git merge -m "test" local', output()), | ||||||
|  |      'git merge -m "test" remote/local'), | ||||||
|  |     (Command('git merge -m "test local" local', output()), | ||||||
|  |      'git merge -m "test local" remote/local')]) | ||||||
|  | def test_get_new_command(command, new_command): | ||||||
|  |     assert get_new_command(command) == new_command | ||||||
							
								
								
									
										25
									
								
								tests/rules/test_git_merge_unrelated.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/rules/test_git_merge_unrelated.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.git_merge_unrelated import match, get_new_command | ||||||
|  | from thefuck.types import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture | ||||||
|  | def output(): | ||||||
|  |     return 'fatal: refusing to merge unrelated histories' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_match(output): | ||||||
|  |     assert match(Command('git merge test', output)) | ||||||
|  |     assert not match(Command('git merge master', '')) | ||||||
|  |     assert not match(Command('ls', output)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('command, new_command', [ | ||||||
|  |     (Command('git merge local', output()), | ||||||
|  |      'git merge local --allow-unrelated-histories'), | ||||||
|  |     (Command('git merge -m "test" local', output()), | ||||||
|  |      'git merge -m "test" local --allow-unrelated-histories'), | ||||||
|  |     (Command('git merge -m "test local" local', output()), | ||||||
|  |      'git merge -m "test local" local --allow-unrelated-histories')]) | ||||||
|  | def test_get_new_command(command, new_command): | ||||||
|  |     assert get_new_command(command) == new_command | ||||||
| @@ -4,30 +4,68 @@ from thefuck.types import Command | |||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.fixture | @pytest.fixture | ||||||
| def output(): | def output(branch_name): | ||||||
|     return '''fatal: The current branch master has no upstream branch. |     if not branch_name: | ||||||
|  |         return '' | ||||||
|  |     return '''fatal: The current branch {} has no upstream branch. | ||||||
| To push the current branch and set the remote as upstream, use | To push the current branch and set the remote as upstream, use | ||||||
|  |  | ||||||
|     git push --set-upstream origin master |     git push --set-upstream origin {} | ||||||
|  |  | ||||||
|  | '''.format(branch_name, branch_name) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.fixture | ||||||
|  | def output_bitbucket(): | ||||||
|  |     return '''Total 0 (delta 0), reused 0 (delta 0) | ||||||
|  | remote: | ||||||
|  | remote: Create pull request for feature/set-upstream: | ||||||
|  | remote:   https://bitbucket.org/set-upstream | ||||||
|  | remote: | ||||||
|  | To git@bitbucket.org:test.git | ||||||
|  |    e5e7fbb..700d998  feature/set-upstream -> feature/set-upstream | ||||||
|  | Branch feature/set-upstream set up to track remote branch feature/set-upstream from origin. | ||||||
| ''' | ''' | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_match(output): | @pytest.mark.parametrize('script, branch_name', [ | ||||||
|     assert match(Command('git push', output)) |     ('git push', 'master'), | ||||||
|     assert match(Command('git push master', output)) |     ('git push origin', 'master')]) | ||||||
|     assert not match(Command('git push master', '')) | def test_match(output, script, branch_name): | ||||||
|     assert not match(Command('ls', output)) |     assert match(Command(script, output)) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_get_new_command(output): | def test_match_bitbucket(output_bitbucket): | ||||||
|     assert get_new_command(Command('git push', output))\ |     assert not match(Command('git push origin', output_bitbucket)) | ||||||
|         == "git push --set-upstream origin master" |  | ||||||
|     assert get_new_command(Command('git push -u', output))\ |  | ||||||
|         == "git push --set-upstream origin master" | @pytest.mark.parametrize('script, branch_name', [ | ||||||
|     assert get_new_command(Command('git push -u origin', output))\ |     ('git push master', None), | ||||||
|         == "git push --set-upstream origin master" |     ('ls', 'master')]) | ||||||
|     assert get_new_command(Command('git push --set-upstream origin', output))\ | def test_not_match(output, script, branch_name): | ||||||
|         == "git push --set-upstream origin master" |     assert not match(Command(script, output)) | ||||||
|     assert get_new_command(Command('git push --quiet', output))\ |  | ||||||
|         == "git push --set-upstream origin master --quiet" |  | ||||||
|  | @pytest.mark.parametrize('script, branch_name, new_command', [ | ||||||
|  |     ('git push', 'master', | ||||||
|  |      'git push --set-upstream origin master'), | ||||||
|  |     ('git push master', 'master', | ||||||
|  |      'git push --set-upstream origin master'), | ||||||
|  |     ('git push -u', 'master', | ||||||
|  |      'git push --set-upstream origin master'), | ||||||
|  |     ('git push -u origin', 'master', | ||||||
|  |      'git push --set-upstream origin master'), | ||||||
|  |     ('git push origin', 'master', | ||||||
|  |      'git push --set-upstream origin master'), | ||||||
|  |     ('git push --set-upstream origin', 'master', | ||||||
|  |      'git push --set-upstream origin master'), | ||||||
|  |     ('git push --quiet', 'master', | ||||||
|  |      'git push --set-upstream origin master --quiet'), | ||||||
|  |     ('git push --quiet origin', 'master', | ||||||
|  |      'git push --set-upstream origin master --quiet'), | ||||||
|  |     ('git -c test=test push --quiet origin', 'master', | ||||||
|  |      'git -c test=test push --set-upstream origin master --quiet'), | ||||||
|  |     ('git push', "test's", | ||||||
|  |      "git push --set-upstream origin test\\'s")]) | ||||||
|  | def test_get_new_command(output, script, branch_name, new_command): | ||||||
|  |     assert get_new_command(Command(script, output)) == new_command | ||||||
|   | |||||||
| @@ -7,7 +7,9 @@ from thefuck.types import Command | |||||||
|  |  | ||||||
| @pytest.mark.parametrize('command', [ | @pytest.mark.parametrize('command', [ | ||||||
|     Command(u'фзе-пуе', 'command not found: фзе-пуе'), |     Command(u'фзе-пуе', 'command not found: фзе-пуе'), | ||||||
|     Command(u'λσ', 'command not found: λσ')]) |     Command(u'λσ', 'command not found: λσ'), | ||||||
|  |     Command(u'שפא-עקא', 'command not found: שפא-עקא'), | ||||||
|  |     Command(u'ךד', 'command not found: ךד')]) | ||||||
| def test_match(command): | def test_match(command): | ||||||
|     assert switch_lang.match(command) |     assert switch_lang.match(command) | ||||||
|  |  | ||||||
| @@ -16,13 +18,16 @@ def test_match(command): | |||||||
|     Command(u'pat-get', 'command not found: pat-get'), |     Command(u'pat-get', 'command not found: pat-get'), | ||||||
|     Command(u'ls', 'command not found: ls'), |     Command(u'ls', 'command not found: ls'), | ||||||
|     Command(u'агсл', 'command not found: агсл'), |     Command(u'агсл', 'command not found: агсл'), | ||||||
|     Command(u'фзе-пуе', 'some info')]) |     Command(u'фзе-пуе', 'some info'), | ||||||
|  |     Command(u'שפא-עקא', 'some info')]) | ||||||
| def test_not_match(command): | def test_not_match(command): | ||||||
|     assert not switch_lang.match(command) |     assert not switch_lang.match(command) | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize('command, new_command', [ | @pytest.mark.parametrize('command, new_command', [ | ||||||
|     (Command(u'фзе-пуе штыефдд мшь', ''), 'apt-get install vim'), |     (Command(u'фзе-пуе штыефдд мшь', ''), 'apt-get install vim'), | ||||||
|     (Command(u'λσ -λα', ''), 'ls -la')]) |     (Command(u'λσ -λα', ''), 'ls -la'), | ||||||
|  |     (Command(u'שפא-עקא ןמדאשךך הןצ', ''), 'apt-get install vim'), | ||||||
|  |     (Command(u'ךד -ךש', ''), 'ls -la')]) | ||||||
| def test_get_new_command(command, new_command): | def test_get_new_command(command, new_command): | ||||||
|     assert switch_lang.get_new_command(command) == new_command |     assert switch_lang.get_new_command(command) == new_command | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								tests/rules/test_unsudo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/rules/test_unsudo.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | import pytest | ||||||
|  | from thefuck.rules.unsudo import match, get_new_command | ||||||
|  | from thefuck.types import Command | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('output', [ | ||||||
|  |     'you cannot perform this operation as root']) | ||||||
|  | def test_match(output): | ||||||
|  |     assert match(Command('sudo ls', output)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_not_match(): | ||||||
|  |     assert not match(Command('', '')) | ||||||
|  |     assert not match(Command('sudo ls', 'Permission denied')) | ||||||
|  |     assert not match(Command('ls', 'you cannot perform this operation as root')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize('before, after', [ | ||||||
|  |     ('sudo ls', 'ls'), | ||||||
|  |     ('sudo pacaur -S helloworld', 'pacaur -S helloworld')]) | ||||||
|  | def test_get_new_command(before, after): | ||||||
|  |     assert get_new_command(Command(before, '')) == after | ||||||
| @@ -51,6 +51,7 @@ class TestBash(object): | |||||||
|     def test_app_alias_variables_correctly_set(self, shell): |     def test_app_alias_variables_correctly_set(self, shell): | ||||||
|         alias = shell.app_alias('fuck') |         alias = shell.app_alias('fuck') | ||||||
|         assert "fuck () {" in alias |         assert "fuck () {" in alias | ||||||
|  |         assert 'TF_SHELL=bash' in alias | ||||||
|         assert "TF_ALIAS=fuck" in alias |         assert "TF_ALIAS=fuck" in alias | ||||||
|         assert 'PYTHONIOENCODING=utf-8' in alias |         assert 'PYTHONIOENCODING=utf-8' in alias | ||||||
|         assert 'TF_SHELL_ALIASES=$(alias)' in alias |         assert 'TF_SHELL_ALIASES=$(alias)' in alias | ||||||
|   | |||||||
| @@ -13,9 +13,10 @@ class TestFish(object): | |||||||
|     @pytest.fixture(autouse=True) |     @pytest.fixture(autouse=True) | ||||||
|     def Popen(self, mocker): |     def Popen(self, mocker): | ||||||
|         mock = mocker.patch('thefuck.shells.fish.Popen') |         mock = mocker.patch('thefuck.shells.fish.Popen') | ||||||
|         mock.return_value.stdout.read.return_value = ( |         mock.return_value.stdout.read.side_effect = [( | ||||||
|             b'cd\nfish_config\nfuck\nfunced\nfuncsave\ngrep\nhistory\nll\nls\n' |             b'cd\nfish_config\nfuck\nfunced\nfuncsave\ngrep\nhistory\nll\nls\n' | ||||||
|             b'man\nmath\npopd\npushd\nruby') |             b'man\nmath\npopd\npushd\nruby'), | ||||||
|  |             b'alias fish_key_reader /usr/bin/fish_key_reader\nalias g git'] | ||||||
|         return mock |         return mock | ||||||
|  |  | ||||||
|     @pytest.mark.parametrize('key, value', [ |     @pytest.mark.parametrize('key, value', [ | ||||||
| @@ -42,7 +43,8 @@ class TestFish(object): | |||||||
|         ('open', 'open'), |         ('open', 'open'), | ||||||
|         ('vim', 'vim'), |         ('vim', 'vim'), | ||||||
|         ('ll', 'fish -ic "ll"'), |         ('ll', 'fish -ic "ll"'), | ||||||
|         ('ls', 'ls')])  # Fish has no aliases but functions |         ('ls', 'ls'), | ||||||
|  |         ('g', 'git')]) | ||||||
|     def test_from_shell(self, before, after, shell): |     def test_from_shell(self, before, after, shell): | ||||||
|         assert shell.from_shell(before) == after |         assert shell.from_shell(before) == after | ||||||
|  |  | ||||||
| @@ -65,12 +67,15 @@ class TestFish(object): | |||||||
|                                        'math': 'math', |                                        'math': 'math', | ||||||
|                                        'popd': 'popd', |                                        'popd': 'popd', | ||||||
|                                        'pushd': 'pushd', |                                        'pushd': 'pushd', | ||||||
|                                        'ruby': 'ruby'} |                                        'ruby': 'ruby', | ||||||
|  |                                        'g': 'git', | ||||||
|  |                                        'fish_key_reader': '/usr/bin/fish_key_reader'} | ||||||
|  |  | ||||||
|     def test_app_alias(self, shell): |     def test_app_alias(self, shell): | ||||||
|         assert 'function fuck' in shell.app_alias('fuck') |         assert 'function fuck' in shell.app_alias('fuck') | ||||||
|         assert 'function FUCK' in shell.app_alias('FUCK') |         assert 'function FUCK' in shell.app_alias('FUCK') | ||||||
|         assert 'thefuck' in shell.app_alias('fuck') |         assert 'thefuck' in shell.app_alias('fuck') | ||||||
|  |         assert 'TF_SHELL=fish' in shell.app_alias('fuck') | ||||||
|         assert 'TF_ALIAS=fuck PYTHONIOENCODING' in shell.app_alias('fuck') |         assert 'TF_ALIAS=fuck PYTHONIOENCODING' in shell.app_alias('fuck') | ||||||
|         assert 'PYTHONIOENCODING=utf-8 thefuck' in shell.app_alias('fuck') |         assert 'PYTHONIOENCODING=utf-8 thefuck' in shell.app_alias('fuck') | ||||||
|  |  | ||||||
|   | |||||||
| @@ -44,6 +44,7 @@ class TestTcsh(object): | |||||||
|                                        'll': 'ls -alF'} |                                        'll': 'ls -alF'} | ||||||
|  |  | ||||||
|     def test_app_alias(self, shell): |     def test_app_alias(self, shell): | ||||||
|  |         assert 'setenv TF_SHELL tcsh' in shell.app_alias('fuck') | ||||||
|         assert 'alias fuck' in shell.app_alias('fuck') |         assert 'alias fuck' in shell.app_alias('fuck') | ||||||
|         assert 'alias FUCK' in shell.app_alias('FUCK') |         assert 'alias FUCK' in shell.app_alias('FUCK') | ||||||
|         assert 'thefuck' in shell.app_alias('fuck') |         assert 'thefuck' in shell.app_alias('fuck') | ||||||
|   | |||||||
| @@ -51,6 +51,7 @@ class TestZsh(object): | |||||||
|     def test_app_alias_variables_correctly_set(self, shell): |     def test_app_alias_variables_correctly_set(self, shell): | ||||||
|         alias = shell.app_alias('fuck') |         alias = shell.app_alias('fuck') | ||||||
|         assert "fuck () {" in alias |         assert "fuck () {" in alias | ||||||
|  |         assert 'TF_SHELL=zsh' in alias | ||||||
|         assert "TF_ALIAS=fuck" in alias |         assert "TF_ALIAS=fuck" in alias | ||||||
|         assert 'PYTHONIOENCODING=utf-8' in alias |         assert 'PYTHONIOENCODING=utf-8' in alias | ||||||
|         assert 'TF_SHELL_ALIASES=$(alias)' in alias |         assert 'TF_SHELL_ALIASES=$(alias)' in alias | ||||||
|   | |||||||
							
								
								
									
										54
									
								
								thefuck/rules/adb_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								thefuck/rules/adb_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | from thefuck.utils import is_app, get_closest, replace_argument | ||||||
|  |  | ||||||
|  |  | ||||||
|  | _ADB_COMMANDS = ( | ||||||
|  |     'backup', | ||||||
|  |     'bugreport', | ||||||
|  |     'connect', | ||||||
|  |     'devices', | ||||||
|  |     'disable-verity', | ||||||
|  |     'disconnect', | ||||||
|  |     'enable-verity', | ||||||
|  |     'emu', | ||||||
|  |     'forward', | ||||||
|  |     'get-devpath', | ||||||
|  |     'get-serialno', | ||||||
|  |     'get-state', | ||||||
|  |     'install', | ||||||
|  |     'install-multiple', | ||||||
|  |     'jdwp', | ||||||
|  |     'keygen', | ||||||
|  |     'kill-server', | ||||||
|  |     'logcat', | ||||||
|  |     'pull', | ||||||
|  |     'push', | ||||||
|  |     'reboot', | ||||||
|  |     'reconnect', | ||||||
|  |     'restore', | ||||||
|  |     'reverse', | ||||||
|  |     'root', | ||||||
|  |     'run-as', | ||||||
|  |     'shell', | ||||||
|  |     'sideload', | ||||||
|  |     'start-server', | ||||||
|  |     'sync', | ||||||
|  |     'tcpip', | ||||||
|  |     'uninstall', | ||||||
|  |     'unroot', | ||||||
|  |     'usb', | ||||||
|  |     'wait-for', | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def match(command): | ||||||
|  |     return (is_app(command, 'adb') | ||||||
|  |             and command.output.startswith('Android Debug Bridge version')) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_new_command(command): | ||||||
|  |     for idx, arg in enumerate(command.script_parts[1:]): | ||||||
|  |         # allowed params to ADB are a/d/e/s/H/P/L where s, H, P and L take additional args | ||||||
|  |         # for example 'adb -s 111 logcat' or 'adb -e logcat' | ||||||
|  |         if not arg[0] == '-' and not command.script_parts[idx] in ('-s', '-H', '-P', '-L'): | ||||||
|  |             adb_cmd = get_closest(arg, _ADB_COMMANDS) | ||||||
|  |             return replace_argument(command.script, arg, adb_cmd) | ||||||
| @@ -11,5 +11,6 @@ def match(command): | |||||||
|     return "Run 'apt list --upgradable' to see them." in command.output |     return "Run 'apt list --upgradable' to see them." in command.output | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @sudo_support | ||||||
| def get_new_command(command): | def get_new_command(command): | ||||||
|     return 'apt list --upgradable' |     return 'apt list --upgradable' | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								thefuck/rules/apt_upgrade.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								thefuck/rules/apt_upgrade.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | from thefuck.specific.apt import apt_available | ||||||
|  | from thefuck.specific.sudo import sudo_support | ||||||
|  | from thefuck.utils import for_app | ||||||
|  |  | ||||||
|  | enabled_by_default = apt_available | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @sudo_support | ||||||
|  | @for_app('apt') | ||||||
|  | def match(command): | ||||||
|  |     return command.script == "apt list --upgradable" and len(command.output.strip().split('\n')) > 1 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @sudo_support | ||||||
|  | def get_new_command(command): | ||||||
|  |     return 'apt upgrade' | ||||||
| @@ -7,14 +7,15 @@ from thefuck.utils import eager | |||||||
| @git_support | @git_support | ||||||
| def match(command): | def match(command): | ||||||
|     return ("fatal: A branch named '" in command.output |     return ("fatal: A branch named '" in command.output | ||||||
|             and " already exists." in command.output) |             and "' already exists." in command.output) | ||||||
|  |  | ||||||
|  |  | ||||||
| @git_support | @git_support | ||||||
| @eager | @eager | ||||||
| def get_new_command(command): | def get_new_command(command): | ||||||
|     branch_name = re.findall( |     branch_name = re.findall( | ||||||
|         r"fatal: A branch named '([^']*)' already exists.", command.output)[0] |         r"fatal: A branch named '(.+)' already exists.", command.output)[0] | ||||||
|  |     branch_name = branch_name.replace("'", r"\'") | ||||||
|     new_command_templates = [['git branch -d {0}', 'git branch {0}'], |     new_command_templates = [['git branch -d {0}', 'git branch {0}'], | ||||||
|                              ['git branch -d {0}', 'git checkout -b {0}'], |                              ['git branch -d {0}', 'git checkout -b {0}'], | ||||||
|                              ['git branch -D {0}', 'git branch {0}'], |                              ['git branch -D {0}', 'git branch {0}'], | ||||||
|   | |||||||
| @@ -34,6 +34,8 @@ def get_new_command(command): | |||||||
|                                        fallback_to_first=False) |                                        fallback_to_first=False) | ||||||
|     if closest_branch: |     if closest_branch: | ||||||
|         return replace_argument(command.script, missing_file, closest_branch) |         return replace_argument(command.script, missing_file, closest_branch) | ||||||
|  |     elif command.script_parts[1] == 'checkout': | ||||||
|  |         return replace_argument(command.script, 'checkout', 'checkout -b') | ||||||
|     else: |     else: | ||||||
|         return shell.and_('git branch {}', '{}').format( |         return shell.and_('git branch {}', '{}').format( | ||||||
|             missing_file, command.script) |             missing_file, command.script) | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								thefuck/rules/git_commit_amend.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								thefuck/rules/git_commit_amend.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | from thefuck.specific.git import git_support | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def match(command): | ||||||
|  |     return ('commit' in command.script_parts) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def get_new_command(command): | ||||||
|  |     return 'git commit --amend' | ||||||
							
								
								
									
										18
									
								
								thefuck/rules/git_merge.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								thefuck/rules/git_merge.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | import re | ||||||
|  | from thefuck.utils import replace_argument | ||||||
|  | from thefuck.specific.git import git_support | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def match(command): | ||||||
|  |     return ('merge' in command.script | ||||||
|  |             and ' - not something we can merge' in command.output | ||||||
|  |             and 'Did you mean this?' in command.output) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def get_new_command(command): | ||||||
|  |     unknown_branch = re.findall(r'merge: (.+) - not something we can merge', command.output)[0] | ||||||
|  |     remote_branch = re.findall(r'Did you mean this\?\n\t([^\n]+)', command.output)[0] | ||||||
|  |  | ||||||
|  |     return replace_argument(command.script, unknown_branch, remote_branch) | ||||||
							
								
								
									
										12
									
								
								thefuck/rules/git_merge_unrelated.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								thefuck/rules/git_merge_unrelated.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | from thefuck.specific.git import git_support | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def match(command): | ||||||
|  |     return ('merge' in command.script | ||||||
|  |             and 'fatal: refusing to merge unrelated histories' in command.output) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @git_support | ||||||
|  | def get_new_command(command): | ||||||
|  |     return command.script + ' --allow-unrelated-histories' | ||||||
| @@ -5,8 +5,8 @@ from thefuck.specific.git import git_support | |||||||
|  |  | ||||||
| @git_support | @git_support | ||||||
| def match(command): | def match(command): | ||||||
|     return ('push' in command.script |     return ('push' in command.script_parts | ||||||
|             and 'set-upstream' in command.output) |             and 'git push --set-upstream' in command.output) | ||||||
|  |  | ||||||
|  |  | ||||||
| def _get_upstream_option_index(command_parts): | def _get_upstream_option_index(command_parts): | ||||||
| @@ -32,7 +32,13 @@ def get_new_command(command): | |||||||
|         # In case of `git push -u` we don't have next argument: |         # In case of `git push -u` we don't have next argument: | ||||||
|         if len(command_parts) > upstream_option_index: |         if len(command_parts) > upstream_option_index: | ||||||
|             command_parts.pop(upstream_option_index) |             command_parts.pop(upstream_option_index) | ||||||
|  |     else: | ||||||
|  |         # the only non-qualified permitted options are the repository and refspec; git's | ||||||
|  |         # suggestion include them, so they won't be lost, but would be duplicated otherwise. | ||||||
|  |         push_idx = command_parts.index('push') + 1 | ||||||
|  |         while len(command_parts) > push_idx and command_parts[len(command_parts) - 1][0] != '-': | ||||||
|  |             command_parts.pop(len(command_parts) - 1) | ||||||
|  |  | ||||||
|     arguments = re.findall(r'git push (.*)', command.output)[0].strip() |     arguments = re.findall(r'git push (.*)', command.output)[0].replace("'", r"\'").strip() | ||||||
|     return replace_argument(" ".join(command_parts), 'push', |     return replace_argument(" ".join(command_parts), 'push', | ||||||
|                             'push {}'.format(arguments)) |                             'push {}'.format(arguments)) | ||||||
|   | |||||||
| @@ -5,7 +5,8 @@ target_layout = '''qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP{}ASDFGHJKL:"ZXCVB | |||||||
|  |  | ||||||
| source_layouts = [u'''йцукенгшщзхъфывапролджэячсмитьбю.ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,''', | source_layouts = [u'''йцукенгшщзхъфывапролджэячсмитьбю.ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,''', | ||||||
|                   u'''ضصثقفغعهخحجچشسیبلاتنمکگظطزرذدپو./ًٌٍَُِّْ][}{ؤئيإأآة»«:؛كٓژٰٔء><؟''', |                   u'''ضصثقفغعهخحجچشسیبلاتنمکگظطزرذدپو./ًٌٍَُِّْ][}{ؤئيإأآة»«:؛كٓژٰٔء><؟''', | ||||||
|                   u''';ςερτυθιοπ[]ασδφγηξκλ΄ζχψωβνμ,./:΅ΕΡΤΥΘΙΟΠ{}ΑΣΔΦΓΗΞΚΛ¨"ΖΧΨΩΒΝΜ<>?'''] |                   u''';ςερτυθιοπ[]ασδφγηξκλ΄ζχψωβνμ,./:΅ΕΡΤΥΘΙΟΠ{}ΑΣΔΦΓΗΞΚΛ¨"ΖΧΨΩΒΝΜ<>?''', | ||||||
|  |                   u'''/'קראטוןםפ][שדגכעיחלךף,זסבהנמצתץ.QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?'''] | ||||||
|  |  | ||||||
|  |  | ||||||
| @memoize | @memoize | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								thefuck/rules/unsudo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								thefuck/rules/unsudo.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | patterns = ['you cannot perform this operation as root'] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def match(command): | ||||||
|  |     if command.script_parts and command.script_parts[0] != 'sudo': | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     for pattern in patterns: | ||||||
|  |         if pattern in command.output.lower(): | ||||||
|  |             return True | ||||||
|  |     return False | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_new_command(command): | ||||||
|  |     return ' '.join(command.script_parts[1:]) | ||||||
| @@ -10,12 +10,24 @@ from .generic import Generic | |||||||
|  |  | ||||||
|  |  | ||||||
| @cache('~/.config/fish/config.fish', '~/.config/fish/functions') | @cache('~/.config/fish/config.fish', '~/.config/fish/functions') | ||||||
| def _get_aliases(overridden): | def _get_functions(overridden): | ||||||
|     proc = Popen(['fish', '-ic', 'functions'], stdout=PIPE, stderr=DEVNULL) |     proc = Popen(['fish', '-ic', 'functions'], stdout=PIPE, stderr=DEVNULL) | ||||||
|     functions = proc.stdout.read().decode('utf-8').strip().split('\n') |     functions = proc.stdout.read().decode('utf-8').strip().split('\n') | ||||||
|     return {func: func for func in functions if func not in overridden} |     return {func: func for func in functions if func not in overridden} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @cache('~/.config/fish/config.fish') | ||||||
|  | def _get_aliases(overridden): | ||||||
|  |     aliases = {} | ||||||
|  |     proc = Popen(['fish', '-ic', 'alias'], stdout=PIPE, stderr=DEVNULL) | ||||||
|  |     alias_out = proc.stdout.read().decode('utf-8').strip().split('\n') | ||||||
|  |     for alias in alias_out: | ||||||
|  |         name, value = alias.replace('alias ', '', 1).split(' ', 1) | ||||||
|  |         if name not in overridden: | ||||||
|  |             aliases[name] = value | ||||||
|  |     return aliases | ||||||
|  |  | ||||||
|  |  | ||||||
| class Fish(Generic): | class Fish(Generic): | ||||||
|     def _get_overridden_aliases(self): |     def _get_overridden_aliases(self): | ||||||
|         overridden = os.environ.get('THEFUCK_OVERRIDDEN_ALIASES', |         overridden = os.environ.get('THEFUCK_OVERRIDDEN_ALIASES', | ||||||
| @@ -35,7 +47,7 @@ class Fish(Generic): | |||||||
|         # It is VERY important to have the variables declared WITHIN the alias |         # It is VERY important to have the variables declared WITHIN the alias | ||||||
|         return ('function {0} -d "Correct your previous console command"\n' |         return ('function {0} -d "Correct your previous console command"\n' | ||||||
|                 '  set -l fucked_up_command $history[1]\n' |                 '  set -l fucked_up_command $history[1]\n' | ||||||
|                 '  env TF_ALIAS={0} PYTHONIOENCODING=utf-8' |                 '  env TF_SHELL=fish TF_ALIAS={0} PYTHONIOENCODING=utf-8' | ||||||
|                 ' thefuck $fucked_up_command | read -l unfucked_command\n' |                 ' thefuck $fucked_up_command | read -l unfucked_command\n' | ||||||
|                 '  if [ "$unfucked_command" != "" ]\n' |                 '  if [ "$unfucked_command" != "" ]\n' | ||||||
|                 '    eval $unfucked_command\n{1}' |                 '    eval $unfucked_command\n{1}' | ||||||
| @@ -44,12 +56,17 @@ class Fish(Generic): | |||||||
|  |  | ||||||
|     def get_aliases(self): |     def get_aliases(self): | ||||||
|         overridden = self._get_overridden_aliases() |         overridden = self._get_overridden_aliases() | ||||||
|         return _get_aliases(overridden) |         functions = _get_functions(overridden) | ||||||
|  |         raw_aliases = _get_aliases(overridden) | ||||||
|  |         functions.update(raw_aliases) | ||||||
|  |         return functions | ||||||
|  |  | ||||||
|     def _expand_aliases(self, command_script): |     def _expand_aliases(self, command_script): | ||||||
|         aliases = self.get_aliases() |         aliases = self.get_aliases() | ||||||
|         binary = command_script.split(' ')[0] |         binary = command_script.split(' ')[0] | ||||||
|         if binary in aliases: |         if binary in aliases and aliases[binary] != binary: | ||||||
|  |             return command_script.replace(binary, aliases[binary], 1) | ||||||
|  |         elif binary in aliases: | ||||||
|             return u'fish -ic "{}"'.format(command_script.replace('"', r'\"')) |             return u'fish -ic "{}"'.format(command_script.replace('"', r'\"')) | ||||||
|         else: |         else: | ||||||
|             return command_script |             return command_script | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ from .generic import Generic | |||||||
|  |  | ||||||
| class Tcsh(Generic): | class Tcsh(Generic): | ||||||
|     def app_alias(self, alias_name): |     def app_alias(self, alias_name): | ||||||
|         return ("alias {0} 'setenv TF_ALIAS {0} && " |         return ("alias {0} 'setenv TF_SHELL tcsh && setenv TF_ALIAS {0} && " | ||||||
|                 "set fucked_cmd=`history -h 2 | head -n 1` && " |                 "set fucked_cmd=`history -h 2 | head -n 1` && " | ||||||
|                 "eval `thefuck ${{fucked_cmd}}`'").format(alias_name) |                 "eval `thefuck ${{fucked_cmd}}`'").format(alias_name) | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user