mirror of
				https://github.com/nvbn/thefuck.git
				synced 2025-11-04 09:02:08 +00:00 
			
		
		
		
	Compare commits
	
		
			94 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					d3a05426de | ||
| 
						 | 
					88db57b4b1 | ||
| 
						 | 
					444908ce1c | ||
| 
						 | 
					2ced7a7f33 | ||
| 
						 | 
					b28ece0f34 | ||
| 
						 | 
					eb60900330 | ||
| 
						 | 
					ed8aaa7f26 | ||
| 
						 | 
					77992029b6 | ||
| 
						 | 
					25c858c13e | ||
| 
						 | 
					60073bea78 | ||
| 
						 | 
					d10fc80fa5 | ||
| 
						 | 
					fdea32b47d | ||
| 
						 | 
					9381cfefa5 | ||
| 
						 | 
					793510ad48 | ||
| 
						 | 
					d85099b8da | ||
| 
						 | 
					ecee70f774 | ||
| 
						 | 
					70b414aca2 | ||
| 
						 | 
					80cfd6991d | ||
| 
						 | 
					0ccb34bde8 | ||
| 
						 | 
					581a292797 | ||
| 
						 | 
					7a9d87f502 | ||
| 
						 | 
					4f165bf6df | ||
| 
						 | 
					6789701e23 | ||
| 
						 | 
					64dd018c1a | ||
| 
						 | 
					3bbd0e9463 | ||
| 
						 | 
					c53676e42f | ||
| 
						 | 
					84c16fb69a | ||
| 
						 | 
					1683f45e94 | ||
| 
						 | 
					d88454a638 | ||
| 
						 | 
					8ef9634492 | ||
| 
						 | 
					335ae40675 | ||
| 
						 | 
					3bbe391391 | ||
| 
						 | 
					01a5ba99d0 | ||
| 
						 | 
					4c3a559124 | ||
| 
						 | 
					e047c1eb40 | ||
| 
						 | 
					48e1e4217f | ||
| 
						 | 
					59dc6cbf90 | ||
| 
						 | 
					59e1f7b122 | ||
| 
						 | 
					ff2944086d | ||
| 
						 | 
					ba949f7fd9 | ||
| 
						 | 
					5efcf1019f | ||
| 
						 | 
					70a13406f0 | ||
| 
						 | 
					201c01fc74 | ||
| 
						 | 
					78ef9eec88 | ||
| 
						 | 
					40ab4eb62d | ||
| 
						 | 
					55cb3546df | ||
| 
						 | 
					82902fb50d | ||
| 
						 | 
					828ae537da | ||
| 
						 | 
					1208faaabb | ||
| 
						 | 
					2d81166213 | ||
| 
						 | 
					8093f7cab8 | ||
| 
						 | 
					b946b7d319 | ||
| 
						 | 
					9354a977dd | ||
| 
						 | 
					1eb4ccbcc9 | ||
| 
						 | 
					ce5feaebf7 | ||
| 
						 | 
					ac343fb1bd | ||
| 
						 | 
					7bc619385b | ||
| 
						 | 
					d86dd5f179 | ||
| 
						 | 
					8c1591fbe3 | ||
| 
						 | 
					dfd31872a9 | ||
| 
						 | 
					1eaead4f70 | ||
| 
						 | 
					5b3350b2dd | ||
| 
						 | 
					81b05b9f88 | ||
| 
						 | 
					b5436a2c47 | ||
| 
						 | 
					b08aec02f5 | ||
| 
						 | 
					e6be00a63b | ||
| 
						 | 
					d226b8f258 | ||
| 
						 | 
					f06ebbf2ae | ||
| 
						 | 
					3e522ba787 | ||
| 
						 | 
					25142f81f8 | ||
| 
						 | 
					5fd4f74701 | ||
| 
						 | 
					a0286b402a | ||
| 
						 | 
					bb41f5c4e5 | ||
| 
						 | 
					926e9ef963 | ||
| 
						 | 
					9d46291944 | ||
| 
						 | 
					cc6d90963e | ||
| 
						 | 
					4e755e4799 | ||
| 
						 | 
					1dfd6373ee | ||
| 
						 | 
					fe0785bc42 | ||
| 
						 | 
					142ef6e66c | ||
| 
						 | 
					59745942b5 | ||
| 
						 | 
					692ee53a33 | ||
| 
						 | 
					534782414f | ||
| 
						 | 
					a6bb41e802 | ||
| 
						 | 
					86efc6a252 | ||
| 
						 | 
					89207d6d7c | ||
| 
						 | 
					f6e50bef82 | ||
| 
						 | 
					81042514c8 | ||
| 
						 | 
					2df1a5a45b | ||
| 
						 | 
					72e88d6ba3 | ||
| 
						 | 
					8db3cf6048 | ||
| 
						 | 
					68949a5922 | ||
| 
						 | 
					216d82b464 | ||
| 
						 | 
					97f2d743b3 | 
							
								
								
									
										11
									
								
								.editorconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								.editorconfig
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					root = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[*]
 | 
				
			||||||
 | 
					charset = utf-8
 | 
				
			||||||
 | 
					end_of_line = lf
 | 
				
			||||||
 | 
					insert_final_newline = true
 | 
				
			||||||
 | 
					indent_style = space
 | 
				
			||||||
 | 
					indent_size = 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[*.py]
 | 
				
			||||||
 | 
					max_line_length = 119
 | 
				
			||||||
							
								
								
									
										11
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								.github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							@@ -6,17 +6,14 @@ update The Fuck and see if the bug is still there. -->
 | 
				
			|||||||
if not, just open an issue on [GitHub](https://github.com/nvbn/thefuck) with
 | 
					if not, just open an issue on [GitHub](https://github.com/nvbn/thefuck) with
 | 
				
			||||||
the following basic information: -->
 | 
					the following basic information: -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The output of `thefuck --version` (something like `The Fuck 3.1 using Python 3.5.0`):
 | 
					The output of `thefuck --version` (something like `The Fuck 3.1 using Python
 | 
				
			||||||
 | 
					3.5.0 and Bash 4.4.12(1)-release`):
 | 
				
			||||||
    FILL THIS IN
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Your shell and its version (`bash`, `zsh`, *Windows PowerShell*, etc.):
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FILL THIS IN
 | 
					    FILL THIS IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Your system (Debian 7, ArchLinux, Windows, etc.):
 | 
					Your system (Debian 7, ArchLinux, Windows, etc.):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!-- FILL THIS IN -->
 | 
					    FILL THIS IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
How to reproduce the bug:
 | 
					How to reproduce the bug:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,6 +29,6 @@ If the bug only appears with a specific application, the output of that applicat
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Anything else you think is relevant:
 | 
					Anything else you think is relevant:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!-- FILL THIS IN -->
 | 
					    FILL THIS IN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!-- It's only with enough information that we can do something to fix the problem. -->
 | 
					<!-- It's only with enough information that we can do something to fix the problem. -->
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										38
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								.travis.yml
									
									
									
									
									
								
							@@ -1,21 +1,25 @@
 | 
				
			|||||||
language: python
 | 
					language: python
 | 
				
			||||||
sudo: false
 | 
					sudo: false
 | 
				
			||||||
 | 
					os: linux
 | 
				
			||||||
 | 
					dist: xenial
 | 
				
			||||||
matrix:
 | 
					matrix:
 | 
				
			||||||
  include:
 | 
					  include:
 | 
				
			||||||
    - os: linux
 | 
					    - python: "nightly"
 | 
				
			||||||
      dist: trusty
 | 
					    - python: "3.8-dev"
 | 
				
			||||||
      python: "3.6"
 | 
					    - python: "3.8"
 | 
				
			||||||
    - os: linux
 | 
					    - python: "3.7-dev"
 | 
				
			||||||
      dist: trusty
 | 
					    - python: "3.7"
 | 
				
			||||||
      python: "3.5"
 | 
					    - python: "3.6-dev"
 | 
				
			||||||
    - os: linux
 | 
					    - python: "3.6"
 | 
				
			||||||
      dist: trusty
 | 
					    - python: "3.5"
 | 
				
			||||||
      python: "3.4"
 | 
					    - python: "2.7"
 | 
				
			||||||
    - os: linux
 | 
					 | 
				
			||||||
      dist: trusty
 | 
					 | 
				
			||||||
      python: "2.7"
 | 
					 | 
				
			||||||
    - os: osx
 | 
					    - os: osx
 | 
				
			||||||
      language: generic
 | 
					      language: generic
 | 
				
			||||||
 | 
					  allow_failures:
 | 
				
			||||||
 | 
					    - python: nightly
 | 
				
			||||||
 | 
					    - python: 3.8-dev
 | 
				
			||||||
 | 
					    - python: 3.7-dev
 | 
				
			||||||
 | 
					    - python: 3.6-dev
 | 
				
			||||||
services:
 | 
					services:
 | 
				
			||||||
  - docker
 | 
					  - docker
 | 
				
			||||||
addons:
 | 
					addons:
 | 
				
			||||||
@@ -24,7 +28,9 @@ addons:
 | 
				
			|||||||
      - python-commandnotfound
 | 
					      - python-commandnotfound
 | 
				
			||||||
      - python3-commandnotfound
 | 
					      - python3-commandnotfound
 | 
				
			||||||
before_install:
 | 
					before_install:
 | 
				
			||||||
  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew update ; fi
 | 
					  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then rm -rf /usr/local/include/c++; fi
 | 
				
			||||||
 | 
					  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew update; fi
 | 
				
			||||||
 | 
					  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew unlink python@2; fi
 | 
				
			||||||
  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew upgrade python; fi
 | 
					  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew upgrade python; fi
 | 
				
			||||||
  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then pip3 install virtualenv; fi
 | 
					  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then pip3 install virtualenv; fi
 | 
				
			||||||
  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then virtualenv venv -p python3; fi
 | 
					  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then virtualenv venv -p python3; fi
 | 
				
			||||||
@@ -39,7 +45,7 @@ script:
 | 
				
			|||||||
  - flake8
 | 
					  - flake8
 | 
				
			||||||
  - export COVERAGE_PYTHON_VERSION=python-${TRAVIS_PYTHON_VERSION:0:1}
 | 
					  - export COVERAGE_PYTHON_VERSION=python-${TRAVIS_PYTHON_VERSION:0:1}
 | 
				
			||||||
  - export RUN_TESTS="coverage run --source=thefuck,tests -m py.test -v --capture=sys tests"
 | 
					  - export RUN_TESTS="coverage run --source=thefuck,tests -m py.test -v --capture=sys tests"
 | 
				
			||||||
  - if [[ $TRAVIS_PYTHON_VERSION == 3.6 && $TRAVIS_OS_NAME != "osx" ]]; then $RUN_TESTS --enable-functional; fi
 | 
					  - if [[ $TRAVIS_PYTHON_VERSION == 3.8 && $TRAVIS_OS_NAME != "osx" ]]; then $RUN_TESTS --enable-functional; fi
 | 
				
			||||||
  - if [[ $TRAVIS_PYTHON_VERSION != 3.6 || $TRAVIS_OS_NAME == "osx" ]]; then $RUN_TESTS; fi
 | 
					  - if [[ $TRAVIS_PYTHON_VERSION != 3.8 || $TRAVIS_OS_NAME == "osx" ]]; then $RUN_TESTS; fi
 | 
				
			||||||
after_success:
 | 
					after_success:
 | 
				
			||||||
  - if [[ $TRAVIS_PYTHON_VERSION == 3.6 && $TRAVIS_OS_NAME != "osx" ]]; then coveralls; fi
 | 
					  - if [[ $TRAVIS_PYTHON_VERSION == 3.8 && $TRAVIS_OS_NAME != "osx" ]]; then coveralls; fi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,8 @@ fixes, etc.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Developing
 | 
					# Developing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Create and activate a Python 3 virtual environment.](https://docs.python.org/3/tutorial/venv.html)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Install `The Fuck` for development:
 | 
					Install `The Fuck` for development:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										74
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										74
									
								
								README.md
									
									
									
									
									
								
							@@ -99,23 +99,27 @@ Reading package lists... Done
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Installation
 | 
					## Installation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
On OS X, you can install *The Fuck* via [Homebrew][homebrew]:
 | 
					On OS X, you can install *The Fuck* via [Homebrew][homebrew] (or via [Linuxbrew][linuxbrew] on Linux):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
brew install thefuck
 | 
					brew install thefuck
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
On Ubuntu, install *The Fuck* with the following commands:
 | 
					On Ubuntu / Mint, install *The Fuck* with the following commands:
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
sudo apt update
 | 
					sudo apt update
 | 
				
			||||||
sudo apt install python3-dev python3-pip
 | 
					sudo apt install python3-dev python3-pip python3-setuptools
 | 
				
			||||||
sudo pip3 install thefuck
 | 
					sudo pip3 install thefuck
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
On FreeBSD, install *The Fuck* with the following commands:
 | 
					On FreeBSD, install *The Fuck* with the following commands:
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
sudo portsnap fetch update
 | 
					pkg install thefuck
 | 
				
			||||||
cd /usr/ports/misc/thefuck && sudo make install clean
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					On ChromeOS, install *The Fuck* using [chromebrew](https://github.com/skycocker/chromebrew) with the following command:
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					crew install thefuck
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
On other systems, install *The Fuck*  by using `pip`:
 | 
					On other systems, install *The Fuck*  by using `pip`:
 | 
				
			||||||
@@ -141,10 +145,10 @@ eval $(thefuck --alias FUCK)
 | 
				
			|||||||
Changes are only available in a new shell session. To make changes immediately
 | 
					Changes are only available in a new shell session. To make changes immediately
 | 
				
			||||||
available, run `source ~/.bashrc` (or your shell config file like `.zshrc`).
 | 
					available, run `source ~/.bashrc` (or your shell config file like `.zshrc`).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To run fixed commands without confirmation, use the `-y` option:
 | 
					To run fixed commands without confirmation, use the `--yeah` option (or just `-y` for short, or `--hard` if you're especially frustrated):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
fuck -y
 | 
					fuck --yeah
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To fix commands recursively until succeeding, use the `-r` option:
 | 
					To fix commands recursively until succeeding, use the `-r` option:
 | 
				
			||||||
@@ -170,20 +174,26 @@ following rules are enabled by default:
 | 
				
			|||||||
* `adb_unknown_command` – fixes misspelled commands like `adb logcta`;
 | 
					* `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`;
 | 
				
			||||||
 | 
					* `az_cli` – fixes misspelled commands like `az providers`;
 | 
				
			||||||
* `cargo` – runs `cargo build` instead of `cargo`;
 | 
					* `cargo` – runs `cargo build` instead of `cargo`;
 | 
				
			||||||
* `cargo_no_command` – fixes wrongs commands like `cargo buid`;
 | 
					* `cargo_no_command` – fixes wrongs commands like `cargo buid`;
 | 
				
			||||||
 | 
					* `cat_dir` – replaces `cat` with `ls` when you try to `cat` a directory;
 | 
				
			||||||
* `cd_correction` – spellchecks and correct failed cd commands;
 | 
					* `cd_correction` – spellchecks and correct failed cd commands;
 | 
				
			||||||
* `cd_mkdir` – creates directories before cd'ing into them;
 | 
					* `cd_mkdir` – creates directories before cd'ing into them;
 | 
				
			||||||
* `cd_parent` – changes `cd..` to `cd ..`;
 | 
					* `cd_parent` – changes `cd..` to `cd ..`;
 | 
				
			||||||
* `chmod_x` – add execution bit;
 | 
					* `chmod_x` – add execution bit;
 | 
				
			||||||
 | 
					* `choco_install` – append common suffixes for chocolatey packages;
 | 
				
			||||||
* `composer_not_command` – fixes composer command name;
 | 
					* `composer_not_command` – fixes composer command name;
 | 
				
			||||||
 | 
					* `cp_create_destination` – creates a new directory when you attempt to `cp` or `mv` to a non existent one
 | 
				
			||||||
* `cp_omitting_directory` – adds `-a` when you `cp` directory;
 | 
					* `cp_omitting_directory` – adds `-a` when you `cp` directory;
 | 
				
			||||||
* `cpp11` – adds missing `-std=c++11` to `g++` or `clang++`;
 | 
					* `cpp11` – adds missing `-std=c++11` to `g++` or `clang++`;
 | 
				
			||||||
* `dirty_untar` – fixes `tar x` command that untarred in the current directory;
 | 
					* `dirty_untar` – fixes `tar x` command that untarred in the current directory;
 | 
				
			||||||
* `dirty_unzip` – fixes `unzip` command that unzipped in the current directory;
 | 
					* `dirty_unzip` – fixes `unzip` command that unzipped in the current directory;
 | 
				
			||||||
* `django_south_ghost` – adds `--delete-ghost-migrations` to failed because ghosts django south migration;
 | 
					* `django_south_ghost` – adds `--delete-ghost-migrations` to failed because ghosts django south migration;
 | 
				
			||||||
* `django_south_merge` – adds `--merge` to inconsistent django south migration;
 | 
					* `django_south_merge` – adds `--merge` to inconsistent django south migration;
 | 
				
			||||||
 | 
					* `docker_login` – executes a `docker login` and repeats the previous command;
 | 
				
			||||||
* `docker_not_command` – fixes wrong docker commands like `docker tags`;
 | 
					* `docker_not_command` – fixes wrong docker commands like `docker tags`;
 | 
				
			||||||
 | 
					* `docker_image_being_used_by_container` ‐ removes the container that is using the image before removing the image;
 | 
				
			||||||
* `dry` – fixes repetitions like `git git push`;
 | 
					* `dry` – fixes repetitions like `git git push`;
 | 
				
			||||||
* `fab_command_not_found` – fix misspelled fabric commands;
 | 
					* `fab_command_not_found` – fix misspelled fabric commands;
 | 
				
			||||||
* `fix_alt_space` – replaces Alt+Space with Space character;
 | 
					* `fix_alt_space` – replaces Alt+Space with Space character;
 | 
				
			||||||
@@ -193,10 +203,12 @@ following rules are enabled by default:
 | 
				
			|||||||
* `git_add_force` – adds `--force` to `git add <pathspec>...` when paths are .gitignore'd;
 | 
					* `git_add_force` – adds `--force` to `git add <pathspec>...` when paths are .gitignore'd;
 | 
				
			||||||
* `git_bisect_usage` – fixes `git bisect strt`, `git bisect goood`, `git bisect rset`, etc. when bisecting;
 | 
					* `git_bisect_usage` – fixes `git bisect strt`, `git bisect goood`, `git bisect rset`, etc. when bisecting;
 | 
				
			||||||
* `git_branch_delete` – changes `git branch -d` to `git branch -D`;
 | 
					* `git_branch_delete` – changes `git branch -d` to `git branch -D`;
 | 
				
			||||||
 | 
					* `git_branch_delete_checked_out` – changes `git branch -d` to `git checkout master && git branch -D` when trying to delete a checked out branch;
 | 
				
			||||||
* `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_commit_amend` – offers `git commit --amend` after previous commit;
 | 
				
			||||||
 | 
					* `git_commit_reset` – offers `git reset HEAD~` 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`);
 | 
				
			||||||
@@ -218,16 +230,17 @@ following rules are enabled by default:
 | 
				
			|||||||
* `git_rm_recursive` – adds `-r` when you try to `rm` a directory;
 | 
					* `git_rm_recursive` – adds `-r` when you try to `rm` a directory;
 | 
				
			||||||
* `git_rm_staged` –  adds `-f` or `--cached` when you try to `rm` a file with staged changes
 | 
					* `git_rm_staged` –  adds `-f` or `--cached` when you try to `rm` a file with staged changes
 | 
				
			||||||
* `git_rebase_merge_dir` – offers `git rebase (--continue | --abort | --skip)` or removing the `.git/rebase-merge` dir when a rebase is in progress;
 | 
					* `git_rebase_merge_dir` – offers `git rebase (--continue | --abort | --skip)` or removing the `.git/rebase-merge` dir when a rebase is in progress;
 | 
				
			||||||
* `git_remote_seturl_add` – runs `git remote add` when `git remote set_url` on nonexistant remote;
 | 
					* `git_remote_seturl_add` – runs `git remote add` when `git remote set_url` on nonexistent remote;
 | 
				
			||||||
* `git_stash` – stashes your local modifications before rebasing or switching branch;
 | 
					* `git_stash` – stashes your local modifications before rebasing or switching branch;
 | 
				
			||||||
* `git_stash_pop` – adds your local modifications before popping stash, then resets;
 | 
					* `git_stash_pop` – adds your local modifications before popping stash, then resets;
 | 
				
			||||||
* `git_tag_force` – adds `--force` to `git tag <tagname>` when the tag already exists;
 | 
					* `git_tag_force` – adds `--force` to `git tag <tagname>` when the tag already exists;
 | 
				
			||||||
* `git_two_dashes` – adds a missing dash to commands like `git commit -amend` or `git rebase -continue`;
 | 
					* `git_two_dashes` – adds a missing dash to commands like `git commit -amend` or `git rebase -continue`;
 | 
				
			||||||
* `go_run` – appends `.go` extension when compiling/running Go programs;
 | 
					* `go_run` – appends `.go` extension when compiling/running Go programs;
 | 
				
			||||||
 | 
					* `go_unknown_command` – fixes wrong `go` commands, for example `go bulid`;
 | 
				
			||||||
* `gradle_no_task` – fixes not found or ambiguous `gradle` task;
 | 
					* `gradle_no_task` – fixes not found or ambiguous `gradle` task;
 | 
				
			||||||
* `gradle_wrapper` – replaces `gradle` with `./gradlew`;
 | 
					* `gradle_wrapper` – replaces `gradle` with `./gradlew`;
 | 
				
			||||||
* `grep_arguments_order` – fixes grep arguments order for situations like `grep -lir . test`;
 | 
					* `grep_arguments_order` – fixes `grep` arguments order for situations like `grep -lir . test`;
 | 
				
			||||||
* `grep_recursive` – adds `-r` when you trying to `grep` directory;
 | 
					* `grep_recursive` – adds `-r` when you try to `grep` directory;
 | 
				
			||||||
* `grunt_task_not_found` – fixes misspelled `grunt` commands;
 | 
					* `grunt_task_not_found` – fixes misspelled `grunt` commands;
 | 
				
			||||||
* `gulp_not_task` – fixes misspelled `gulp` tasks;
 | 
					* `gulp_not_task` – fixes misspelled `gulp` tasks;
 | 
				
			||||||
* `has_exists_script` – prepends `./` when script/binary exists;
 | 
					* `has_exists_script` – prepends `./` when script/binary exists;
 | 
				
			||||||
@@ -239,6 +252,7 @@ following rules are enabled by default:
 | 
				
			|||||||
* `java` – removes `.java` extension when running Java programs;
 | 
					* `java` – removes `.java` extension when running Java programs;
 | 
				
			||||||
* `javac` – appends missing `.java` when compiling Java files;
 | 
					* `javac` – appends missing `.java` when compiling Java files;
 | 
				
			||||||
* `lein_not_task` – fixes wrong `lein` tasks like `lein rpl`;
 | 
					* `lein_not_task` – fixes wrong `lein` tasks like `lein rpl`;
 | 
				
			||||||
 | 
					* `long_form_help` – changes `-h` to `--help` when the short form version is not supported
 | 
				
			||||||
* `ln_no_hard_link` – catches hard link creation on directories, suggest symbolic link;
 | 
					* `ln_no_hard_link` – catches hard link creation on directories, suggest symbolic link;
 | 
				
			||||||
* `ln_s_order` – fixes `ln -s` arguments order;
 | 
					* `ln_s_order` – fixes `ln -s` arguments order;
 | 
				
			||||||
* `ls_all` – adds `-A` to `ls` when output is empty;
 | 
					* `ls_all` – adds `-A` to `ls` when output is empty;
 | 
				
			||||||
@@ -247,26 +261,29 @@ following rules are enabled by default:
 | 
				
			|||||||
* `man_no_space` – fixes man commands without spaces, for example `mandiff`;
 | 
					* `man_no_space` – fixes man commands without spaces, for example `mandiff`;
 | 
				
			||||||
* `mercurial` – fixes wrong `hg` commands;
 | 
					* `mercurial` – fixes wrong `hg` commands;
 | 
				
			||||||
* `missing_space_before_subcommand` – fixes command with missing space like `npminstall`;
 | 
					* `missing_space_before_subcommand` – fixes command with missing space like `npminstall`;
 | 
				
			||||||
* `mkdir_p` – adds `-p` when you trying to create directory without parent;
 | 
					* `mkdir_p` – adds `-p` when you try to create a directory without parent;
 | 
				
			||||||
* `mvn_no_command` – adds `clean package` to `mvn`;
 | 
					* `mvn_no_command` – adds `clean package` to `mvn`;
 | 
				
			||||||
* `mvn_unknown_lifecycle_phase` – fixes misspelled lifecycle phases with `mvn`;
 | 
					* `mvn_unknown_lifecycle_phase` – fixes misspelled life cycle phases with `mvn`;
 | 
				
			||||||
* `npm_missing_script` – fixes `npm` custom script name in `npm run-script <script>`;
 | 
					* `npm_missing_script` – fixes `npm` custom script name in `npm run-script <script>`;
 | 
				
			||||||
* `npm_run_script` – adds missing `run-script` for custom `npm` scripts;
 | 
					* `npm_run_script` – adds missing `run-script` for custom `npm` scripts;
 | 
				
			||||||
* `npm_wrong_command` – fixes wrong npm commands like `npm urgrade`;
 | 
					* `npm_wrong_command` – fixes wrong npm commands like `npm urgrade`;
 | 
				
			||||||
* `no_command` – fixes wrong console commands, for example `vom/vim`;
 | 
					* `no_command` – fixes wrong console commands, for example `vom/vim`;
 | 
				
			||||||
* `no_such_file` – creates missing directories with `mv` and `cp` commands;
 | 
					* `no_such_file` – creates missing directories with `mv` and `cp` commands;
 | 
				
			||||||
* `open` – either prepends `http://` to address passed to `open` or create a new file or directory and passes it to `open`;
 | 
					* `open` – either prepends `http://` to address passed to `open` or create a new file or directory and passes it to `open`;
 | 
				
			||||||
 | 
					* `pip_install` – fixes permission issues with `pip install` commands by adding `--user` or prepending `sudo` if necessary;
 | 
				
			||||||
* `pip_unknown_command` – fixes wrong `pip` commands, for example `pip instatl/pip install`;
 | 
					* `pip_unknown_command` – fixes wrong `pip` commands, for example `pip instatl/pip install`;
 | 
				
			||||||
* `php_s` – replaces `-s` by `-S` when trying to run a local php server;
 | 
					* `php_s` – replaces `-s` by `-S` when trying to run a local php server;
 | 
				
			||||||
* `port_already_in_use` – kills process that bound port;
 | 
					* `port_already_in_use` – kills process that bound port;
 | 
				
			||||||
* `prove_recursively` – adds `-r` when called with directory;
 | 
					* `prove_recursively` – adds `-r` when called with directory;
 | 
				
			||||||
* `python_command` – prepends `python` when you trying to run not executable/without `./` python script;
 | 
					* `pyenv_no_such_command` – fixes wrong pyenv commands like `pyenv isntall` or `pyenv list`;
 | 
				
			||||||
 | 
					* `python_command` – prepends `python` when you try to run non-executable/without `./` python script;
 | 
				
			||||||
* `python_execute` – appends missing `.py` when executing Python files;
 | 
					* `python_execute` – appends missing `.py` when executing Python files;
 | 
				
			||||||
* `quotation_marks` – fixes uneven usage of `'` and `"` when containing args';
 | 
					* `quotation_marks` – fixes uneven usage of `'` and `"` when containing args';
 | 
				
			||||||
* `path_from_history` – replaces not found path with similar absolute path from history;
 | 
					* `path_from_history` – replaces not found path with similar absolute path from history;
 | 
				
			||||||
* `react_native_command_unrecognized` – fixes unrecognized `react-native` commands;
 | 
					* `react_native_command_unrecognized` – fixes unrecognized `react-native` commands;
 | 
				
			||||||
* `remove_trailing_cedilla` – remove trailling cedillas `ç`, a common typo for european keyboard layouts;
 | 
					* `remove_shell_prompt_literal` – remove leading shell prompt symbol `$`, common when copying commands from documentations;
 | 
				
			||||||
* `rm_dir` – adds `-rf` when you trying to remove directory;
 | 
					* `remove_trailing_cedilla` – remove trailing cedillas `ç`, a common typo for european keyboard layouts;
 | 
				
			||||||
 | 
					* `rm_dir` – adds `-rf` when you try to remove a directory;
 | 
				
			||||||
* `scm_correction` – corrects wrong scm like `hg log` to `git log`;
 | 
					* `scm_correction` – corrects wrong scm like `hg log` to `git log`;
 | 
				
			||||||
* `sed_unterminated_s` – adds missing '/' to `sed`'s `s` commands;
 | 
					* `sed_unterminated_s` – adds missing '/' to `sed`'s `s` commands;
 | 
				
			||||||
* `sl_ls` – changes `sl` to `ls`;
 | 
					* `sl_ls` – changes `sl` to `ls`;
 | 
				
			||||||
@@ -275,6 +292,7 @@ following rules are enabled by default:
 | 
				
			|||||||
* `sudo_command_from_user_path` – runs commands from users `$PATH` with `sudo`;
 | 
					* `sudo_command_from_user_path` – runs commands from users `$PATH` with `sudo`;
 | 
				
			||||||
* `switch_lang` – switches command from your local layout to en;
 | 
					* `switch_lang` – switches command from your local layout to en;
 | 
				
			||||||
* `systemctl` – correctly orders parameters of confusing `systemctl`;
 | 
					* `systemctl` – correctly orders parameters of confusing `systemctl`;
 | 
				
			||||||
 | 
					* `terraform_init.py` – run `terraform init` before plan or apply;
 | 
				
			||||||
* `test.py` – runs `py.test` instead of `test.py`;
 | 
					* `test.py` – runs `py.test` instead of `test.py`;
 | 
				
			||||||
* `touch` – creates missing directories before "touching";
 | 
					* `touch` – creates missing directories before "touching";
 | 
				
			||||||
* `tsuru_login` – runs `tsuru login` if not authenticated or session expired;
 | 
					* `tsuru_login` – runs `tsuru login` if not authenticated or session expired;
 | 
				
			||||||
@@ -299,13 +317,16 @@ The following rules are enabled by default on specific platforms only:
 | 
				
			|||||||
* `apt_upgrade` – helps you run `apt upgrade` after `apt list --upgradable`;
 | 
					* `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_reinstall` – turns `brew install <formula>` into `brew reinstall <formula>`;
 | 
				
			||||||
* `brew_link` – adds `--overwrite --dry-run` if linking fails;
 | 
					* `brew_link` – adds `--overwrite --dry-run` if linking fails;
 | 
				
			||||||
* `brew_uninstall` – adds `--force` to `brew uninstall` if multiple versions were installed;
 | 
					* `brew_uninstall` – adds `--force` to `brew uninstall` if multiple versions were installed;
 | 
				
			||||||
* `brew_unknown_command` – fixes wrong brew commands, for example `brew docto/brew doctor`;
 | 
					* `brew_unknown_command` – fixes wrong brew commands, for example `brew docto/brew doctor`;
 | 
				
			||||||
* `brew_update_formula` – turns `brew update <formula>` into `brew upgrade <formula>`;
 | 
					* `brew_update_formula` – turns `brew update <formula>` into `brew upgrade <formula>`;
 | 
				
			||||||
* `dnf_no_such_command` – fixes mistyped DNF commands;
 | 
					* `dnf_no_such_command` – fixes mistyped DNF commands;
 | 
				
			||||||
* `pacman` – installs app with `pacman` if it is not installed (uses `yaourt` if available);
 | 
					* `nixos_cmd_not_found` – installs apps on NixOS;
 | 
				
			||||||
* `pacman_not_found` – fixes package name with `pacman` or `yaourt`.
 | 
					* `pacman` – installs app with `pacman` if it is not installed (uses `yay` or `yaourt` if available);
 | 
				
			||||||
 | 
					* `pacman_not_found` – fixes package name with `pacman`, `yay` or `yaourt`.
 | 
				
			||||||
 | 
					* `yum_invalid_operation` – fixes invalid `yum` calls, like `yum isntall vim`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The following commands are bundled with *The Fuck*, but are not enabled by
 | 
					The following commands are bundled with *The Fuck*, but are not enabled by
 | 
				
			||||||
default:
 | 
					default:
 | 
				
			||||||
@@ -336,8 +357,8 @@ Your rule should not change `Command`.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
**Rules api changed in 3.0:** To access a rule's settings, import it with
 | 
					**Rules api changed in 3.0:** To access a rule's settings, import it with
 | 
				
			||||||
 `from thefuck.conf import settings`
 | 
					 `from thefuck.conf import settings`
 | 
				
			||||||
  
 | 
					
 | 
				
			||||||
`settings` is a special object assembled from `~/.config/thefuck/settings.py`, 
 | 
					`settings` is a special object assembled from `~/.config/thefuck/settings.py`,
 | 
				
			||||||
and values from env ([see more below](#settings)).
 | 
					and values from env ([see more below](#settings)).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A simple example rule for running a script with `sudo`:
 | 
					A simple example rule for running a script with `sudo`:
 | 
				
			||||||
@@ -371,7 +392,7 @@ requires_output = True
 | 
				
			|||||||
Several *The Fuck* parameters can be changed in the file `$XDG_CONFIG_HOME/thefuck/settings.py`
 | 
					Several *The Fuck* parameters can be changed in the file `$XDG_CONFIG_HOME/thefuck/settings.py`
 | 
				
			||||||
(`$XDG_CONFIG_HOME` defaults to `~/.config`):
 | 
					(`$XDG_CONFIG_HOME` defaults to `~/.config`):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `rules` – list of enabled rules, by default `thefuck.conf.DEFAULT_RULES`;
 | 
					* `rules` – list of enabled rules, by default `thefuck.const.DEFAULT_RULES`;
 | 
				
			||||||
* `exclude_rules` – list of disabled rules, by default `[]`;
 | 
					* `exclude_rules` – list of disabled rules, by default `[]`;
 | 
				
			||||||
* `require_confirmation` – requires confirmation before running new command, by default `True`;
 | 
					* `require_confirmation` – requires confirmation before running new command, by default `True`;
 | 
				
			||||||
* `wait_command` – max amount of time in seconds for getting previous command output;
 | 
					* `wait_command` – max amount of time in seconds for getting previous command output;
 | 
				
			||||||
@@ -381,7 +402,8 @@ Several *The Fuck* parameters can be changed in the file `$XDG_CONFIG_HOME/thefu
 | 
				
			|||||||
* `history_limit` – numeric value of how many history commands will be scanned, like `2000`;
 | 
					* `history_limit` – numeric value of how many history commands will be scanned, like `2000`;
 | 
				
			||||||
* `alter_history` – push fixed command to history, by default `True`;
 | 
					* `alter_history` – push fixed command to history, by default `True`;
 | 
				
			||||||
* `wait_slow_command` – max amount of time in seconds for getting previous command output if it in `slow_commands` list;
 | 
					* `wait_slow_command` – max amount of time in seconds for getting previous command output if it in `slow_commands` list;
 | 
				
			||||||
* `slow_commands` – list of slow commands.
 | 
					* `slow_commands` – list of slow commands;
 | 
				
			||||||
 | 
					* `num_close_matches` – maximum number of close matches to suggest, by default `3`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
An example of `settings.py`:
 | 
					An example of `settings.py`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -396,6 +418,7 @@ debug = False
 | 
				
			|||||||
history_limit = 9999
 | 
					history_limit = 9999
 | 
				
			||||||
wait_slow_command = 20
 | 
					wait_slow_command = 20
 | 
				
			||||||
slow_commands = ['react-native', 'gradle']
 | 
					slow_commands = ['react-native', 'gradle']
 | 
				
			||||||
 | 
					num_close_matches = 5
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Or via environment variables:
 | 
					Or via environment variables:
 | 
				
			||||||
@@ -411,7 +434,8 @@ rule with lower `priority` will be matched first;
 | 
				
			|||||||
* `THEFUCK_HISTORY_LIMIT` – how many history commands will be scanned, like `2000`;
 | 
					* `THEFUCK_HISTORY_LIMIT` – how many history commands will be scanned, like `2000`;
 | 
				
			||||||
* `THEFUCK_ALTER_HISTORY` – push fixed command to history `true/false`;
 | 
					* `THEFUCK_ALTER_HISTORY` – push fixed command to history `true/false`;
 | 
				
			||||||
* `THEFUCK_WAIT_SLOW_COMMAND` – max amount of time in seconds for getting previous command output if it in `slow_commands` list;
 | 
					* `THEFUCK_WAIT_SLOW_COMMAND` – max amount of time in seconds for getting previous command output if it in `slow_commands` list;
 | 
				
			||||||
* `THEFUCK_SLOW_COMMANDS` – list of slow commands, like `lein:gradle`.
 | 
					* `THEFUCK_SLOW_COMMANDS` – list of slow commands, like `lein:gradle`;
 | 
				
			||||||
 | 
					* `THEFUCK_NUM_CLOSE_MATCHES` – maximum number of close matches to suggest, like `5`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For example:
 | 
					For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -423,6 +447,7 @@ export THEFUCK_WAIT_COMMAND=10
 | 
				
			|||||||
export THEFUCK_NO_COLORS='false'
 | 
					export THEFUCK_NO_COLORS='false'
 | 
				
			||||||
export THEFUCK_PRIORITY='no_command=9999:apt_get=100'
 | 
					export THEFUCK_PRIORITY='no_command=9999:apt_get=100'
 | 
				
			||||||
export THEFUCK_HISTORY_LIMIT='2000'
 | 
					export THEFUCK_HISTORY_LIMIT='2000'
 | 
				
			||||||
 | 
					export THEFUCK_NUM_CLOSE_MATCHES='5'
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Third-party packages with rules
 | 
					## Third-party packages with rules
 | 
				
			||||||
@@ -452,7 +477,7 @@ then reading the log.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[![gif with instant mode][instant-mode-gif-link]][instant-mode-gif-link]
 | 
					[![gif with instant mode][instant-mode-gif-link]][instant-mode-gif-link]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Currently, instant mode only supports Python 3 with bash or zsh.
 | 
					Currently, instant mode only supports Python 3 with bash or zsh. zsh's autocorrect function also needs to be disabled in order for thefuck to work properly.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To enable instant mode, add `--enable-experimental-instant-mode`
 | 
					To enable instant mode, add `--enable-experimental-instant-mode`
 | 
				
			||||||
to the alias initialization in `.bashrc`, `.bash_profile` or `.zshrc`.
 | 
					to the alias initialization in `.bashrc`, `.bash_profile` or `.zshrc`.
 | 
				
			||||||
@@ -482,4 +507,5 @@ Project License can be found [here](LICENSE.md).
 | 
				
			|||||||
[license-badge]:   https://img.shields.io/badge/license-MIT-007EC7.svg
 | 
					[license-badge]:   https://img.shields.io/badge/license-MIT-007EC7.svg
 | 
				
			||||||
[examples-link]:   https://raw.githubusercontent.com/nvbn/thefuck/master/example.gif
 | 
					[examples-link]:   https://raw.githubusercontent.com/nvbn/thefuck/master/example.gif
 | 
				
			||||||
[instant-mode-gif-link]:   https://raw.githubusercontent.com/nvbn/thefuck/master/example_instant_mode.gif
 | 
					[instant-mode-gif-link]:   https://raw.githubusercontent.com/nvbn/thefuck/master/example_instant_mode.gif
 | 
				
			||||||
[homebrew]:        http://brew.sh/
 | 
					[homebrew]:        https://brew.sh/
 | 
				
			||||||
 | 
					[linuxbrew]:       https://linuxbrew.sh/
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,9 +3,9 @@ build: false
 | 
				
			|||||||
environment:
 | 
					environment:
 | 
				
			||||||
  matrix:
 | 
					  matrix:
 | 
				
			||||||
    - PYTHON: "C:/Python27"
 | 
					    - PYTHON: "C:/Python27"
 | 
				
			||||||
    - PYTHON: "C:/Python34"
 | 
					 | 
				
			||||||
    - PYTHON: "C:/Python35"
 | 
					    - PYTHON: "C:/Python35"
 | 
				
			||||||
    - PYTHON: "C:/Python36"
 | 
					    - PYTHON: "C:/Python36"
 | 
				
			||||||
 | 
					    - PYTHON: "C:/Python37"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
init:
 | 
					init:
 | 
				
			||||||
  - "ECHO %PYTHON%"
 | 
					  - "ECHO %PYTHON%"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,7 +37,7 @@ http://github.com/ninjaaron/fast-entry_points
 | 
				
			|||||||
'''
 | 
					'''
 | 
				
			||||||
from setuptools.command import easy_install
 | 
					from setuptools.command import easy_install
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
TEMPLATE = '''\
 | 
					TEMPLATE = r'''\
 | 
				
			||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
# EASY-INSTALL-ENTRY-SCRIPT: '{3}','{4}','{5}'
 | 
					# EASY-INSTALL-ENTRY-SCRIPT: '{3}','{4}','{5}'
 | 
				
			||||||
__requires__ = '{3}'
 | 
					__requires__ = '{3}'
 | 
				
			||||||
@@ -83,7 +83,7 @@ def main():
 | 
				
			|||||||
    import shutil
 | 
					    import shutil
 | 
				
			||||||
    import sys
 | 
					    import sys
 | 
				
			||||||
    dests = sys.argv[1:] or ['.']
 | 
					    dests = sys.argv[1:] or ['.']
 | 
				
			||||||
    filename = re.sub('\.pyc$', '.py', __file__)
 | 
					    filename = re.sub(r'\.pyc$', '.py', __file__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for dst in dests:
 | 
					    for dst in dests:
 | 
				
			||||||
        shutil.copy(filename, dst)
 | 
					        shutil.copy(filename, dst)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,4 +32,6 @@ call('git push --tags', shell=True)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
env = os.environ
 | 
					env = os.environ
 | 
				
			||||||
env['CONVERT_README'] = 'true'
 | 
					env['CONVERT_README'] = 'true'
 | 
				
			||||||
call('python setup.py sdist bdist_wheel upload', shell=True, env=env)
 | 
					call('rm -rf dist/*', shell=True, env=env)
 | 
				
			||||||
 | 
					call('python setup.py sdist bdist_wheel', shell=True, env=env)
 | 
				
			||||||
 | 
					call('twine upload dist/*', shell=True, env=env)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,3 @@
 | 
				
			|||||||
pip
 | 
					 | 
				
			||||||
flake8
 | 
					flake8
 | 
				
			||||||
pytest
 | 
					pytest
 | 
				
			||||||
mock
 | 
					mock
 | 
				
			||||||
@@ -9,3 +8,4 @@ pexpect
 | 
				
			|||||||
pypandoc
 | 
					pypandoc
 | 
				
			||||||
pytest-benchmark
 | 
					pytest-benchmark
 | 
				
			||||||
pytest-docker-pexpect
 | 
					pytest-docker-pexpect
 | 
				
			||||||
 | 
					twine
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								setup.py
									
									
									
									
									
								
							@@ -26,12 +26,12 @@ 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, 4):
 | 
					elif (3, 0) < version < (3, 5):
 | 
				
			||||||
    print('thefuck requires Python version 3.4 or later' +
 | 
					    print('thefuck requires Python version 3.5 or later' +
 | 
				
			||||||
          ' ({}.{} detected).'.format(*version))
 | 
					          ' ({}.{} detected).'.format(*version))
 | 
				
			||||||
    sys.exit(-1)
 | 
					    sys.exit(-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VERSION = '3.26'
 | 
					VERSION = '3.30'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install_requires = ['psutil', 'colorama', 'six', 'decorator', 'pyte']
 | 
					install_requires = ['psutil', 'colorama', 'six', 'decorator', 'pyte']
 | 
				
			||||||
extras_require = {':python_version<"3.4"': ['pathlib2'],
 | 
					extras_require = {':python_version<"3.4"': ['pathlib2'],
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								snapcraft.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								snapcraft.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					name: thefuck
 | 
				
			||||||
 | 
					version: stable
 | 
				
			||||||
 | 
					version-script: git -C parts/thefuck/build describe --abbrev=0 --tags
 | 
				
			||||||
 | 
					summary: Magnificent app which corrects your previous console command.
 | 
				
			||||||
 | 
					description: |
 | 
				
			||||||
 | 
					  The Fuck tries to match a rule for the previous command,
 | 
				
			||||||
 | 
					  creates a new command using the matched rule and runs it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					grade: stable
 | 
				
			||||||
 | 
					confinement: classic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					apps:
 | 
				
			||||||
 | 
					  thefuck:
 | 
				
			||||||
 | 
					    command: bin/thefuck
 | 
				
			||||||
 | 
					    environment:
 | 
				
			||||||
 | 
					        PYTHONIOENCODING: utf-8
 | 
				
			||||||
 | 
					  fuck:
 | 
				
			||||||
 | 
					    command: bin/fuck
 | 
				
			||||||
 | 
					    environment:
 | 
				
			||||||
 | 
					        PYTHONIOENCODING: utf-8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					parts:
 | 
				
			||||||
 | 
					  thefuck:
 | 
				
			||||||
 | 
					    source: https://github.com/nvbn/thefuck.git
 | 
				
			||||||
 | 
					    plugin: python
 | 
				
			||||||
@@ -42,7 +42,7 @@ def no_cache(monkeypatch):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@pytest.fixture(autouse=True)
 | 
					@pytest.fixture(autouse=True)
 | 
				
			||||||
def functional(request):
 | 
					def functional(request):
 | 
				
			||||||
    if request.node.get_marker('functional') \
 | 
					    if request.node.get_closest_marker('functional') \
 | 
				
			||||||
            and not request.config.getoption('enable_functional'):
 | 
					            and not request.config.getoption('enable_functional'):
 | 
				
			||||||
        pytest.skip('functional tests are disabled')
 | 
					        pytest.skip('functional tests are disabled')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,45 +0,0 @@
 | 
				
			|||||||
import pytest
 | 
					 | 
				
			||||||
import time
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dockerfile = u'''
 | 
					 | 
				
			||||||
FROM python:3
 | 
					 | 
				
			||||||
RUN adduser --disabled-password --gecos '' test
 | 
					 | 
				
			||||||
ENV SEED "{seed}"
 | 
					 | 
				
			||||||
WORKDIR /src
 | 
					 | 
				
			||||||
USER test
 | 
					 | 
				
			||||||
RUN echo 'eval $(thefuck --alias)' > /home/test/.bashrc
 | 
					 | 
				
			||||||
RUN echo > /home/test/.bash_history
 | 
					 | 
				
			||||||
RUN git config --global user.email "you@example.com"
 | 
					 | 
				
			||||||
RUN git config --global user.name "Your Name"
 | 
					 | 
				
			||||||
USER root
 | 
					 | 
				
			||||||
'''.format(seed=time.time())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def plot(proc, TIMEOUT):
 | 
					 | 
				
			||||||
    proc.sendline(u'cd /home/test/')
 | 
					 | 
				
			||||||
    proc.sendline(u'fuck')
 | 
					 | 
				
			||||||
    assert proc.expect([TIMEOUT, u'No fucks given'])
 | 
					 | 
				
			||||||
    proc.sendline(u'git init')
 | 
					 | 
				
			||||||
    proc.sendline(u'git add .')
 | 
					 | 
				
			||||||
    proc.sendline(u'git commit -a -m init')
 | 
					 | 
				
			||||||
    proc.sendline(u'git brnch')
 | 
					 | 
				
			||||||
    proc.sendline(u'fuck')
 | 
					 | 
				
			||||||
    assert proc.expect([TIMEOUT, u'git branch'])
 | 
					 | 
				
			||||||
    proc.send('\n')
 | 
					 | 
				
			||||||
    assert proc.expect([TIMEOUT, u'master'])
 | 
					 | 
				
			||||||
    proc.sendline(u'echo test')
 | 
					 | 
				
			||||||
    proc.sendline(u'echo tst')
 | 
					 | 
				
			||||||
    proc.sendline(u'fuck')
 | 
					 | 
				
			||||||
    assert proc.expect([TIMEOUT, u'echo test'])
 | 
					 | 
				
			||||||
    proc.send('\n')
 | 
					 | 
				
			||||||
    assert proc.expect([TIMEOUT, u'test'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@pytest.mark.functional
 | 
					 | 
				
			||||||
@pytest.mark.benchmark(min_rounds=10)
 | 
					 | 
				
			||||||
def test_performance(spawnu, TIMEOUT, benchmark):
 | 
					 | 
				
			||||||
    proc = spawnu(u'thefuck/python3-bash-performance',
 | 
					 | 
				
			||||||
                  dockerfile, u'bash')
 | 
					 | 
				
			||||||
    proc.sendline(u'pip install /src')
 | 
					 | 
				
			||||||
    proc.sendline(u'su test')
 | 
					 | 
				
			||||||
    assert benchmark(plot, proc, TIMEOUT) is None
 | 
					 | 
				
			||||||
							
								
								
									
										58
									
								
								tests/output_readers/test_rerun.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								tests/output_readers/test_rerun.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					# -*- encoding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from mock import Mock, patch
 | 
				
			||||||
 | 
					from psutil import AccessDenied, TimeoutExpired
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from thefuck.output_readers import rerun
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestRerun(object):
 | 
				
			||||||
 | 
					    def setup_method(self, test_method):
 | 
				
			||||||
 | 
					        self.patcher = patch('thefuck.output_readers.rerun.Process')
 | 
				
			||||||
 | 
					        process_mock = self.patcher.start()
 | 
				
			||||||
 | 
					        self.proc_mock = process_mock.return_value = Mock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def teardown_method(self, test_method):
 | 
				
			||||||
 | 
					        self.patcher.stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @patch('thefuck.output_readers.rerun._wait_output', return_value=False)
 | 
				
			||||||
 | 
					    @patch('thefuck.output_readers.rerun.Popen')
 | 
				
			||||||
 | 
					    def test_get_output(self, popen_mock, wait_output_mock):
 | 
				
			||||||
 | 
					        popen_mock.return_value.stdout.read.return_value = b'output'
 | 
				
			||||||
 | 
					        assert rerun.get_output('', '') is None
 | 
				
			||||||
 | 
					        wait_output_mock.assert_called_once()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_wait_output_is_slow(self, settings):
 | 
				
			||||||
 | 
					        assert rerun._wait_output(Mock(), True)
 | 
				
			||||||
 | 
					        self.proc_mock.wait.assert_called_once_with(settings.wait_slow_command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_wait_output_is_not_slow(self, settings):
 | 
				
			||||||
 | 
					        assert rerun._wait_output(Mock(), False)
 | 
				
			||||||
 | 
					        self.proc_mock.wait.assert_called_once_with(settings.wait_command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @patch('thefuck.output_readers.rerun._kill_process')
 | 
				
			||||||
 | 
					    def test_wait_output_timeout(self, kill_process_mock):
 | 
				
			||||||
 | 
					        self.proc_mock.wait.side_effect = TimeoutExpired(3)
 | 
				
			||||||
 | 
					        self.proc_mock.children.return_value = []
 | 
				
			||||||
 | 
					        assert not rerun._wait_output(Mock(), False)
 | 
				
			||||||
 | 
					        kill_process_mock.assert_called_once_with(self.proc_mock)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @patch('thefuck.output_readers.rerun._kill_process')
 | 
				
			||||||
 | 
					    def test_wait_output_timeout_children(self, kill_process_mock):
 | 
				
			||||||
 | 
					        self.proc_mock.wait.side_effect = TimeoutExpired(3)
 | 
				
			||||||
 | 
					        self.proc_mock.children.return_value = [Mock()] * 2
 | 
				
			||||||
 | 
					        assert not rerun._wait_output(Mock(), False)
 | 
				
			||||||
 | 
					        assert kill_process_mock.call_count == 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_kill_process(self):
 | 
				
			||||||
 | 
					        proc = Mock()
 | 
				
			||||||
 | 
					        rerun._kill_process(proc)
 | 
				
			||||||
 | 
					        proc.kill.assert_called_once_with()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @patch('thefuck.output_readers.rerun.logs')
 | 
				
			||||||
 | 
					    def test_kill_process_access_denied(self, logs_mock):
 | 
				
			||||||
 | 
					        proc = Mock()
 | 
				
			||||||
 | 
					        proc.kill.side_effect = AccessDenied()
 | 
				
			||||||
 | 
					        rerun._kill_process(proc)
 | 
				
			||||||
 | 
					        proc.kill.assert_called_once_with()
 | 
				
			||||||
 | 
					        logs_mock.debug.assert_called_once()
 | 
				
			||||||
@@ -9,7 +9,7 @@ def output():
 | 
				
			|||||||
            'If you meant to search for a literal string, run ag with -Q\n')
 | 
					            'If you meant to search for a literal string, run ag with -Q\n')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('script', ['ag \('])
 | 
					@pytest.mark.parametrize('script', ['ag \\('])
 | 
				
			||||||
def test_match(script, output):
 | 
					def test_match(script, output):
 | 
				
			||||||
    assert match(Command(script, output))
 | 
					    assert match(Command(script, output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,6 +20,6 @@ def test_not_match(script):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('script, new_cmd', [
 | 
					@pytest.mark.parametrize('script, new_cmd', [
 | 
				
			||||||
    ('ag \(', 'ag -Q \(')])
 | 
					    ('ag \\(', 'ag -Q \\(')])
 | 
				
			||||||
def test_get_new_command(script, new_cmd, output):
 | 
					def test_get_new_command(script, new_cmd, output):
 | 
				
			||||||
    assert get_new_command((Command(script, output))) == new_cmd
 | 
					    assert get_new_command((Command(script, output))) == new_cmd
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -76,6 +76,45 @@ apt_get_operations = ['update', 'upgrade', 'install', 'remove', 'autoremove',
 | 
				
			|||||||
                      'dselect-upgrade', 'clean', 'autoclean', 'check',
 | 
					                      'dselect-upgrade', 'clean', 'autoclean', 'check',
 | 
				
			||||||
                      'changelog', 'download']
 | 
					                      'changelog', 'download']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					new_apt_get_help = b'''apt 1.6.12 (amd64)
 | 
				
			||||||
 | 
					Usage: apt-get [options] command
 | 
				
			||||||
 | 
					       apt-get [options] install|remove pkg1 [pkg2 ...]
 | 
				
			||||||
 | 
					       apt-get [options] source pkg1 [pkg2 ...]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					apt-get is a command line interface for retrieval of packages
 | 
				
			||||||
 | 
					and information about them from authenticated sources and
 | 
				
			||||||
 | 
					for installation, upgrade and removal of packages together
 | 
				
			||||||
 | 
					with their dependencies.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Most used commands:
 | 
				
			||||||
 | 
					  update - Retrieve new lists of packages
 | 
				
			||||||
 | 
					  upgrade - Perform an upgrade
 | 
				
			||||||
 | 
					  install - Install new packages (pkg is libc6 not libc6.deb)
 | 
				
			||||||
 | 
					  remove - Remove packages
 | 
				
			||||||
 | 
					  purge - Remove packages and config files
 | 
				
			||||||
 | 
					  autoremove - Remove automatically all unused packages
 | 
				
			||||||
 | 
					  dist-upgrade - Distribution upgrade, see apt-get(8)
 | 
				
			||||||
 | 
					  dselect-upgrade - Follow dselect selections
 | 
				
			||||||
 | 
					  build-dep - Configure build-dependencies for source packages
 | 
				
			||||||
 | 
					  clean - Erase downloaded archive files
 | 
				
			||||||
 | 
					  autoclean - Erase old downloaded archive files
 | 
				
			||||||
 | 
					  check - Verify that there are no broken dependencies
 | 
				
			||||||
 | 
					  source - Download source archives
 | 
				
			||||||
 | 
					  download - Download the binary package into the current directory
 | 
				
			||||||
 | 
					  changelog - Download and display the changelog for the given package
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See apt-get(8) for more information about the available commands.
 | 
				
			||||||
 | 
					Configuration options and syntax is detailed in apt.conf(5).
 | 
				
			||||||
 | 
					Information about how to configure sources can be found in sources.list(5).
 | 
				
			||||||
 | 
					Package and version choices can be expressed via apt_preferences(5).
 | 
				
			||||||
 | 
					Security details are available in apt-secure(8).
 | 
				
			||||||
 | 
					                                        This APT has Super Cow Powers.
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					new_apt_get_operations = ['update', 'upgrade', 'install', 'remove', 'purge',
 | 
				
			||||||
 | 
					                          'autoremove', 'dist-upgrade', 'dselect-upgrade',
 | 
				
			||||||
 | 
					                          'build-dep', 'clean', 'autoclean', 'check',
 | 
				
			||||||
 | 
					                          'source', 'download', 'changelog']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('script, output', [
 | 
					@pytest.mark.parametrize('script, output', [
 | 
				
			||||||
    ('apt', invalid_operation('saerch')),
 | 
					    ('apt', invalid_operation('saerch')),
 | 
				
			||||||
@@ -104,7 +143,8 @@ def set_help(mocker):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('app, help_text, operations', [
 | 
					@pytest.mark.parametrize('app, help_text, operations', [
 | 
				
			||||||
    ('apt', apt_help, apt_operations),
 | 
					    ('apt', apt_help, apt_operations),
 | 
				
			||||||
    ('apt-get', apt_get_help, apt_get_operations)
 | 
					    ('apt-get', apt_get_help, apt_get_operations),
 | 
				
			||||||
 | 
					    ('apt-get', new_apt_get_help, new_apt_get_operations)
 | 
				
			||||||
])
 | 
					])
 | 
				
			||||||
def test_get_operations(set_help, app, help_text, operations):
 | 
					def test_get_operations(set_help, app, help_text, operations):
 | 
				
			||||||
    set_help(help_text)
 | 
					    set_help(help_text)
 | 
				
			||||||
@@ -116,6 +156,8 @@ def test_get_operations(set_help, app, help_text, operations):
 | 
				
			|||||||
     apt_get_help, 'apt-get install vim'),
 | 
					     apt_get_help, 'apt-get install vim'),
 | 
				
			||||||
    ('apt saerch vim', invalid_operation('saerch'),
 | 
					    ('apt saerch vim', invalid_operation('saerch'),
 | 
				
			||||||
     apt_help, 'apt search vim'),
 | 
					     apt_help, 'apt search vim'),
 | 
				
			||||||
 | 
					    ('apt uninstall vim', invalid_operation('uninstall'),
 | 
				
			||||||
 | 
					     apt_help, 'apt remove vim'),
 | 
				
			||||||
])
 | 
					])
 | 
				
			||||||
def test_get_new_command(set_help, output, script, help_text, result):
 | 
					def test_get_new_command(set_help, output, script, help_text, result):
 | 
				
			||||||
    set_help(help_text)
 | 
					    set_help(help_text)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,10 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from thefuck.rules.apt_list_upgradable import get_new_command, match
 | 
					from thefuck.rules.apt_list_upgradable import get_new_command, match
 | 
				
			||||||
from thefuck.types import Command
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
match_output = '''
 | 
					full_english_output = '''
 | 
				
			||||||
Hit:1 http://us.archive.ubuntu.com/ubuntu zesty InRelease
 | 
					Hit:1 http://us.archive.ubuntu.com/ubuntu zesty InRelease
 | 
				
			||||||
Hit:2 http://us.archive.ubuntu.com/ubuntu zesty-updates InRelease
 | 
					Hit:2 http://us.archive.ubuntu.com/ubuntu zesty-updates InRelease
 | 
				
			||||||
Get:3 http://us.archive.ubuntu.com/ubuntu zesty-backports InRelease [89.2 kB]
 | 
					Get:3 http://us.archive.ubuntu.com/ubuntu zesty-backports InRelease [89.2 kB]
 | 
				
			||||||
@@ -17,6 +19,11 @@ Reading state information... Done
 | 
				
			|||||||
8 packages can be upgraded. Run 'apt list --upgradable' to see them.
 | 
					8 packages can be upgraded. Run 'apt list --upgradable' to see them.
 | 
				
			||||||
'''
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					match_output = [
 | 
				
			||||||
 | 
					    full_english_output,
 | 
				
			||||||
 | 
					    'Führen Sie »apt list --upgradable« aus, um sie anzuzeigen.'  # German
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
no_match_output = '''
 | 
					no_match_output = '''
 | 
				
			||||||
Hit:1 http://us.archive.ubuntu.com/ubuntu zesty InRelease
 | 
					Hit:1 http://us.archive.ubuntu.com/ubuntu zesty InRelease
 | 
				
			||||||
Get:2 http://us.archive.ubuntu.com/ubuntu zesty-updates InRelease [89.2 kB]
 | 
					Get:2 http://us.archive.ubuntu.com/ubuntu zesty-updates InRelease [89.2 kB]
 | 
				
			||||||
@@ -48,8 +55,9 @@ All packages are up to date.
 | 
				
			|||||||
'''
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_match():
 | 
					@pytest.mark.parametrize('output', match_output)
 | 
				
			||||||
    assert match(Command('sudo apt update', match_output))
 | 
					def test_match(output):
 | 
				
			||||||
 | 
					    assert match(Command('sudo apt update', output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('command', [
 | 
					@pytest.mark.parametrize('command', [
 | 
				
			||||||
@@ -67,9 +75,10 @@ def test_not_match(command):
 | 
				
			|||||||
    assert not match(command)
 | 
					    assert not match(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_get_new_command():
 | 
					@pytest.mark.parametrize('output', match_output)
 | 
				
			||||||
    new_command = get_new_command(Command('sudo apt update', match_output))
 | 
					def test_get_new_command(output):
 | 
				
			||||||
 | 
					    new_command = get_new_command(Command('sudo apt update', output))
 | 
				
			||||||
    assert new_command == 'sudo apt list --upgradable'
 | 
					    assert new_command == 'sudo apt list --upgradable'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    new_command = get_new_command(Command('apt update', match_output))
 | 
					    new_command = get_new_command(Command('apt update', output))
 | 
				
			||||||
    assert new_command == 'apt list --upgradable'
 | 
					    assert new_command == 'apt list --upgradable'
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										44
									
								
								tests/rules/test_az_cli.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								tests/rules/test_az_cli.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from thefuck.rules.az_cli import match, get_new_command
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					no_suggestions = '''\
 | 
				
			||||||
 | 
					az provider: error: the following arguments are required: _subcommand
 | 
				
			||||||
 | 
					usage: az provider [-h] {list,show,register,unregister,operation} ...
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					misspelled_command = '''\
 | 
				
			||||||
 | 
					az: 'providers' is not in the 'az' command group. See 'az --help'.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The most similar choice to 'providers' is:
 | 
				
			||||||
 | 
					    provider
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					misspelled_subcommand = '''\
 | 
				
			||||||
 | 
					az provider: 'lis' is not in the 'az provider' command group. See 'az provider --help'.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The most similar choice to 'lis' is:
 | 
				
			||||||
 | 
					    list
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('command', [
 | 
				
			||||||
 | 
					    Command('az providers', misspelled_command),
 | 
				
			||||||
 | 
					    Command('az provider lis', misspelled_subcommand)])
 | 
				
			||||||
 | 
					def test_match(command):
 | 
				
			||||||
 | 
					    assert match(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_not_match():
 | 
				
			||||||
 | 
					    assert not match(Command('az provider', no_suggestions))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('command, result', [
 | 
				
			||||||
 | 
					    (Command('az providers list', misspelled_command), ['az provider list']),
 | 
				
			||||||
 | 
					    (Command('az provider lis', misspelled_subcommand), ['az provider list'])
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					def test_get_new_command(command, result):
 | 
				
			||||||
 | 
					    assert get_new_command(command) == result
 | 
				
			||||||
							
								
								
									
										28
									
								
								tests/rules/test_brew_reinstall.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								tests/rules/test_brew_reinstall.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					from thefuck.rules.brew_reinstall import get_new_command, match
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					output = ("Warning: thefuck 9.9 is already installed and up-to-date\nTo "
 | 
				
			||||||
 | 
					          "reinstall 9.9, run `brew reinstall thefuck`")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_match():
 | 
				
			||||||
 | 
					    command = Command('brew install thefuck', output)
 | 
				
			||||||
 | 
					    assert match(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('script', [
 | 
				
			||||||
 | 
					    'brew reinstall thefuck',
 | 
				
			||||||
 | 
					    'brew install foo'])
 | 
				
			||||||
 | 
					def test_not_match(script):
 | 
				
			||||||
 | 
					    assert not match(Command(script, ''))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('script, formula, ', [
 | 
				
			||||||
 | 
					    ('brew install foo', 'foo'),
 | 
				
			||||||
 | 
					    ('brew install bar zap', 'bar zap')])
 | 
				
			||||||
 | 
					def test_get_new_command(script, formula):
 | 
				
			||||||
 | 
					    command = Command(script, output)
 | 
				
			||||||
 | 
					    new_command = 'brew reinstall {}'.format(formula)
 | 
				
			||||||
 | 
					    assert get_new_command(command) == new_command
 | 
				
			||||||
							
								
								
									
										39
									
								
								tests/rules/test_cat_dir.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								tests/rules/test_cat_dir.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from thefuck.rules.cat_dir import match, get_new_command
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture
 | 
				
			||||||
 | 
					def isdir(mocker):
 | 
				
			||||||
 | 
					    return mocker.patch('thefuck.rules.cat_dir'
 | 
				
			||||||
 | 
					                        '.os.path.isdir')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('command', [
 | 
				
			||||||
 | 
					    Command('cat foo', 'cat: foo: Is a directory\n'),
 | 
				
			||||||
 | 
					    Command('cat /foo/bar/', 'cat: /foo/bar/: Is a directory\n'),
 | 
				
			||||||
 | 
					    Command('cat cat/', 'cat: cat/: Is a directory\n'),
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					def test_match(command, isdir):
 | 
				
			||||||
 | 
					    isdir.return_value = True
 | 
				
			||||||
 | 
					    assert match(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('command', [
 | 
				
			||||||
 | 
					    Command('cat foo', 'foo bar baz'),
 | 
				
			||||||
 | 
					    Command('cat foo bar', 'foo bar baz'),
 | 
				
			||||||
 | 
					    Command('notcat foo bar', 'some output'),
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					def test_not_match(command, isdir):
 | 
				
			||||||
 | 
					    isdir.return_value = False
 | 
				
			||||||
 | 
					    assert not match(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('command, new_command', [
 | 
				
			||||||
 | 
					    (Command('cat foo', 'cat: foo: Is a directory\n'), 'ls foo'),
 | 
				
			||||||
 | 
					    (Command('cat /foo/bar/', 'cat: /foo/bar/: Is a directory\n'), 'ls /foo/bar/'),
 | 
				
			||||||
 | 
					    (Command('cat cat', 'cat: cat: Is a directory\n'), 'ls cat'),
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					def test_get_new_command(command, new_command):
 | 
				
			||||||
 | 
					    isdir.return_value = True
 | 
				
			||||||
 | 
					    assert get_new_command(command) == new_command
 | 
				
			||||||
							
								
								
									
										86
									
								
								tests/rules/test_choco_install.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								tests/rules/test_choco_install.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from thefuck.rules.choco_install import match, get_new_command
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package_not_found_error = (
 | 
				
			||||||
 | 
					    'Chocolatey v0.10.15\n'
 | 
				
			||||||
 | 
					    'Installing the following packages:\n'
 | 
				
			||||||
 | 
					    'logstitcher\n'
 | 
				
			||||||
 | 
					    'By installing you accept licenses for the packages.\n'
 | 
				
			||||||
 | 
					    'logstitcher not installed. The package was not found with the source(s) listed.\n'
 | 
				
			||||||
 | 
					    ' Source(s): \'https://chocolatey.org/api/v2/\'\n'
 | 
				
			||||||
 | 
					    ' NOTE: When you specify explicit sources, it overrides default sources.\n'
 | 
				
			||||||
 | 
					    'If the package version is a prerelease and you didn\'t specify `--pre`,\n'
 | 
				
			||||||
 | 
					    ' the package may not be found.\n'
 | 
				
			||||||
 | 
					    'Please see https://chocolatey.org/docs/troubleshooting for more\n'
 | 
				
			||||||
 | 
					    ' assistance.\n'
 | 
				
			||||||
 | 
					    '\n'
 | 
				
			||||||
 | 
					    'Chocolatey installed 0/1 packages. 1 packages failed.\n'
 | 
				
			||||||
 | 
					    ' See the log for details (C:\\ProgramData\\chocolatey\\logs\\chocolatey.log).\n'
 | 
				
			||||||
 | 
					    '\n'
 | 
				
			||||||
 | 
					    'Failures\n'
 | 
				
			||||||
 | 
					    ' - logstitcher - logstitcher not installed. The package was not found with the source(s) listed.\n'
 | 
				
			||||||
 | 
					    ' Source(s): \'https://chocolatey.org/api/v2/\'\n'
 | 
				
			||||||
 | 
					    ' NOTE: When you specify explicit sources, it overrides default sources.\n'
 | 
				
			||||||
 | 
					    'If the package version is a prerelease and you didn\'t specify `--pre`,\n'
 | 
				
			||||||
 | 
					    ' the package may not be found.\n'
 | 
				
			||||||
 | 
					    'Please see https://chocolatey.org/docs/troubleshooting for more\n'
 | 
				
			||||||
 | 
					    ' assistance.\n'
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('command', [
 | 
				
			||||||
 | 
					    Command('choco install logstitcher', package_not_found_error),
 | 
				
			||||||
 | 
					    Command('cinst logstitcher', package_not_found_error),
 | 
				
			||||||
 | 
					    Command('choco install logstitcher -y', package_not_found_error),
 | 
				
			||||||
 | 
					    Command('cinst logstitcher -y', package_not_found_error),
 | 
				
			||||||
 | 
					    Command('choco install logstitcher -y -n=test', package_not_found_error),
 | 
				
			||||||
 | 
					    Command('cinst logstitcher -y -n=test', package_not_found_error),
 | 
				
			||||||
 | 
					    Command('choco install logstitcher -y -n=test /env', package_not_found_error),
 | 
				
			||||||
 | 
					    Command('cinst logstitcher -y -n=test /env', package_not_found_error),
 | 
				
			||||||
 | 
					    Command('choco install chocolatey -y', package_not_found_error),
 | 
				
			||||||
 | 
					    Command('cinst chocolatey -y', package_not_found_error)])
 | 
				
			||||||
 | 
					def test_match(command):
 | 
				
			||||||
 | 
					    assert match(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('command', [
 | 
				
			||||||
 | 
					    Command('choco /?', ''),
 | 
				
			||||||
 | 
					    Command('choco upgrade logstitcher', ''),
 | 
				
			||||||
 | 
					    Command('cup logstitcher', ''),
 | 
				
			||||||
 | 
					    Command('choco upgrade logstitcher -y', ''),
 | 
				
			||||||
 | 
					    Command('cup logstitcher -y', ''),
 | 
				
			||||||
 | 
					    Command('choco upgrade logstitcher -y -n=test', ''),
 | 
				
			||||||
 | 
					    Command('cup logstitcher -y -n=test', ''),
 | 
				
			||||||
 | 
					    Command('choco upgrade logstitcher -y -n=test /env', ''),
 | 
				
			||||||
 | 
					    Command('cup logstitcher -y -n=test /env', ''),
 | 
				
			||||||
 | 
					    Command('choco upgrade chocolatey -y', ''),
 | 
				
			||||||
 | 
					    Command('cup chocolatey -y', ''),
 | 
				
			||||||
 | 
					    Command('choco uninstall logstitcher', ''),
 | 
				
			||||||
 | 
					    Command('cuninst logstitcher', ''),
 | 
				
			||||||
 | 
					    Command('choco uninstall logstitcher -y', ''),
 | 
				
			||||||
 | 
					    Command('cuninst logstitcher -y', ''),
 | 
				
			||||||
 | 
					    Command('choco uninstall logstitcher -y -n=test', ''),
 | 
				
			||||||
 | 
					    Command('cuninst logstitcher -y -n=test', ''),
 | 
				
			||||||
 | 
					    Command('choco uninstall logstitcher -y -n=test /env', ''),
 | 
				
			||||||
 | 
					    Command('cuninst logstitcher -y -n=test /env', ''),
 | 
				
			||||||
 | 
					    Command('choco uninstall chocolatey -y', ''),
 | 
				
			||||||
 | 
					    Command('cuninst chocolatey -y', '')])
 | 
				
			||||||
 | 
					def not_test_match(command):
 | 
				
			||||||
 | 
					    assert not match(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('before, after', [
 | 
				
			||||||
 | 
					    ('choco install logstitcher', 'choco install logstitcher.install'),
 | 
				
			||||||
 | 
					    ('cinst logstitcher', 'cinst logstitcher.install'),
 | 
				
			||||||
 | 
					    ('choco install logstitcher -y', 'choco install logstitcher.install -y'),
 | 
				
			||||||
 | 
					    ('cinst logstitcher -y', 'cinst logstitcher.install -y'),
 | 
				
			||||||
 | 
					    ('choco install logstitcher -y -n=test', 'choco install logstitcher.install -y -n=test'),
 | 
				
			||||||
 | 
					    ('cinst logstitcher -y -n=test', 'cinst logstitcher.install -y -n=test'),
 | 
				
			||||||
 | 
					    ('choco install logstitcher -y -n=test /env', 'choco install logstitcher.install -y -n=test /env'),
 | 
				
			||||||
 | 
					    ('cinst logstitcher -y -n=test /env', 'cinst logstitcher.install -y -n=test /env'),
 | 
				
			||||||
 | 
					    ('choco install chocolatey -y', 'choco install chocolatey.install -y'),
 | 
				
			||||||
 | 
					    ('cinst chocolatey -y', 'cinst chocolatey.install -y'), ])
 | 
				
			||||||
 | 
					def test_get_new_command(before, after):
 | 
				
			||||||
 | 
					    assert (get_new_command(Command(before, '')) == after)
 | 
				
			||||||
							
								
								
									
										30
									
								
								tests/rules/test_cp_create_destination.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								tests/rules/test_cp_create_destination.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from thefuck.rules.cp_create_destination import match, get_new_command
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize(
 | 
				
			||||||
 | 
					    "script, output",
 | 
				
			||||||
 | 
					    [("cp", "cp: directory foo does not exist\n"), ("mv", "No such file or directory")],
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					def test_match(script, output):
 | 
				
			||||||
 | 
					    assert match(Command(script, output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize(
 | 
				
			||||||
 | 
					    "script, output", [("cp", ""), ("mv", ""), ("ls", "No such file or directory")]
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					def test_not_match(script, output):
 | 
				
			||||||
 | 
					    assert not match(Command(script, output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize(
 | 
				
			||||||
 | 
					    "script, output, new_command",
 | 
				
			||||||
 | 
					    [
 | 
				
			||||||
 | 
					        ("cp foo bar/", "cp: directory foo does not exist\n", "mkdir -p bar/ && cp foo bar/"),
 | 
				
			||||||
 | 
					        ("mv foo bar/", "No such file or directory", "mkdir -p bar/ && mv foo bar/"),
 | 
				
			||||||
 | 
					        ("cp foo bar/baz/", "cp: directory foo does not exist\n", "mkdir -p bar/baz/ && cp foo bar/baz/"),
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					def test_get_new_command(script, output, new_command):
 | 
				
			||||||
 | 
					    assert get_new_command(Command(script, output)) == new_command
 | 
				
			||||||
							
								
								
									
										27
									
								
								tests/rules/test_docker_image_being_used_by_container.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								tests/rules/test_docker_image_being_used_by_container.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					from thefuck.rules.docker_image_being_used_by_container import match, get_new_command
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_match():
 | 
				
			||||||
 | 
					    err_response = """Error response from daemon: conflict: unable to delete cd809b04b6ff (cannot be forced) - image is being used by running container e5e2591040d1"""
 | 
				
			||||||
 | 
					    assert match(Command('docker image rm -f cd809b04b6ff', err_response))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_not_match():
 | 
				
			||||||
 | 
					    err_response = 'bash: docker: command not found'
 | 
				
			||||||
 | 
					    assert not match(Command('docker image rm -f cd809b04b6ff', err_response))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_not_docker_command():
 | 
				
			||||||
 | 
					    err_response = """Error response from daemon: conflict: unable to delete cd809b04b6ff (cannot be forced) - image is being used by running container e5e2591040d1"""
 | 
				
			||||||
 | 
					    assert not match(Command('git image rm -f cd809b04b6ff', err_response))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_get_new_command():
 | 
				
			||||||
 | 
					    err_response = """
 | 
				
			||||||
 | 
					        Error response from daemon: conflict: unable to delete cd809b04b6ff (cannot be forced) - image
 | 
				
			||||||
 | 
					        is being used by running container e5e2591040d1
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					    result = get_new_command(Command('docker image rm -f cd809b04b6ff', err_response))
 | 
				
			||||||
 | 
					    expected = 'docker container rm -f e5e2591040d1 && docker image rm -f cd809b04b6ff'
 | 
				
			||||||
 | 
					    assert result == expected
 | 
				
			||||||
							
								
								
									
										37
									
								
								tests/rules/test_docker_login.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								tests/rules/test_docker_login.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					from thefuck.rules.docker_login import match, get_new_command
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_match():
 | 
				
			||||||
 | 
					    err_response1 = """
 | 
				
			||||||
 | 
					    Sending build context to Docker daemon  118.8kB
 | 
				
			||||||
 | 
					Step 1/6 : FROM foo/bar:fdb7c6d
 | 
				
			||||||
 | 
					pull access denied for foo/bar, repository does not exist or may require 'docker login'
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					    assert match(Command('docker build -t artifactory:9090/foo/bar:fdb7c6d .', err_response1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    err_response2 = """
 | 
				
			||||||
 | 
					    The push refers to repository [artifactory:9090/foo/bar]
 | 
				
			||||||
 | 
					push access denied for foo/bar, repository does not exist or may require 'docker login'
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					    assert match(Command('docker push artifactory:9090/foo/bar:fdb7c6d', err_response2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    err_response3 = """
 | 
				
			||||||
 | 
					    docker push artifactory:9090/foo/bar:fdb7c6d
 | 
				
			||||||
 | 
					The push refers to repository [artifactory:9090/foo/bar]
 | 
				
			||||||
 | 
					9c29c7ad209d: Preparing
 | 
				
			||||||
 | 
					71f3ad53dfe0: Preparing
 | 
				
			||||||
 | 
					f58ee068224c: Preparing
 | 
				
			||||||
 | 
					aeddc924d0f7: Preparing
 | 
				
			||||||
 | 
					c2040e5d6363: Preparing
 | 
				
			||||||
 | 
					4d42df4f350f: Preparing
 | 
				
			||||||
 | 
					35723dab26f9: Preparing
 | 
				
			||||||
 | 
					71f3ad53dfe0: Pushed
 | 
				
			||||||
 | 
					cb95fa0faeb1: Layer already exists
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					    assert not match(Command('docker push artifactory:9090/foo/bar:fdb7c6d', err_response3))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_get_new_command():
 | 
				
			||||||
 | 
					    assert get_new_command(Command('docker build -t artifactory:9090/foo/bar:fdb7c6d .', '')) == 'docker login && docker build -t artifactory:9090/foo/bar:fdb7c6d .'
 | 
				
			||||||
 | 
					    assert get_new_command(Command('docker push artifactory:9090/foo/bar:fdb7c6d', '')) == 'docker login && docker push artifactory:9090/foo/bar:fdb7c6d'
 | 
				
			||||||
@@ -4,6 +4,46 @@ from thefuck.types import Command
 | 
				
			|||||||
from thefuck.rules.docker_not_command import get_new_command, match
 | 
					from thefuck.rules.docker_not_command import get_new_command, match
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_DOCKER_SWARM_OUTPUT = '''
 | 
				
			||||||
 | 
					Usage:	docker swarm COMMAND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Manage Swarm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Commands:
 | 
				
			||||||
 | 
					  ca          Display and rotate the root CA
 | 
				
			||||||
 | 
					  init        Initialize a swarm
 | 
				
			||||||
 | 
					  join        Join a swarm as a node and/or manager
 | 
				
			||||||
 | 
					  join-token  Manage join tokens
 | 
				
			||||||
 | 
					  leave       Leave the swarm
 | 
				
			||||||
 | 
					  unlock      Unlock swarm
 | 
				
			||||||
 | 
					  unlock-key  Manage the unlock key
 | 
				
			||||||
 | 
					  update      Update the swarm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Run 'docker swarm COMMAND --help' for more information on a command.
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					_DOCKER_IMAGE_OUTPUT = '''
 | 
				
			||||||
 | 
					Usage:	docker image COMMAND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Manage images
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Commands:
 | 
				
			||||||
 | 
					  build       Build an image from a Dockerfile
 | 
				
			||||||
 | 
					  history     Show the history of an image
 | 
				
			||||||
 | 
					  import      Import the contents from a tarball to create a filesystem image
 | 
				
			||||||
 | 
					  inspect     Display detailed information on one or more images
 | 
				
			||||||
 | 
					  load        Load an image from a tar archive or STDIN
 | 
				
			||||||
 | 
					  ls          List images
 | 
				
			||||||
 | 
					  prune       Remove unused images
 | 
				
			||||||
 | 
					  pull        Pull an image or a repository from a registry
 | 
				
			||||||
 | 
					  push        Push an image or a repository to a registry
 | 
				
			||||||
 | 
					  rm          Remove one or more images
 | 
				
			||||||
 | 
					  save        Save one or more images to a tar archive (streamed to STDOUT by default)
 | 
				
			||||||
 | 
					  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Run 'docker image COMMAND --help' for more information on a command.
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture
 | 
					@pytest.fixture
 | 
				
			||||||
def docker_help(mocker):
 | 
					def docker_help(mocker):
 | 
				
			||||||
    help = b'''Usage: docker [OPTIONS] COMMAND [arg...]
 | 
					    help = b'''Usage: docker [OPTIONS] COMMAND [arg...]
 | 
				
			||||||
@@ -104,6 +144,94 @@ Run 'docker COMMAND --help' for more information on a command.
 | 
				
			|||||||
    return mock
 | 
					    return mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture
 | 
				
			||||||
 | 
					def docker_help_new(mocker):
 | 
				
			||||||
 | 
					    helptext_new = b'''
 | 
				
			||||||
 | 
					Usage:	docker [OPTIONS] COMMAND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A self-sufficient runtime for containers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Options:
 | 
				
			||||||
 | 
					      --config string      Location of client config files (default "/Users/ik1ne/.docker")
 | 
				
			||||||
 | 
					  -c, --context string     Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var
 | 
				
			||||||
 | 
					                           and default context set with "docker context use")
 | 
				
			||||||
 | 
					  -D, --debug              Enable debug mode
 | 
				
			||||||
 | 
					  -H, --host list          Daemon socket(s) to connect to
 | 
				
			||||||
 | 
					  -l, --log-level string   Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
 | 
				
			||||||
 | 
					      --tls                Use TLS; implied by --tlsverify
 | 
				
			||||||
 | 
					      --tlscacert string   Trust certs signed only by this CA (default "/Users/ik1ne/.docker/ca.pem")
 | 
				
			||||||
 | 
					      --tlscert string     Path to TLS certificate file (default "/Users/ik1ne/.docker/cert.pem")
 | 
				
			||||||
 | 
					      --tlskey string      Path to TLS key file (default "/Users/ik1ne/.docker/key.pem")
 | 
				
			||||||
 | 
					      --tlsverify          Use TLS and verify the remote
 | 
				
			||||||
 | 
					  -v, --version            Print version information and quit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Management Commands:
 | 
				
			||||||
 | 
					  builder     Manage builds
 | 
				
			||||||
 | 
					  config      Manage Docker configs
 | 
				
			||||||
 | 
					  container   Manage containers
 | 
				
			||||||
 | 
					  context     Manage contexts
 | 
				
			||||||
 | 
					  image       Manage images
 | 
				
			||||||
 | 
					  network     Manage networks
 | 
				
			||||||
 | 
					  node        Manage Swarm nodes
 | 
				
			||||||
 | 
					  plugin      Manage plugins
 | 
				
			||||||
 | 
					  secret      Manage Docker secrets
 | 
				
			||||||
 | 
					  service     Manage services
 | 
				
			||||||
 | 
					  stack       Manage Docker stacks
 | 
				
			||||||
 | 
					  swarm       Manage Swarm
 | 
				
			||||||
 | 
					  system      Manage Docker
 | 
				
			||||||
 | 
					  trust       Manage trust on Docker images
 | 
				
			||||||
 | 
					  volume      Manage volumes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Commands:
 | 
				
			||||||
 | 
					  attach      Attach local standard input, output, and error streams to a running container
 | 
				
			||||||
 | 
					  build       Build an image from a Dockerfile
 | 
				
			||||||
 | 
					  commit      Create a new image from a container's changes
 | 
				
			||||||
 | 
					  cp          Copy files/folders between a container and the local filesystem
 | 
				
			||||||
 | 
					  create      Create a new container
 | 
				
			||||||
 | 
					  diff        Inspect changes to files or directories on a container's filesystem
 | 
				
			||||||
 | 
					  events      Get real time events from the server
 | 
				
			||||||
 | 
					  exec        Run a command in a running container
 | 
				
			||||||
 | 
					  export      Export a container's filesystem as a tar archive
 | 
				
			||||||
 | 
					  history     Show the history of an image
 | 
				
			||||||
 | 
					  images      List images
 | 
				
			||||||
 | 
					  import      Import the contents from a tarball to create a filesystem image
 | 
				
			||||||
 | 
					  info        Display system-wide information
 | 
				
			||||||
 | 
					  inspect     Return low-level information on Docker objects
 | 
				
			||||||
 | 
					  kill        Kill one or more running containers
 | 
				
			||||||
 | 
					  load        Load an image from a tar archive or STDIN
 | 
				
			||||||
 | 
					  login       Log in to a Docker registry
 | 
				
			||||||
 | 
					  logout      Log out from a Docker registry
 | 
				
			||||||
 | 
					  logs        Fetch the logs of a container
 | 
				
			||||||
 | 
					  pause       Pause all processes within one or more containers
 | 
				
			||||||
 | 
					  port        List port mappings or a specific mapping for the container
 | 
				
			||||||
 | 
					  ps          List containers
 | 
				
			||||||
 | 
					  pull        Pull an image or a repository from a registry
 | 
				
			||||||
 | 
					  push        Push an image or a repository to a registry
 | 
				
			||||||
 | 
					  rename      Rename a container
 | 
				
			||||||
 | 
					  restart     Restart one or more containers
 | 
				
			||||||
 | 
					  rm          Remove one or more containers
 | 
				
			||||||
 | 
					  rmi         Remove one or more images
 | 
				
			||||||
 | 
					  run         Run a command in a new container
 | 
				
			||||||
 | 
					  save        Save one or more images to a tar archive (streamed to STDOUT by default)
 | 
				
			||||||
 | 
					  search      Search the Docker Hub for images
 | 
				
			||||||
 | 
					  start       Start one or more stopped containers
 | 
				
			||||||
 | 
					  stats       Display a live stream of container(s) resource usage statistics
 | 
				
			||||||
 | 
					  stop        Stop one or more running containers
 | 
				
			||||||
 | 
					  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
 | 
				
			||||||
 | 
					  top         Display the running processes of a container
 | 
				
			||||||
 | 
					  unpause     Unpause all processes within one or more containers
 | 
				
			||||||
 | 
					  update      Update configuration of one or more containers
 | 
				
			||||||
 | 
					  version     Show the Docker version information
 | 
				
			||||||
 | 
					  wait        Block until one or more containers stop, then print their exit codes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Run 'docker COMMAND --help' for more information on a command.
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					    mock = mocker.patch('subprocess.Popen')
 | 
				
			||||||
 | 
					    mock.return_value.stdout = BytesIO(b'')
 | 
				
			||||||
 | 
					    mock.return_value.stderr = BytesIO(helptext_new)
 | 
				
			||||||
 | 
					    return mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def output(cmd):
 | 
					def output(cmd):
 | 
				
			||||||
    return "docker: '{}' is not a docker command.\n" \
 | 
					    return "docker: '{}' is not a docker command.\n" \
 | 
				
			||||||
           "See 'docker --help'.".format(cmd)
 | 
					           "See 'docker --help'.".format(cmd)
 | 
				
			||||||
@@ -113,6 +241,24 @@ def test_match():
 | 
				
			|||||||
    assert match(Command('docker pes', output('pes')))
 | 
					    assert match(Command('docker pes', output('pes')))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# tests docker (management command)
 | 
				
			||||||
 | 
					@pytest.mark.usefixtures('no_memoize')
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('script, output', [
 | 
				
			||||||
 | 
					    ('docker swarn', output('swarn')),
 | 
				
			||||||
 | 
					    ('docker imge', output('imge'))])
 | 
				
			||||||
 | 
					def test_match_management_cmd(script, output):
 | 
				
			||||||
 | 
					    assert match(Command(script, output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# tests docker (management cmd) (management subcmd)
 | 
				
			||||||
 | 
					@pytest.mark.usefixtures('no_memoize')
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('script, output', [
 | 
				
			||||||
 | 
					    ('docker swarm int', _DOCKER_SWARM_OUTPUT),
 | 
				
			||||||
 | 
					    ('docker image la', _DOCKER_IMAGE_OUTPUT)])
 | 
				
			||||||
 | 
					def test_match_management_subcmd(script, output):
 | 
				
			||||||
 | 
					    assert match(Command(script, output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('script, output', [
 | 
					@pytest.mark.parametrize('script, output', [
 | 
				
			||||||
    ('docker ps', ''),
 | 
					    ('docker ps', ''),
 | 
				
			||||||
    ('cat pes', output('pes'))])
 | 
					    ('cat pes', output('pes'))])
 | 
				
			||||||
@@ -120,10 +266,28 @@ def test_not_match(script, output):
 | 
				
			|||||||
    assert not match(Command(script, output))
 | 
					    assert not match(Command(script, output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.usefixtures('docker_help')
 | 
					@pytest.mark.usefixtures('no_memoize', 'docker_help')
 | 
				
			||||||
@pytest.mark.parametrize('wrong, fixed', [
 | 
					@pytest.mark.parametrize('wrong, fixed', [
 | 
				
			||||||
    ('pes', ['ps', 'push', 'pause']),
 | 
					    ('pes', ['ps', 'push', 'pause']),
 | 
				
			||||||
    ('tags', ['tag', 'stats', 'images'])])
 | 
					    ('tags', ['tag', 'stats', 'images'])])
 | 
				
			||||||
def test_get_new_command(wrong, fixed):
 | 
					def test_get_new_command(wrong, fixed):
 | 
				
			||||||
    command = Command('docker {}'.format(wrong), output(wrong))
 | 
					    command = Command('docker {}'.format(wrong), output(wrong))
 | 
				
			||||||
    assert get_new_command(command) == ['docker {}'.format(x) for x in fixed]
 | 
					    assert get_new_command(command) == ['docker {}'.format(x) for x in fixed]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.usefixtures('no_memoize', 'docker_help_new')
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('wrong, fixed', [
 | 
				
			||||||
 | 
					    ('swarn', ['swarm', 'start', 'search']),
 | 
				
			||||||
 | 
					    ('inage', ['image', 'images', 'rename'])])
 | 
				
			||||||
 | 
					def test_get_new_management_command(wrong, fixed):
 | 
				
			||||||
 | 
					    command = Command('docker {}'.format(wrong), output(wrong))
 | 
				
			||||||
 | 
					    assert get_new_command(command) == ['docker {}'.format(x) for x in fixed]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.usefixtures('no_memoize', 'docker_help_new')
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('wrong, fixed, output', [
 | 
				
			||||||
 | 
					    ('swarm int', ['swarm init', 'swarm join', 'swarm join-token'], _DOCKER_SWARM_OUTPUT),
 | 
				
			||||||
 | 
					    ('image la', ['image load', 'image ls', 'image tag'], _DOCKER_IMAGE_OUTPUT)])
 | 
				
			||||||
 | 
					def test_get_new_management_command_subcommand(wrong, fixed, output):
 | 
				
			||||||
 | 
					    command = Command('docker {}'.format(wrong), output)
 | 
				
			||||||
 | 
					    assert get_new_command(command) == ['docker {}'.format(x) for x in fixed]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										29
									
								
								tests/rules/test_git_branch_delete_checked_out.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								tests/rules/test_git_branch_delete_checked_out.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from thefuck.rules.git_branch_delete_checked_out import match, get_new_command
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture
 | 
				
			||||||
 | 
					def output():
 | 
				
			||||||
 | 
					    return "error: Cannot delete branch 'foo' checked out at '/bar/foo'"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize("script", ["git branch -d foo", "git branch -D foo"])
 | 
				
			||||||
 | 
					def test_match(script, output):
 | 
				
			||||||
 | 
					    assert match(Command(script, output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize("script", ["git branch -d foo", "git branch -D foo"])
 | 
				
			||||||
 | 
					def test_not_match(script):
 | 
				
			||||||
 | 
					    assert not match(Command(script, "Deleted branch foo (was a1b2c3d)."))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize(
 | 
				
			||||||
 | 
					    "script, new_command",
 | 
				
			||||||
 | 
					    [
 | 
				
			||||||
 | 
					        ("git branch -d foo", "git checkout master && git branch -D foo"),
 | 
				
			||||||
 | 
					        ("git branch -D foo", "git checkout master && git branch -D foo"),
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					def test_get_new_command(script, new_command, output):
 | 
				
			||||||
 | 
					    assert get_new_command(Command(script, output)) == new_command
 | 
				
			||||||
@@ -4,7 +4,6 @@ from thefuck.rules.git_checkout import match, get_branches, get_new_command
 | 
				
			|||||||
from thefuck.types import Command
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture
 | 
					 | 
				
			||||||
def did_not_match(target, did_you_forget=False):
 | 
					def did_not_match(target, did_you_forget=False):
 | 
				
			||||||
    error = ("error: pathspec '{}' did not match any "
 | 
					    error = ("error: pathspec '{}' did not match any "
 | 
				
			||||||
             "file(s) known to git.".format(target))
 | 
					             "file(s) known to git.".format(target))
 | 
				
			||||||
@@ -40,6 +39,11 @@ def test_not_match(command):
 | 
				
			|||||||
    (b'', []),
 | 
					    (b'', []),
 | 
				
			||||||
    (b'* master', ['master']),
 | 
					    (b'* master', ['master']),
 | 
				
			||||||
    (b'  remotes/origin/master', ['master']),
 | 
					    (b'  remotes/origin/master', ['master']),
 | 
				
			||||||
 | 
					    (b'  remotes/origin/test/1', ['test/1']),
 | 
				
			||||||
 | 
					    (b'  remotes/origin/test/1/2/3', ['test/1/2/3']),
 | 
				
			||||||
 | 
					    (b'  test/1', ['test/1']),
 | 
				
			||||||
 | 
					    (b'  test/1/2/3', ['test/1/2/3']),
 | 
				
			||||||
 | 
					    (b'  remotes/origin/HEAD -> origin/master', []),
 | 
				
			||||||
    (b'  just-another-branch', ['just-another-branch']),
 | 
					    (b'  just-another-branch', ['just-another-branch']),
 | 
				
			||||||
    (b'* master\n  just-another-branch', ['master', 'just-another-branch']),
 | 
					    (b'* master\n  just-another-branch', ['master', 'just-another-branch']),
 | 
				
			||||||
    (b'* master\n  remotes/origin/master\n  just-another-branch',
 | 
					    (b'* master\n  remotes/origin/master\n  just-another-branch',
 | 
				
			||||||
@@ -52,18 +56,18 @@ 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 checkout -b 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']),
 | 
				
			||||||
    (b'  test-random-branch-123',
 | 
					    (b'  test-random-branch-123',
 | 
				
			||||||
     Command('git checkout tst-rdm-brnch-123',
 | 
					     Command('git checkout tst-rdm-brnch-123',
 | 
				
			||||||
             did_not_match('tst-rdm-brnch-123')),
 | 
					             did_not_match('tst-rdm-brnch-123')),
 | 
				
			||||||
     'git checkout test-random-branch-123'),
 | 
					     ['git checkout test-random-branch-123', 'git checkout -b tst-rdm-brnch-123']),
 | 
				
			||||||
    (b'  test-random-branch-123',
 | 
					    (b'  test-random-branch-123',
 | 
				
			||||||
     Command('git commit tst-rdm-brnch-123',
 | 
					     Command('git commit tst-rdm-brnch-123',
 | 
				
			||||||
             did_not_match('tst-rdm-brnch-123')),
 | 
					             did_not_match('tst-rdm-brnch-123')),
 | 
				
			||||||
     'git commit test-random-branch-123')])
 | 
					     ['git commit test-random-branch-123'])])
 | 
				
			||||||
def test_get_new_command(branches, command, new_command, git_branch):
 | 
					def test_get_new_command(branches, command, new_command, git_branch):
 | 
				
			||||||
    git_branch(branches)
 | 
					    git_branch(branches)
 | 
				
			||||||
    assert get_new_command(command) == new_command
 | 
					    assert get_new_command(command) == new_command
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								tests/rules/test_git_commit_reset.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/rules/test_git_commit_reset.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from thefuck.rules.git_commit_reset 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 reset HEAD~'
 | 
				
			||||||
@@ -3,24 +3,22 @@ from thefuck.rules.git_merge import match, get_new_command
 | 
				
			|||||||
from thefuck.types import Command
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture
 | 
					output = 'merge: local - not something we can merge\n\n' \
 | 
				
			||||||
def output():
 | 
					         'Did you mean this?\n\tremote/local'
 | 
				
			||||||
    return 'merge: local - not something we can merge\n\n' \
 | 
					 | 
				
			||||||
        'Did you mean this?\n\tremote/local'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_match(output):
 | 
					def test_match():
 | 
				
			||||||
    assert match(Command('git merge test', output))
 | 
					    assert match(Command('git merge test', output))
 | 
				
			||||||
    assert not match(Command('git merge master', ''))
 | 
					    assert not match(Command('git merge master', ''))
 | 
				
			||||||
    assert not match(Command('ls', output))
 | 
					    assert not match(Command('ls', output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('command, new_command', [
 | 
					@pytest.mark.parametrize('command, new_command', [
 | 
				
			||||||
    (Command('git merge local', output()),
 | 
					    (Command('git merge local', output),
 | 
				
			||||||
     'git merge remote/local'),
 | 
					     'git merge remote/local'),
 | 
				
			||||||
    (Command('git merge -m "test" local', output()),
 | 
					    (Command('git merge -m "test" local', output),
 | 
				
			||||||
     'git merge -m "test" remote/local'),
 | 
					     'git merge -m "test" remote/local'),
 | 
				
			||||||
    (Command('git merge -m "test local" local', output()),
 | 
					    (Command('git merge -m "test local" local', output),
 | 
				
			||||||
     'git merge -m "test local" remote/local')])
 | 
					     'git merge -m "test local" remote/local')])
 | 
				
			||||||
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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,23 +3,21 @@ from thefuck.rules.git_merge_unrelated import match, get_new_command
 | 
				
			|||||||
from thefuck.types import Command
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture
 | 
					output = 'fatal: refusing to merge unrelated histories'
 | 
				
			||||||
def output():
 | 
					 | 
				
			||||||
    return 'fatal: refusing to merge unrelated histories'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_match(output):
 | 
					def test_match():
 | 
				
			||||||
    assert match(Command('git merge test', output))
 | 
					    assert match(Command('git merge test', output))
 | 
				
			||||||
    assert not match(Command('git merge master', ''))
 | 
					    assert not match(Command('git merge master', ''))
 | 
				
			||||||
    assert not match(Command('ls', output))
 | 
					    assert not match(Command('ls', output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('command, new_command', [
 | 
					@pytest.mark.parametrize('command, new_command', [
 | 
				
			||||||
    (Command('git merge local', output()),
 | 
					    (Command('git merge local', output),
 | 
				
			||||||
     'git merge local --allow-unrelated-histories'),
 | 
					     'git merge local --allow-unrelated-histories'),
 | 
				
			||||||
    (Command('git merge -m "test" local', output()),
 | 
					    (Command('git merge -m "test" local', output),
 | 
				
			||||||
     'git merge -m "test" local --allow-unrelated-histories'),
 | 
					     'git merge -m "test" local --allow-unrelated-histories'),
 | 
				
			||||||
    (Command('git merge -m "test local" local', output()),
 | 
					    (Command('git merge -m "test local" local', output),
 | 
				
			||||||
     'git merge -m "test local" local --allow-unrelated-histories')])
 | 
					     'git merge -m "test local" local --allow-unrelated-histories')])
 | 
				
			||||||
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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,6 +66,10 @@ def test_not_match(output, script, branch_name):
 | 
				
			|||||||
    ('git -c test=test push --quiet origin', 'master',
 | 
					    ('git -c test=test push --quiet origin', 'master',
 | 
				
			||||||
     'git -c test=test push --set-upstream origin master --quiet'),
 | 
					     'git -c test=test push --set-upstream origin master --quiet'),
 | 
				
			||||||
    ('git push', "test's",
 | 
					    ('git push', "test's",
 | 
				
			||||||
     "git push --set-upstream origin test\\'s")])
 | 
					     "git push --set-upstream origin test\\'s"),
 | 
				
			||||||
 | 
					    ('git push --force', 'master',
 | 
				
			||||||
 | 
					     'git push --set-upstream origin master --force'),
 | 
				
			||||||
 | 
					    ('git push --force-with-lease', 'master',
 | 
				
			||||||
 | 
					     'git push --set-upstream origin master --force-with-lease')])
 | 
				
			||||||
def test_get_new_command(output, script, branch_name, new_command):
 | 
					def test_get_new_command(output, script, branch_name, new_command):
 | 
				
			||||||
    assert get_new_command(Command(script, output)) == new_command
 | 
					    assert get_new_command(Command(script, output)) == new_command
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								tests/rules/test_go_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								tests/rules/test_go_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from thefuck.rules.go_unknown_command import match, get_new_command
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture
 | 
				
			||||||
 | 
					def build_misspelled_output():
 | 
				
			||||||
 | 
					    return '''go bulid: unknown command
 | 
				
			||||||
 | 
					Run 'go help' for usage.'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_match(build_misspelled_output):
 | 
				
			||||||
 | 
					    assert match(Command('go bulid', build_misspelled_output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_not_match():
 | 
				
			||||||
 | 
					    assert not match(Command('go run', 'go run: no go files listed'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_get_new_command(build_misspelled_output):
 | 
				
			||||||
 | 
					    assert get_new_command(Command('go bulid', build_misspelled_output)) == 'go build'
 | 
				
			||||||
							
								
								
									
										22
									
								
								tests/rules/test_long_form_help.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/rules/test_long_form_help.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from thefuck.rules.long_form_help import match, get_new_command
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('output', [
 | 
				
			||||||
 | 
					    'Try \'grep --help\' for more information.'])
 | 
				
			||||||
 | 
					def test_match(output):
 | 
				
			||||||
 | 
					    assert match(Command('grep -h', output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_not_match():
 | 
				
			||||||
 | 
					    assert not match(Command('', ''))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('before, after', [
 | 
				
			||||||
 | 
					    ('grep -h', 'grep --help'),
 | 
				
			||||||
 | 
					    ('tar -h', 'tar --help'),
 | 
				
			||||||
 | 
					    ('docker run -h', 'docker run --help'),
 | 
				
			||||||
 | 
					    ('cut -h', 'cut --help')])
 | 
				
			||||||
 | 
					def test_get_new_command(before, after):
 | 
				
			||||||
 | 
					    assert get_new_command(Command(before, '')) == after
 | 
				
			||||||
							
								
								
									
										25
									
								
								tests/rules/test_nixos_cmd_not_found.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/rules/test_nixos_cmd_not_found.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from thefuck.rules.nixos_cmd_not_found import match, get_new_command
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('command', [
 | 
				
			||||||
 | 
					    Command('vim', 'nix-env -iA nixos.vim')])
 | 
				
			||||||
 | 
					def test_match(mocker, command):
 | 
				
			||||||
 | 
					    mocker.patch('thefuck.rules.nixos_cmd_not_found', return_value=None)
 | 
				
			||||||
 | 
					    assert match(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('command', [
 | 
				
			||||||
 | 
					    Command('vim', ''),
 | 
				
			||||||
 | 
					    Command('', '')])
 | 
				
			||||||
 | 
					def test_not_match(mocker, command):
 | 
				
			||||||
 | 
					    mocker.patch('thefuck.rules.nixos_cmd_not_found', return_value=None)
 | 
				
			||||||
 | 
					    assert not match(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('command, new_command', [
 | 
				
			||||||
 | 
					    (Command('vim', 'nix-env -iA nixos.vim'), 'nix-env -iA nixos.vim && vim'),
 | 
				
			||||||
 | 
					    (Command('pacman', 'nix-env -iA nixos.pacman'), 'nix-env -iA nixos.pacman && pacman')])
 | 
				
			||||||
 | 
					def test_get_new_command(mocker, command, new_command):
 | 
				
			||||||
 | 
					    assert get_new_command(command) == new_command
 | 
				
			||||||
@@ -6,7 +6,7 @@ from thefuck.types import Command
 | 
				
			|||||||
@pytest.fixture(autouse=True)
 | 
					@pytest.fixture(autouse=True)
 | 
				
			||||||
def get_all_executables(mocker):
 | 
					def get_all_executables(mocker):
 | 
				
			||||||
    mocker.patch('thefuck.rules.no_command.get_all_executables',
 | 
					    mocker.patch('thefuck.rules.no_command.get_all_executables',
 | 
				
			||||||
                 return_value=['vim', 'fsck', 'git', 'go'])
 | 
					                 return_value=['vim', 'fsck', 'git', 'go', 'python'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture(autouse=True)
 | 
					@pytest.fixture(autouse=True)
 | 
				
			||||||
@@ -20,6 +20,7 @@ def history_without_current(mocker):
 | 
				
			|||||||
@pytest.mark.parametrize('script, output', [
 | 
					@pytest.mark.parametrize('script, output', [
 | 
				
			||||||
    ('vom file.py', 'vom: not found'),
 | 
					    ('vom file.py', 'vom: not found'),
 | 
				
			||||||
    ('fucck', 'fucck: not found'),
 | 
					    ('fucck', 'fucck: not found'),
 | 
				
			||||||
 | 
					    ('puthon', "'puthon' is not recognized as an internal or external command"),
 | 
				
			||||||
    ('got commit', 'got: command not found')])
 | 
					    ('got commit', 'got: command not found')])
 | 
				
			||||||
def test_match(mocker, script, output):
 | 
					def test_match(mocker, script, output):
 | 
				
			||||||
    mocker.patch('thefuck.rules.no_command.which', return_value=None)
 | 
					    mocker.patch('thefuck.rules.no_command.which', return_value=None)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ extra/llvm35 3.5.2-13/usr/bin/llc'''
 | 
				
			|||||||
@pytest.mark.skipif(not getattr(pacman_not_found, 'enabled_by_default', True),
 | 
					@pytest.mark.skipif(not getattr(pacman_not_found, 'enabled_by_default', True),
 | 
				
			||||||
                    reason='Skip if pacman is not available')
 | 
					                    reason='Skip if pacman is not available')
 | 
				
			||||||
@pytest.mark.parametrize('command', [
 | 
					@pytest.mark.parametrize('command', [
 | 
				
			||||||
 | 
					    Command('yay -S llc', 'error: target not found: llc'),
 | 
				
			||||||
    Command('yaourt -S llc', 'error: target not found: llc'),
 | 
					    Command('yaourt -S llc', 'error: target not found: llc'),
 | 
				
			||||||
    Command('pacman llc', 'error: target not found: llc'),
 | 
					    Command('pacman llc', 'error: target not found: llc'),
 | 
				
			||||||
    Command('sudo pacman llc', 'error: target not found: llc')])
 | 
					    Command('sudo pacman llc', 'error: target not found: llc')])
 | 
				
			||||||
@@ -19,6 +20,7 @@ def test_match(command):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('command', [
 | 
					@pytest.mark.parametrize('command', [
 | 
				
			||||||
 | 
					    Command('yay -S llc', 'error: target not found: llc'),
 | 
				
			||||||
    Command('yaourt -S llc', 'error: target not found: llc'),
 | 
					    Command('yaourt -S llc', 'error: target not found: llc'),
 | 
				
			||||||
    Command('pacman llc', 'error: target not found: llc'),
 | 
					    Command('pacman llc', 'error: target not found: llc'),
 | 
				
			||||||
    Command('sudo pacman llc', 'error: target not found: llc')])
 | 
					    Command('sudo pacman llc', 'error: target not found: llc')])
 | 
				
			||||||
@@ -31,6 +33,7 @@ def test_match_mocked(subp_mock, command):
 | 
				
			|||||||
@pytest.mark.skipif(not getattr(pacman_not_found, 'enabled_by_default', True),
 | 
					@pytest.mark.skipif(not getattr(pacman_not_found, 'enabled_by_default', True),
 | 
				
			||||||
                    reason='Skip if pacman is not available')
 | 
					                    reason='Skip if pacman is not available')
 | 
				
			||||||
@pytest.mark.parametrize('command, fixed', [
 | 
					@pytest.mark.parametrize('command, fixed', [
 | 
				
			||||||
 | 
					    (Command('yay -S llc', 'error: target not found: llc'), ['yay -S extra/llvm', 'yay -S extra/llvm35']),
 | 
				
			||||||
    (Command('yaourt -S llc', 'error: target not found: llc'), ['yaourt -S extra/llvm', 'yaourt -S extra/llvm35']),
 | 
					    (Command('yaourt -S llc', 'error: target not found: llc'), ['yaourt -S extra/llvm', 'yaourt -S extra/llvm35']),
 | 
				
			||||||
    (Command('pacman -S llc', 'error: target not found: llc'), ['pacman -S extra/llvm', 'pacman -S extra/llvm35']),
 | 
					    (Command('pacman -S llc', 'error: target not found: llc'), ['pacman -S extra/llvm', 'pacman -S extra/llvm35']),
 | 
				
			||||||
    (Command('sudo pacman -S llc', 'error: target not found: llc'), ['sudo pacman -S extra/llvm', 'sudo pacman -S extra/llvm35'])])
 | 
					    (Command('sudo pacman -S llc', 'error: target not found: llc'), ['sudo pacman -S extra/llvm', 'sudo pacman -S extra/llvm35'])])
 | 
				
			||||||
@@ -39,6 +42,7 @@ def test_get_new_command(command, fixed):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('command, fixed', [
 | 
					@pytest.mark.parametrize('command, fixed', [
 | 
				
			||||||
 | 
					    (Command('yay -S llc', 'error: target not found: llc'), ['yay -S extra/llvm', 'yay -S extra/llvm35']),
 | 
				
			||||||
    (Command('yaourt -S llc', 'error: target not found: llc'), ['yaourt -S extra/llvm', 'yaourt -S extra/llvm35']),
 | 
					    (Command('yaourt -S llc', 'error: target not found: llc'), ['yaourt -S extra/llvm', 'yaourt -S extra/llvm35']),
 | 
				
			||||||
    (Command('pacman -S llc', 'error: target not found: llc'), ['pacman -S extra/llvm', 'pacman -S extra/llvm35']),
 | 
					    (Command('pacman -S llc', 'error: target not found: llc'), ['pacman -S extra/llvm', 'pacman -S extra/llvm35']),
 | 
				
			||||||
    (Command('sudo pacman -S llc', 'error: target not found: llc'), ['sudo pacman -S extra/llvm', 'sudo pacman -S extra/llvm35'])])
 | 
					    (Command('sudo pacman -S llc', 'error: target not found: llc'), ['sudo pacman -S extra/llvm', 'sudo pacman -S extra/llvm35'])])
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										27
									
								
								tests/rules/test_pip_install.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								tests/rules/test_pip_install.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					# -*- coding: UTF-8 -*-
 | 
				
			||||||
 | 
					from thefuck.rules.pip_install import match, get_new_command
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_match():
 | 
				
			||||||
 | 
					    response1 = """
 | 
				
			||||||
 | 
					    Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: '/Library/Python/2.7/site-packages/entrypoints.pyc'
 | 
				
			||||||
 | 
					Consider using the `--user` option or check the permissions.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					    assert match(Command('pip install -r requirements.txt', response1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    response2 = """
 | 
				
			||||||
 | 
					Collecting bacon
 | 
				
			||||||
 | 
					  Downloading https://files.pythonhosted.org/packages/b2/81/19fb79139ee71c8bc4e5a444546f318e2b87253b8939ec8a7e10d63b7341/bacon-0.3.1.zip (11.0MB)
 | 
				
			||||||
 | 
					    100% |████████████████████████████████| 11.0MB 3.0MB/s
 | 
				
			||||||
 | 
					Installing collected packages: bacon
 | 
				
			||||||
 | 
					  Running setup.py install for bacon ... done
 | 
				
			||||||
 | 
					Successfully installed bacon-0.3.1
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					    assert not match(Command('pip install bacon', response2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_get_new_command():
 | 
				
			||||||
 | 
					    assert get_new_command(Command('pip install -r requirements.txt', '')) == 'pip install --user -r requirements.txt'
 | 
				
			||||||
 | 
					    assert get_new_command(Command('pip install bacon', '')) == 'pip install --user bacon'
 | 
				
			||||||
 | 
					    assert get_new_command(Command('pip install --user -r requirements.txt', '')) == 'sudo pip install -r requirements.txt'
 | 
				
			||||||
@@ -4,13 +4,23 @@ from thefuck.types import Command
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture
 | 
					@pytest.fixture
 | 
				
			||||||
def pip_unknown_cmd():
 | 
					def pip_unknown_cmd_without_recommend():
 | 
				
			||||||
    return '''ERROR: unknown command "instatl" - maybe you meant "install"'''
 | 
					    return '''ERROR: unknown command "i"'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture
 | 
					@pytest.fixture
 | 
				
			||||||
def pip_unknown_cmd_without_recommend():
 | 
					def broken():
 | 
				
			||||||
    return '''ERROR: unknown command "i"'''
 | 
					    return 'instatl'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture
 | 
				
			||||||
 | 
					def suggested():
 | 
				
			||||||
 | 
					    return 'install'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture
 | 
				
			||||||
 | 
					def pip_unknown_cmd(broken, suggested):
 | 
				
			||||||
 | 
					    return 'ERROR: unknown command "{}" - maybe you meant "{}"'.format(broken, suggested)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_match(pip_unknown_cmd, pip_unknown_cmd_without_recommend):
 | 
					def test_match(pip_unknown_cmd, pip_unknown_cmd_without_recommend):
 | 
				
			||||||
@@ -19,6 +29,9 @@ def test_match(pip_unknown_cmd, pip_unknown_cmd_without_recommend):
 | 
				
			|||||||
                             pip_unknown_cmd_without_recommend))
 | 
					                             pip_unknown_cmd_without_recommend))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_get_new_command(pip_unknown_cmd):
 | 
					@pytest.mark.parametrize('script, broken, suggested, new_cmd', [
 | 
				
			||||||
    assert get_new_command(Command('pip instatl',
 | 
					    ('pip un+install thefuck', 'un+install', 'uninstall', 'pip uninstall thefuck'),
 | 
				
			||||||
                                   pip_unknown_cmd)) == 'pip install'
 | 
					    ('pip instatl', 'instatl', 'install', 'pip install')])
 | 
				
			||||||
 | 
					def test_get_new_command(script, new_cmd, pip_unknown_cmd):
 | 
				
			||||||
 | 
					    assert get_new_command(Command(script,
 | 
				
			||||||
 | 
					                                   pip_unknown_cmd)) == new_cmd
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										52
									
								
								tests/rules/test_pyenv_no_such_command.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								tests/rules/test_pyenv_no_such_command.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from thefuck.rules.pyenv_no_such_command import get_new_command, match
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture
 | 
				
			||||||
 | 
					def output(pyenv_cmd):
 | 
				
			||||||
 | 
					    return "pyenv: no such command `{}'".format(pyenv_cmd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture(autouse=True)
 | 
				
			||||||
 | 
					def Popen(mocker):
 | 
				
			||||||
 | 
					    mock = mocker.patch('thefuck.rules.pyenv_no_such_command.Popen')
 | 
				
			||||||
 | 
					    mock.return_value.stdout.readlines.return_value = (
 | 
				
			||||||
 | 
					        b'--version\nactivate\ncommands\ncompletions\ndeactivate\nexec_\n'
 | 
				
			||||||
 | 
					        b'global\nhelp\nhooks\ninit\ninstall\nlocal\nprefix_\n'
 | 
				
			||||||
 | 
					        b'realpath.dylib\nrehash\nroot\nshell\nshims\nuninstall\nversion_\n'
 | 
				
			||||||
 | 
					        b'version-file\nversion-file-read\nversion-file-write\nversion-name_\n'
 | 
				
			||||||
 | 
					        b'version-origin\nversions\nvirtualenv\nvirtualenv-delete_\n'
 | 
				
			||||||
 | 
					        b'virtualenv-init\nvirtualenv-prefix\nvirtualenvs_\n'
 | 
				
			||||||
 | 
					        b'virtualenvwrapper\nvirtualenvwrapper_lazy\nwhence\nwhich_\n'
 | 
				
			||||||
 | 
					    ).split()
 | 
				
			||||||
 | 
					    return mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('script, pyenv_cmd', [
 | 
				
			||||||
 | 
					    ('pyenv globe', 'globe'),
 | 
				
			||||||
 | 
					    ('pyenv intall 3.8.0', 'intall'),
 | 
				
			||||||
 | 
					    ('pyenv list', 'list'),
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					def test_match(script, pyenv_cmd, output):
 | 
				
			||||||
 | 
					    assert match(Command(script, output=output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('script, output', [
 | 
				
			||||||
 | 
					    ('pyenv global', 'system'),
 | 
				
			||||||
 | 
					    ('pyenv versions', '  3.7.0\n  3.7.1\n* 3.7.2\n'),
 | 
				
			||||||
 | 
					    ('pyenv install --list', '  3.7.0\n  3.7.1\n  3.7.2\n'),
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					def test_not_match(script, output):
 | 
				
			||||||
 | 
					    assert not match(Command(script, output=output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('script, pyenv_cmd, result', [
 | 
				
			||||||
 | 
					    ('pyenv globe', 'globe', 'pyenv global'),
 | 
				
			||||||
 | 
					    ('pyenv intall 3.8.0', 'intall', 'pyenv install 3.8.0'),
 | 
				
			||||||
 | 
					    ('pyenv list', 'list', 'pyenv install --list'),
 | 
				
			||||||
 | 
					    ('pyenv remove 3.8.0', 'remove', 'pyenv uninstall 3.8.0'),
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					def test_get_new_command(script, pyenv_cmd, output, result):
 | 
				
			||||||
 | 
					    assert result in get_new_command(Command(script, output))
 | 
				
			||||||
							
								
								
									
										38
									
								
								tests/rules/test_remove_shell_prompt_literal.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								tests/rules/test_remove_shell_prompt_literal.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from thefuck.rules.remove_shell_prompt_literal import match, get_new_command
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture
 | 
				
			||||||
 | 
					def output():
 | 
				
			||||||
 | 
					    return "$: command not found"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize("script", ["$ cd newdir", " $ cd newdir"])
 | 
				
			||||||
 | 
					def test_match(script, output):
 | 
				
			||||||
 | 
					    assert match(Command(script, output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize(
 | 
				
			||||||
 | 
					    "command",
 | 
				
			||||||
 | 
					    [
 | 
				
			||||||
 | 
					        Command("$", "$: command not found"),
 | 
				
			||||||
 | 
					        Command(" $", "$: command not found"),
 | 
				
			||||||
 | 
					        Command("$?", "127: command not found"),
 | 
				
			||||||
 | 
					        Command(" $?", "127: command not found"),
 | 
				
			||||||
 | 
					        Command("", ""),
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					def test_not_match(command):
 | 
				
			||||||
 | 
					    assert not match(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize(
 | 
				
			||||||
 | 
					    "script, new_command",
 | 
				
			||||||
 | 
					    [
 | 
				
			||||||
 | 
					        ("$ cd newdir", "cd newdir"),
 | 
				
			||||||
 | 
					        ("$ python3 -m virtualenv env", "python3 -m virtualenv env"),
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					def test_get_new_command(script, new_command, output):
 | 
				
			||||||
 | 
					    assert get_new_command(Command(script, output)) == new_command
 | 
				
			||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
# -*- encoding: utf-8 -*-
 | 
					# -*- encoding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from thefuck.rules import switch_lang
 | 
					from thefuck.rules import switch_lang
 | 
				
			||||||
from thefuck.types import Command
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -9,7 +10,8 @@ from thefuck.types import 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: שפא-עקא'),
 | 
				
			||||||
    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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -19,7 +21,8 @@ def test_match(command):
 | 
				
			|||||||
    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')])
 | 
					    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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,6 +31,9 @@ def test_not_match(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'שפא-עקא ןמדאשךך הןצ', ''), 'apt-get install vim'),
 | 
				
			||||||
    (Command(u'ךד -ךש', ''), 'ls -la')])
 | 
					    (Command(u'ךד -ךש', ''), 'ls -la'),
 | 
				
			||||||
 | 
					    (Command(u'멧-ㅎㄷㅅ ㅑㅜㄴㅅ미ㅣ 퍄ㅡ', ''), 'apt-get install vim'),
 | 
				
			||||||
 | 
					    (Command(u'ㅣㄴ -ㅣㅁ', ''), 'ls -la'),
 | 
				
			||||||
 | 
					    (Command(u'ㅔㅁㅅ촤', ''), 'patchk'), ])
 | 
				
			||||||
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
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										33
									
								
								tests/rules/test_terraform_init.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								tests/rules/test_terraform_init.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from thefuck.rules.terraform_init import match, get_new_command
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('script, output', [
 | 
				
			||||||
 | 
					    ('terraform plan', 'Error: Initialization required. '
 | 
				
			||||||
 | 
					                       'Please see the error message above.'),
 | 
				
			||||||
 | 
					    ('terraform plan', 'This module is not yet installed. Run "terraform init" '
 | 
				
			||||||
 | 
					                       'to install all modules required by this configuration.'),
 | 
				
			||||||
 | 
					    ('terraform apply', 'Error: Initialization required. '
 | 
				
			||||||
 | 
					                        'Please see the error message above.'),
 | 
				
			||||||
 | 
					    ('terraform apply', 'This module is not yet installed. Run "terraform init" '
 | 
				
			||||||
 | 
					                        'to install all modules required by this configuration.')])
 | 
				
			||||||
 | 
					def test_match(script, output):
 | 
				
			||||||
 | 
					    assert match(Command(script, output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('script, output', [
 | 
				
			||||||
 | 
					    ('terraform --version', 'Terraform v0.12.2'),
 | 
				
			||||||
 | 
					    ('terraform plan', 'No changes. Infrastructure is up-to-date.'),
 | 
				
			||||||
 | 
					    ('terraform apply', 'Apply complete! Resources: 0 added, 0 changed, 0 destroyed.'),
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					def test_not_match(script, output):
 | 
				
			||||||
 | 
					    assert not match(Command(script, output=output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('command, new_command', [
 | 
				
			||||||
 | 
					    (Command('terraform plan', ''), 'terraform init && terraform plan'),
 | 
				
			||||||
 | 
					    (Command('terraform apply', ''), 'terraform init && terraform apply'),
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					def test_get_new_command(command, new_command):
 | 
				
			||||||
 | 
					    assert get_new_command(command) == new_command
 | 
				
			||||||
@@ -3,25 +3,31 @@ from thefuck.rules.touch import match, get_new_command
 | 
				
			|||||||
from thefuck.types import Command
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture
 | 
					def output(is_bsd):
 | 
				
			||||||
def output():
 | 
					    if is_bsd:
 | 
				
			||||||
    return "touch: cannot touch '/a/b/c':" \
 | 
					        return "touch: /a/b/c: No such file or directory"
 | 
				
			||||||
           " No such file or directory"
 | 
					    return "touch: cannot touch '/a/b/c': No such file or directory"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_match(output):
 | 
					@pytest.mark.parametrize('script, is_bsd', [
 | 
				
			||||||
    command = Command('touch /a/b/c', output)
 | 
					    ('touch /a/b/c', False),
 | 
				
			||||||
 | 
					    ('touch /a/b/c', True)])
 | 
				
			||||||
 | 
					def test_match(script, is_bsd):
 | 
				
			||||||
 | 
					    command = Command(script, output(is_bsd))
 | 
				
			||||||
    assert match(command)
 | 
					    assert match(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('command', [
 | 
					@pytest.mark.parametrize('command', [
 | 
				
			||||||
    Command('touch /a/b/c', ''),
 | 
					    Command('touch /a/b/c', ''),
 | 
				
			||||||
    Command('ls /a/b/c', output())])
 | 
					    Command('ls /a/b/c', output(False))])
 | 
				
			||||||
def test_not_match(command):
 | 
					def test_not_match(command):
 | 
				
			||||||
    assert not match(command)
 | 
					    assert not match(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_get_new_command(output):
 | 
					@pytest.mark.parametrize('script, is_bsd', [
 | 
				
			||||||
    command = Command('touch /a/b/c', output)
 | 
					    ('touch /a/b/c', False),
 | 
				
			||||||
 | 
					    ('touch /a/b/c', True)])
 | 
				
			||||||
 | 
					def test_get_new_command(script, is_bsd):
 | 
				
			||||||
 | 
					    command = Command(script, output(is_bsd))
 | 
				
			||||||
    fixed_command = get_new_command(command)
 | 
					    fixed_command = get_new_command(command)
 | 
				
			||||||
    assert fixed_command == 'mkdir -p /a/b && touch /a/b/c'
 | 
					    assert fixed_command == 'mkdir -p /a/b && touch /a/b/c'
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										173
									
								
								tests/rules/test_yum_invalid_operation.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								tests/rules/test_yum_invalid_operation.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,173 @@
 | 
				
			|||||||
 | 
					from io import BytesIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from thefuck.rules.yum_invalid_operation import match, get_new_command, _get_operations
 | 
				
			||||||
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					yum_help_text = '''Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
 | 
				
			||||||
 | 
					Usage: yum [options] COMMAND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					List of Commands:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					check          Check for problems in the rpmdb
 | 
				
			||||||
 | 
					check-update   Check for available package updates
 | 
				
			||||||
 | 
					clean          Remove cached data
 | 
				
			||||||
 | 
					deplist        List a package's dependencies
 | 
				
			||||||
 | 
					distribution-synchronization Synchronize installed packages to the latest available versions
 | 
				
			||||||
 | 
					downgrade      downgrade a package
 | 
				
			||||||
 | 
					erase          Remove a package or packages from your system
 | 
				
			||||||
 | 
					fs             Acts on the filesystem data of the host, mainly for removing docs/lanuages for minimal hosts.
 | 
				
			||||||
 | 
					fssnapshot     Creates filesystem snapshots, or lists/deletes current snapshots.
 | 
				
			||||||
 | 
					groups         Display, or use, the groups information
 | 
				
			||||||
 | 
					help           Display a helpful usage message
 | 
				
			||||||
 | 
					history        Display, or use, the transaction history
 | 
				
			||||||
 | 
					info           Display details about a package or group of packages
 | 
				
			||||||
 | 
					install        Install a package or packages on your system
 | 
				
			||||||
 | 
					langavailable  Check available languages
 | 
				
			||||||
 | 
					langinfo       List languages information
 | 
				
			||||||
 | 
					langinstall    Install appropriate language packs for a language
 | 
				
			||||||
 | 
					langlist       List installed languages
 | 
				
			||||||
 | 
					langremove     Remove installed language packs for a language
 | 
				
			||||||
 | 
					list           List a package or groups of packages
 | 
				
			||||||
 | 
					load-transaction load a saved transaction from filename
 | 
				
			||||||
 | 
					makecache      Generate the metadata cache
 | 
				
			||||||
 | 
					provides       Find what package provides the given value
 | 
				
			||||||
 | 
					reinstall      reinstall a package
 | 
				
			||||||
 | 
					repo-pkgs      Treat a repo. as a group of packages, so we can install/remove all of them
 | 
				
			||||||
 | 
					repolist       Display the configured software repositories
 | 
				
			||||||
 | 
					search         Search package details for the given string
 | 
				
			||||||
 | 
					shell          Run an interactive yum shell
 | 
				
			||||||
 | 
					swap           Simple way to swap packages, instead of using shell
 | 
				
			||||||
 | 
					update         Update a package or packages on your system
 | 
				
			||||||
 | 
					update-minimal Works like upgrade, but goes to the 'newest' package match which fixes a problem that affects your system
 | 
				
			||||||
 | 
					updateinfo     Acts on repository update information
 | 
				
			||||||
 | 
					upgrade        Update packages taking obsoletes into account
 | 
				
			||||||
 | 
					version        Display a version for the machine and/or available repos.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Options:
 | 
				
			||||||
 | 
					  -h, --help            show this help message and exit
 | 
				
			||||||
 | 
					  -t, --tolerant        be tolerant of errors
 | 
				
			||||||
 | 
					  -C, --cacheonly       run entirely from system cache, don't update cache
 | 
				
			||||||
 | 
					  -c [config file], --config=[config file]
 | 
				
			||||||
 | 
					                        config file location
 | 
				
			||||||
 | 
					  -R [minutes], --randomwait=[minutes]
 | 
				
			||||||
 | 
					                        maximum command wait time
 | 
				
			||||||
 | 
					  -d [debug level], --debuglevel=[debug level]
 | 
				
			||||||
 | 
					                        debugging output level
 | 
				
			||||||
 | 
					  --showduplicates      show duplicates, in repos, in list/search commands
 | 
				
			||||||
 | 
					  -e [error level], --errorlevel=[error level]
 | 
				
			||||||
 | 
					                        error output level
 | 
				
			||||||
 | 
					  --rpmverbosity=[debug level name]
 | 
				
			||||||
 | 
					                        debugging output level for rpm
 | 
				
			||||||
 | 
					  -q, --quiet           quiet operation
 | 
				
			||||||
 | 
					  -v, --verbose         verbose operation
 | 
				
			||||||
 | 
					  -y, --assumeyes       answer yes for all questions
 | 
				
			||||||
 | 
					  --assumeno            answer no for all questions
 | 
				
			||||||
 | 
					  --version             show Yum version and exit
 | 
				
			||||||
 | 
					  --installroot=[path]  set install root
 | 
				
			||||||
 | 
					  --enablerepo=[repo]   enable one or more repositories (wildcards allowed)
 | 
				
			||||||
 | 
					  --disablerepo=[repo]  disable one or more repositories (wildcards allowed)
 | 
				
			||||||
 | 
					  -x [package], --exclude=[package]
 | 
				
			||||||
 | 
					                        exclude package(s) by name or glob
 | 
				
			||||||
 | 
					  --disableexcludes=[repo]
 | 
				
			||||||
 | 
					                        disable exclude from main, for a repo or for
 | 
				
			||||||
 | 
					                        everything
 | 
				
			||||||
 | 
					  --disableincludes=[repo]
 | 
				
			||||||
 | 
					                        disable includepkgs for a repo or for everything
 | 
				
			||||||
 | 
					  --obsoletes           enable obsoletes processing during updates
 | 
				
			||||||
 | 
					  --noplugins           disable Yum plugins
 | 
				
			||||||
 | 
					  --nogpgcheck          disable gpg signature checking
 | 
				
			||||||
 | 
					  --disableplugin=[plugin]
 | 
				
			||||||
 | 
					                        disable plugins by name
 | 
				
			||||||
 | 
					  --enableplugin=[plugin]
 | 
				
			||||||
 | 
					                        enable plugins by name
 | 
				
			||||||
 | 
					  --skip-broken         skip packages with depsolving problems
 | 
				
			||||||
 | 
					  --color=COLOR         control whether color is used
 | 
				
			||||||
 | 
					  --releasever=RELEASEVER
 | 
				
			||||||
 | 
					                        set value of $releasever in yum config and repo files
 | 
				
			||||||
 | 
					  --downloadonly        don't update, just download
 | 
				
			||||||
 | 
					  --downloaddir=DLDIR   specifies an alternate directory to store packages
 | 
				
			||||||
 | 
					  --setopt=SETOPTS      set arbitrary config and repo options
 | 
				
			||||||
 | 
					  --bugfix              Include bugfix relevant packages, in updates
 | 
				
			||||||
 | 
					  --security            Include security relevant packages, in updates
 | 
				
			||||||
 | 
					  --advisory=ADVS, --advisories=ADVS
 | 
				
			||||||
 | 
					                        Include packages needed to fix the given advisory, in
 | 
				
			||||||
 | 
					                        updates
 | 
				
			||||||
 | 
					  --bzs=BZS             Include packages needed to fix the given BZ, in
 | 
				
			||||||
 | 
					                        updates
 | 
				
			||||||
 | 
					  --cves=CVES           Include packages needed to fix the given CVE, in
 | 
				
			||||||
 | 
					                        updates
 | 
				
			||||||
 | 
					  --sec-severity=SEVS, --secseverity=SEVS
 | 
				
			||||||
 | 
					                        Include security relevant packages matching the
 | 
				
			||||||
 | 
					                        severity, in updates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Plugin Options:
 | 
				
			||||||
 | 
					    --samearch-priorities
 | 
				
			||||||
 | 
					                        Priority-exclude packages based on name + arch
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					yum_unsuccessful_search_text = '''Warning: No matches found for: {}
 | 
				
			||||||
 | 
					No matches found
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					yum_successful_vim_search_text = '''================================================== N/S matched: vim ===================================================
 | 
				
			||||||
 | 
					protobuf-vim.x86_64 : Vim syntax highlighting for Google Protocol Buffers descriptions
 | 
				
			||||||
 | 
					vim-X11.x86_64 : The VIM version of the vi editor for the X Window System - GVim
 | 
				
			||||||
 | 
					vim-common.x86_64 : The common files needed by any version of the VIM editor
 | 
				
			||||||
 | 
					vim-enhanced.x86_64 : A version of the VIM editor which includes recent enhancements
 | 
				
			||||||
 | 
					vim-filesystem.x86_64 : VIM filesystem layout
 | 
				
			||||||
 | 
					vim-filesystem.noarch : VIM filesystem layout
 | 
				
			||||||
 | 
					vim-minimal.x86_64 : A minimal version of the VIM editor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Name and summary matches only, use "search all" for everything.
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					yum_invalid_op_text = '''Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
 | 
				
			||||||
 | 
					No such command: {}. Please use /usr/bin/yum --help
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					yum_operations = [
 | 
				
			||||||
 | 
					    'check', 'check-update', 'clean', 'deplist', 'distribution-synchronization', 'downgrade', 'erase', 'fs',
 | 
				
			||||||
 | 
					    'fssnapshot', 'groups', 'help', 'history', 'info', 'install', 'langavailable', 'langinfo', 'langinstall',
 | 
				
			||||||
 | 
					    'langlist', 'langremove', 'list', 'load-transaction', 'makecache', 'provides', 'reinstall', 'repo-pkgs', 'repolist',
 | 
				
			||||||
 | 
					    'search', 'shell', 'swap', 'update', 'update-minimal', 'updateinfo', 'upgrade', 'version', ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('command', [
 | 
				
			||||||
 | 
					    'saerch', 'uninstall',
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					def test_match(command):
 | 
				
			||||||
 | 
					    assert match(Command('yum {}'.format(command), yum_invalid_op_text.format(command)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('command, output', [
 | 
				
			||||||
 | 
					    ('vim', ''),
 | 
				
			||||||
 | 
					    ('yum', yum_help_text,),
 | 
				
			||||||
 | 
					    ('yum help', yum_help_text,),
 | 
				
			||||||
 | 
					    ('yum search asdf', yum_unsuccessful_search_text.format('asdf'),),
 | 
				
			||||||
 | 
					    ('yum search vim', yum_successful_vim_search_text)
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					def test_not_match(command, output):
 | 
				
			||||||
 | 
					    assert not match(Command(command, output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture
 | 
				
			||||||
 | 
					def yum_help(mocker):
 | 
				
			||||||
 | 
					    mock = mocker.patch('subprocess.Popen')
 | 
				
			||||||
 | 
					    mock.return_value.stdout = BytesIO(bytes(yum_help_text.encode('utf-8')))
 | 
				
			||||||
 | 
					    return mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.usefixtures('no_memoize', 'yum_help')
 | 
				
			||||||
 | 
					def test_get_operations():
 | 
				
			||||||
 | 
					    assert _get_operations() == yum_operations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.usefixtures('no_memoize', 'yum_help')
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('script, output, result', [
 | 
				
			||||||
 | 
					    ('yum uninstall', yum_invalid_op_text.format('uninstall'), 'yum remove',),
 | 
				
			||||||
 | 
					    ('yum saerch asdf', yum_invalid_op_text.format('saerch'), 'yum search asdf',),
 | 
				
			||||||
 | 
					    ('yum hlep', yum_invalid_op_text.format('hlep'), 'yum help',),
 | 
				
			||||||
 | 
					])
 | 
				
			||||||
 | 
					def test_get_new_command(script, output, result):
 | 
				
			||||||
 | 
					    assert get_new_command(Command(script, output))[0] == result
 | 
				
			||||||
@@ -11,6 +11,11 @@ class TestBash(object):
 | 
				
			|||||||
    def shell(self):
 | 
					    def shell(self):
 | 
				
			||||||
        return Bash()
 | 
					        return Bash()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @pytest.fixture(autouse=True)
 | 
				
			||||||
 | 
					    def Popen(self, mocker):
 | 
				
			||||||
 | 
					        mock = mocker.patch('thefuck.shells.bash.Popen')
 | 
				
			||||||
 | 
					        return mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @pytest.fixture(autouse=True)
 | 
					    @pytest.fixture(autouse=True)
 | 
				
			||||||
    def shell_aliases(self):
 | 
					    def shell_aliases(self):
 | 
				
			||||||
        os.environ['TF_SHELL_ALIASES'] = (
 | 
					        os.environ['TF_SHELL_ALIASES'] = (
 | 
				
			||||||
@@ -73,3 +78,13 @@ class TestBash(object):
 | 
				
			|||||||
                                                    config_exists):
 | 
					                                                    config_exists):
 | 
				
			||||||
        config_exists.return_value = False
 | 
					        config_exists.return_value = False
 | 
				
			||||||
        assert not shell.how_to_configure().can_configure_automatically
 | 
					        assert not shell.how_to_configure().can_configure_automatically
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_info(self, shell, Popen):
 | 
				
			||||||
 | 
					        Popen.return_value.stdout.read.side_effect = [b'3.5.9']
 | 
				
			||||||
 | 
					        assert shell.info() == 'Bash 3.5.9'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_get_version_error(self, shell, Popen):
 | 
				
			||||||
 | 
					        Popen.return_value.stdout.read.side_effect = OSError
 | 
				
			||||||
 | 
					        with pytest.raises(OSError):
 | 
				
			||||||
 | 
					            shell._get_version()
 | 
				
			||||||
 | 
					        assert Popen.call_args[0][0] == ['bash', '-c', 'echo $BASH_VERSION']
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
 | 
					from thefuck.const import ARGUMENT_PLACEHOLDER
 | 
				
			||||||
from thefuck.shells import Fish
 | 
					from thefuck.shells import Fish
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -16,7 +17,8 @@ class TestFish(object):
 | 
				
			|||||||
        mock.return_value.stdout.read.side_effect = [(
 | 
					        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']
 | 
					            (b'alias fish_key_reader /usr/bin/fish_key_reader\nalias g git\n'
 | 
				
			||||||
 | 
					             b'alias alias_with_equal_sign=echo\ninvalid_alias'), b'func1\nfunc2', b'']
 | 
				
			||||||
        return mock
 | 
					        return mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @pytest.mark.parametrize('key, value', [
 | 
					    @pytest.mark.parametrize('key, value', [
 | 
				
			||||||
@@ -27,8 +29,9 @@ class TestFish(object):
 | 
				
			|||||||
        ('THEFUCK_OVERRIDDEN_ALIASES', '\ncut,\n\ngit,\tsed\r')])
 | 
					        ('THEFUCK_OVERRIDDEN_ALIASES', '\ncut,\n\ngit,\tsed\r')])
 | 
				
			||||||
    def test_get_overridden_aliases(self, shell, os_environ, key, value):
 | 
					    def test_get_overridden_aliases(self, shell, os_environ, key, value):
 | 
				
			||||||
        os_environ[key] = value
 | 
					        os_environ[key] = value
 | 
				
			||||||
        assert shell._get_overridden_aliases() == {'cd', 'cut', 'git', 'grep',
 | 
					        overridden = shell._get_overridden_aliases()
 | 
				
			||||||
                                                   'ls', 'man', 'open', 'sed'}
 | 
					        assert set(overridden) == {'cd', 'cut', 'git', 'grep',
 | 
				
			||||||
 | 
					                                   'ls', 'man', 'open', 'sed'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @pytest.mark.parametrize('before, after', [
 | 
					    @pytest.mark.parametrize('before, after', [
 | 
				
			||||||
        ('cd', 'cd'),
 | 
					        ('cd', 'cd'),
 | 
				
			||||||
@@ -69,7 +72,9 @@ class TestFish(object):
 | 
				
			|||||||
                                       'pushd': 'pushd',
 | 
					                                       'pushd': 'pushd',
 | 
				
			||||||
                                       'ruby': 'ruby',
 | 
					                                       'ruby': 'ruby',
 | 
				
			||||||
                                       'g': 'git',
 | 
					                                       'g': 'git',
 | 
				
			||||||
                                       'fish_key_reader': '/usr/bin/fish_key_reader'}
 | 
					                                       'fish_key_reader': '/usr/bin/fish_key_reader',
 | 
				
			||||||
 | 
					                                       'alias_with_equal_sign': 'echo'}
 | 
				
			||||||
 | 
					        assert shell.get_aliases() == {'func1': 'func1', 'func2': 'func2'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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')
 | 
				
			||||||
@@ -78,6 +83,7 @@ class TestFish(object):
 | 
				
			|||||||
        assert 'TF_SHELL=fish' 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')
 | 
				
			||||||
 | 
					        assert ARGUMENT_PLACEHOLDER in shell.app_alias('fuck')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_app_alias_alter_history(self, settings, shell):
 | 
					    def test_app_alias_alter_history(self, settings, shell):
 | 
				
			||||||
        settings.alter_history = True
 | 
					        settings.alter_history = True
 | 
				
			||||||
@@ -109,3 +115,18 @@ class TestFish(object):
 | 
				
			|||||||
                                                    config_exists):
 | 
					                                                    config_exists):
 | 
				
			||||||
        config_exists.return_value = False
 | 
					        config_exists.return_value = False
 | 
				
			||||||
        assert not shell.how_to_configure().can_configure_automatically
 | 
					        assert not shell.how_to_configure().can_configure_automatically
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_get_version(self, shell, Popen):
 | 
				
			||||||
 | 
					        Popen.return_value.stdout.read.side_effect = [b'fish, version 3.5.9\n']
 | 
				
			||||||
 | 
					        assert shell._get_version() == '3.5.9'
 | 
				
			||||||
 | 
					        assert Popen.call_args[0][0] == ['fish', '--version']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @pytest.mark.parametrize('side_effect, exception', [
 | 
				
			||||||
 | 
					        ([b'\n'], IndexError),
 | 
				
			||||||
 | 
					        (OSError('file not found'), OSError),
 | 
				
			||||||
 | 
					    ])
 | 
				
			||||||
 | 
					    def test_get_version_error(self, side_effect, exception, shell, Popen):
 | 
				
			||||||
 | 
					        Popen.return_value.stdout.read.side_effect = side_effect
 | 
				
			||||||
 | 
					        with pytest.raises(exception):
 | 
				
			||||||
 | 
					            shell._get_version()
 | 
				
			||||||
 | 
					        assert Popen.call_args[0][0] == ['fish', '--version']
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,3 +43,14 @@ class TestGeneric(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def test_how_to_configure(self, shell):
 | 
					    def test_how_to_configure(self, shell):
 | 
				
			||||||
        assert shell.how_to_configure() is None
 | 
					        assert shell.how_to_configure() is None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @pytest.mark.parametrize('side_effect, expected_info, warn', [
 | 
				
			||||||
 | 
					        ([u'3.5.9'], u'Generic Shell 3.5.9', False),
 | 
				
			||||||
 | 
					        ([OSError], u'Generic Shell', True),
 | 
				
			||||||
 | 
					    ])
 | 
				
			||||||
 | 
					    def test_info(self, side_effect, expected_info, warn, shell, mocker):
 | 
				
			||||||
 | 
					        warn_mock = mocker.patch('thefuck.shells.generic.warn')
 | 
				
			||||||
 | 
					        shell._get_version = mocker.Mock(side_effect=side_effect)
 | 
				
			||||||
 | 
					        assert shell.info() == expected_info
 | 
				
			||||||
 | 
					        assert warn_mock.called is warn
 | 
				
			||||||
 | 
					        assert shell._get_version.called
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,11 @@ class TestPowershell(object):
 | 
				
			|||||||
    def shell(self):
 | 
					    def shell(self):
 | 
				
			||||||
        return Powershell()
 | 
					        return Powershell()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @pytest.fixture(autouse=True)
 | 
				
			||||||
 | 
					    def Popen(self, mocker):
 | 
				
			||||||
 | 
					        mock = mocker.patch('thefuck.shells.powershell.Popen')
 | 
				
			||||||
 | 
					        return mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_and_(self, shell):
 | 
					    def test_and_(self, shell):
 | 
				
			||||||
        assert shell.and_('ls', 'cd') == '(ls) -and (cd)'
 | 
					        assert shell.and_('ls', 'cd') == '(ls) -and (cd)'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,3 +25,20 @@ class TestPowershell(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def test_how_to_configure(self, shell):
 | 
					    def test_how_to_configure(self, shell):
 | 
				
			||||||
        assert not shell.how_to_configure().can_configure_automatically
 | 
					        assert not shell.how_to_configure().can_configure_automatically
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @pytest.mark.parametrize('side_effect, expected_version, call_args', [
 | 
				
			||||||
 | 
					        ([b'''Major  Minor  Build  Revision
 | 
				
			||||||
 | 
					-----  -----  -----  --------
 | 
				
			||||||
 | 
					5      1      17763  316     \n'''], 'PowerShell 5.1.17763.316', ['powershell.exe']),
 | 
				
			||||||
 | 
					        ([IOError, b'PowerShell 6.1.2\n'], 'PowerShell 6.1.2', ['powershell.exe', 'pwsh'])])
 | 
				
			||||||
 | 
					    def test_info(self, side_effect, expected_version, call_args, shell, Popen):
 | 
				
			||||||
 | 
					        Popen.return_value.stdout.read.side_effect = side_effect
 | 
				
			||||||
 | 
					        assert shell.info() == expected_version
 | 
				
			||||||
 | 
					        assert Popen.call_count == len(call_args)
 | 
				
			||||||
 | 
					        assert all([Popen.call_args_list[i][0][0][0] == call_arg for i, call_arg in enumerate(call_args)])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_get_version_error(self, shell, Popen):
 | 
				
			||||||
 | 
					        Popen.return_value.stdout.read.side_effect = RuntimeError
 | 
				
			||||||
 | 
					        with pytest.raises(RuntimeError):
 | 
				
			||||||
 | 
					            shell._get_version()
 | 
				
			||||||
 | 
					        assert Popen.call_args[0][0] == ['powershell.exe', '$PSVersionTable.PSVersion']
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,3 +61,17 @@ class TestTcsh(object):
 | 
				
			|||||||
                                                    config_exists):
 | 
					                                                    config_exists):
 | 
				
			||||||
        config_exists.return_value = False
 | 
					        config_exists.return_value = False
 | 
				
			||||||
        assert not shell.how_to_configure().can_configure_automatically
 | 
					        assert not shell.how_to_configure().can_configure_automatically
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_info(self, shell, Popen):
 | 
				
			||||||
 | 
					        Popen.return_value.stdout.read.side_effect = [
 | 
				
			||||||
 | 
					            b'tcsh 6.20.00 (Astron) 2016-11-24 (unknown-unknown-bsd44) \n']
 | 
				
			||||||
 | 
					        assert shell.info() == 'Tcsh 6.20.00'
 | 
				
			||||||
 | 
					        assert Popen.call_args[0][0] == ['tcsh', '--version']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @pytest.mark.parametrize('side_effect, exception', [
 | 
				
			||||||
 | 
					        ([b'\n'], IndexError), (OSError, OSError)])
 | 
				
			||||||
 | 
					    def test_get_version_error(self, side_effect, exception, shell, Popen):
 | 
				
			||||||
 | 
					        Popen.return_value.stdout.read.side_effect = side_effect
 | 
				
			||||||
 | 
					        with pytest.raises(exception):
 | 
				
			||||||
 | 
					            shell._get_version()
 | 
				
			||||||
 | 
					        assert Popen.call_args[0][0] == ['tcsh', '--version']
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,11 @@ class TestZsh(object):
 | 
				
			|||||||
    def shell(self):
 | 
					    def shell(self):
 | 
				
			||||||
        return Zsh()
 | 
					        return Zsh()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @pytest.fixture(autouse=True)
 | 
				
			||||||
 | 
					    def Popen(self, mocker):
 | 
				
			||||||
 | 
					        mock = mocker.patch('thefuck.shells.zsh.Popen')
 | 
				
			||||||
 | 
					        return mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @pytest.fixture(autouse=True)
 | 
					    @pytest.fixture(autouse=True)
 | 
				
			||||||
    def shell_aliases(self):
 | 
					    def shell_aliases(self):
 | 
				
			||||||
        os.environ['TF_SHELL_ALIASES'] = (
 | 
					        os.environ['TF_SHELL_ALIASES'] = (
 | 
				
			||||||
@@ -68,3 +73,13 @@ class TestZsh(object):
 | 
				
			|||||||
                                                    config_exists):
 | 
					                                                    config_exists):
 | 
				
			||||||
        config_exists.return_value = False
 | 
					        config_exists.return_value = False
 | 
				
			||||||
        assert not shell.how_to_configure().can_configure_automatically
 | 
					        assert not shell.how_to_configure().can_configure_automatically
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_info(self, shell, Popen):
 | 
				
			||||||
 | 
					        Popen.return_value.stdout.read.side_effect = [b'3.5.9']
 | 
				
			||||||
 | 
					        assert shell.info() == 'ZSH 3.5.9'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_get_version_error(self, shell, Popen):
 | 
				
			||||||
 | 
					        Popen.return_value.stdout.read.side_effect = OSError
 | 
				
			||||||
 | 
					        with pytest.raises(OSError):
 | 
				
			||||||
 | 
					            shell._get_version()
 | 
				
			||||||
 | 
					        assert Popen.call_args[0][0] == ['zsh', '-c', 'echo $ZSH_VERSION']
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,7 +53,8 @@ class TestSettingsFromEnv(object):
 | 
				
			|||||||
                           'THEFUCK_NO_COLORS': 'false',
 | 
					                           'THEFUCK_NO_COLORS': 'false',
 | 
				
			||||||
                           'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15',
 | 
					                           'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15',
 | 
				
			||||||
                           'THEFUCK_WAIT_SLOW_COMMAND': '999',
 | 
					                           'THEFUCK_WAIT_SLOW_COMMAND': '999',
 | 
				
			||||||
                           'THEFUCK_SLOW_COMMANDS': 'lein:react-native:./gradlew'})
 | 
					                           'THEFUCK_SLOW_COMMANDS': 'lein:react-native:./gradlew',
 | 
				
			||||||
 | 
					                           'THEFUCK_NUM_CLOSE_MATCHES': '359'})
 | 
				
			||||||
        settings.init()
 | 
					        settings.init()
 | 
				
			||||||
        assert settings.rules == ['bash', 'lisp']
 | 
					        assert settings.rules == ['bash', 'lisp']
 | 
				
			||||||
        assert settings.exclude_rules == ['git', 'vim']
 | 
					        assert settings.exclude_rules == ['git', 'vim']
 | 
				
			||||||
@@ -63,6 +64,7 @@ class TestSettingsFromEnv(object):
 | 
				
			|||||||
        assert settings.priority == {'bash': 10, 'vim': 15}
 | 
					        assert settings.priority == {'bash': 10, 'vim': 15}
 | 
				
			||||||
        assert settings.wait_slow_command == 999
 | 
					        assert settings.wait_slow_command == 999
 | 
				
			||||||
        assert settings.slow_commands == ['lein', 'react-native', './gradlew']
 | 
					        assert settings.slow_commands == ['lein', 'react-native', './gradlew']
 | 
				
			||||||
 | 
					        assert settings.num_close_matches == 359
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_from_env_with_DEFAULT(self, os_environ, settings):
 | 
					    def test_from_env_with_DEFAULT(self, os_environ, settings):
 | 
				
			||||||
        os_environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'})
 | 
					        os_environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'})
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
import warnings
 | 
					import warnings
 | 
				
			||||||
from mock import Mock
 | 
					from mock import Mock, call, patch
 | 
				
			||||||
from thefuck.utils import default_settings, \
 | 
					from thefuck.utils import default_settings, \
 | 
				
			||||||
    memoize, get_closest, get_all_executables, replace_argument, \
 | 
					    memoize, get_closest, get_all_executables, replace_argument, \
 | 
				
			||||||
    get_all_matched_commands, is_app, for_app, cache, \
 | 
					    get_all_matched_commands, is_app, for_app, cache, \
 | 
				
			||||||
    get_valid_history_without_current, _cache
 | 
					    get_valid_history_without_current, _cache, get_close_matches
 | 
				
			||||||
from thefuck.types import Command
 | 
					from thefuck.types import Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -50,6 +50,18 @@ class TestGetClosest(object):
 | 
				
			|||||||
                           fallback_to_first=False) is None
 | 
					                           fallback_to_first=False) is None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestGetCloseMatches(object):
 | 
				
			||||||
 | 
					    @patch('thefuck.utils.difflib_get_close_matches')
 | 
				
			||||||
 | 
					    def test_call_with_n(self, difflib_mock):
 | 
				
			||||||
 | 
					        get_close_matches('', [], 1)
 | 
				
			||||||
 | 
					        assert difflib_mock.call_args[0][2] == 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @patch('thefuck.utils.difflib_get_close_matches')
 | 
				
			||||||
 | 
					    def test_call_without_n(self, difflib_mock, settings):
 | 
				
			||||||
 | 
					        get_close_matches('', [])
 | 
				
			||||||
 | 
					        assert difflib_mock.call_args[0][2] == settings.get('num_close_matches')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture
 | 
					@pytest.fixture
 | 
				
			||||||
def get_aliases(mocker):
 | 
					def get_aliases(mocker):
 | 
				
			||||||
    mocker.patch('thefuck.shells.shell.get_aliases',
 | 
					    mocker.patch('thefuck.shells.shell.get_aliases',
 | 
				
			||||||
@@ -64,6 +76,24 @@ def test_get_all_executables():
 | 
				
			|||||||
    assert 'fuck' not in all_callables
 | 
					    assert 'fuck' not in all_callables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture
 | 
				
			||||||
 | 
					def os_environ_pathsep(monkeypatch, path, pathsep):
 | 
				
			||||||
 | 
					    env = {'PATH': path}
 | 
				
			||||||
 | 
					    monkeypatch.setattr('os.environ', env)
 | 
				
			||||||
 | 
					    monkeypatch.setattr('os.pathsep', pathsep)
 | 
				
			||||||
 | 
					    return env
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.usefixtures('no_memoize', 'os_environ_pathsep')
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('path, pathsep', [
 | 
				
			||||||
 | 
					    ('/foo:/bar:/baz:/foo/bar', ':'),
 | 
				
			||||||
 | 
					    (r'C:\\foo;C:\\bar;C:\\baz;C:\\foo\\bar', ';')])
 | 
				
			||||||
 | 
					def test_get_all_executables_pathsep(path, pathsep):
 | 
				
			||||||
 | 
					    with patch('thefuck.utils.Path') as Path_mock:
 | 
				
			||||||
 | 
					        get_all_executables()
 | 
				
			||||||
 | 
					        Path_mock.assert_has_calls([call(p) for p in path.split(pathsep)], True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('args, result', [
 | 
					@pytest.mark.parametrize('args, result', [
 | 
				
			||||||
    (('apt-get instol vim', 'instol', 'install'), 'apt-get install vim'),
 | 
					    (('apt-get instol vim', 'instol', 'install'), 'apt-get install vim'),
 | 
				
			||||||
    (('git brnch', 'brnch', 'branch'), 'git branch')])
 | 
					    (('git brnch', 'brnch', 'branch'), 'git branch')])
 | 
				
			||||||
@@ -195,9 +225,12 @@ class TestGetValidHistoryWithoutCurrent(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @pytest.fixture(autouse=True)
 | 
					    @pytest.fixture(autouse=True)
 | 
				
			||||||
    def history(self, mocker):
 | 
					    def history(self, mocker):
 | 
				
			||||||
        return mocker.patch('thefuck.shells.shell.get_history',
 | 
					        mock = mocker.patch('thefuck.shells.shell.get_history')
 | 
				
			||||||
                            return_value=['le cat', 'fuck', 'ls cat',
 | 
					        #  Passing as an argument causes `UnicodeDecodeError`
 | 
				
			||||||
                                          'diff x', 'nocommand x', u'café ô'])
 | 
					        #  with newer py.test and python 2.7
 | 
				
			||||||
 | 
					        mock.return_value = ['le cat', 'fuck', 'ls cat',
 | 
				
			||||||
 | 
					                             'diff x', 'nocommand x', u'café ô']
 | 
				
			||||||
 | 
					        return mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @pytest.fixture(autouse=True)
 | 
					    @pytest.fixture(autouse=True)
 | 
				
			||||||
    def alias(self, mocker):
 | 
					    def alias(self, mocker):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,7 +55,7 @@ class Parser(object):
 | 
				
			|||||||
        """It's too dangerous to use `-y` and `-r` together."""
 | 
					        """It's too dangerous to use `-y` and `-r` together."""
 | 
				
			||||||
        group = self._parser.add_mutually_exclusive_group()
 | 
					        group = self._parser.add_mutually_exclusive_group()
 | 
				
			||||||
        group.add_argument(
 | 
					        group.add_argument(
 | 
				
			||||||
            '-y', '--yes',
 | 
					            '-y', '--yes', '--yeah', '--hard',
 | 
				
			||||||
            action='store_true',
 | 
					            action='store_true',
 | 
				
			||||||
            help='execute fixed command without confirmation')
 | 
					            help='execute fixed command without confirmation')
 | 
				
			||||||
        group.add_argument(
 | 
					        group.add_argument(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -95,7 +95,8 @@ class Settings(dict):
 | 
				
			|||||||
            return self._rules_from_env(val)
 | 
					            return self._rules_from_env(val)
 | 
				
			||||||
        elif attr == 'priority':
 | 
					        elif attr == 'priority':
 | 
				
			||||||
            return dict(self._priority_from_env(val))
 | 
					            return dict(self._priority_from_env(val))
 | 
				
			||||||
        elif attr in ('wait_command', 'history_limit', 'wait_slow_command'):
 | 
					        elif attr in ('wait_command', 'history_limit', 'wait_slow_command',
 | 
				
			||||||
 | 
					                      'num_close_matches'):
 | 
				
			||||||
            return int(val)
 | 
					            return int(val)
 | 
				
			||||||
        elif attr in ('require_confirmation', 'no_colors', 'debug',
 | 
					        elif attr in ('require_confirmation', 'no_colors', 'debug',
 | 
				
			||||||
                      'alter_history', 'instant_mode'):
 | 
					                      'alter_history', 'instant_mode'):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,7 @@ DEFAULT_SETTINGS = {'rules': DEFAULT_RULES,
 | 
				
			|||||||
                                      './gradlew', 'vagrant'],
 | 
					                                      './gradlew', 'vagrant'],
 | 
				
			||||||
                    'repeat': False,
 | 
					                    'repeat': False,
 | 
				
			||||||
                    'instant_mode': False,
 | 
					                    'instant_mode': False,
 | 
				
			||||||
 | 
					                    'num_close_matches': 3,
 | 
				
			||||||
                    'env': {'LC_ALL': 'C', 'LANG': 'C', 'GIT_TRACE': '1'}}
 | 
					                    'env': {'LC_ALL': 'C', 'LANG': 'C', 'GIT_TRACE': '1'}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ENV_TO_ATTR = {'THEFUCK_RULES': 'rules',
 | 
					ENV_TO_ATTR = {'THEFUCK_RULES': 'rules',
 | 
				
			||||||
@@ -56,7 +57,8 @@ ENV_TO_ATTR = {'THEFUCK_RULES': 'rules',
 | 
				
			|||||||
               'THEFUCK_WAIT_SLOW_COMMAND': 'wait_slow_command',
 | 
					               'THEFUCK_WAIT_SLOW_COMMAND': 'wait_slow_command',
 | 
				
			||||||
               'THEFUCK_SLOW_COMMANDS': 'slow_commands',
 | 
					               'THEFUCK_SLOW_COMMANDS': 'slow_commands',
 | 
				
			||||||
               'THEFUCK_REPEAT': 'repeat',
 | 
					               'THEFUCK_REPEAT': 'repeat',
 | 
				
			||||||
               'THEFUCK_INSTANT_MODE': 'instant_mode'}
 | 
					               'THEFUCK_INSTANT_MODE': 'instant_mode',
 | 
				
			||||||
 | 
					               'THEFUCK_NUM_CLOSE_MATCHES': 'num_close_matches'}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SETTINGS_HEADER = u"""# The Fuck settings file
 | 
					SETTINGS_HEADER = u"""# The Fuck settings file
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
@@ -81,3 +83,7 @@ LOG_SIZE_IN_BYTES = 1024 * 1024
 | 
				
			|||||||
LOG_SIZE_TO_CLEAN = 10 * 1024
 | 
					LOG_SIZE_TO_CLEAN = 10 * 1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DIFF_WITH_ALIAS = 0.5
 | 
					DIFF_WITH_ALIAS = 0.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SHELL_LOGGER_SOCKET_ENV = 'SHELL_LOGGER_SOCKET'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SHELL_LOGGER_LIMIT = 5
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import sys  # noqa: E402
 | 
				
			|||||||
from .. import logs  # noqa: E402
 | 
					from .. import logs  # noqa: E402
 | 
				
			||||||
from ..argument_parser import Parser  # noqa: E402
 | 
					from ..argument_parser import Parser  # noqa: E402
 | 
				
			||||||
from ..utils import get_installation_info  # noqa: E402
 | 
					from ..utils import get_installation_info  # noqa: E402
 | 
				
			||||||
 | 
					from ..shells import shell  # noqa: E402
 | 
				
			||||||
from .alias import print_alias  # noqa: E402
 | 
					from .alias import print_alias  # noqa: E402
 | 
				
			||||||
from .fix_command import fix_command  # noqa: E402
 | 
					from .fix_command import fix_command  # noqa: E402
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,11 +21,14 @@ def main():
 | 
				
			|||||||
        parser.print_help()
 | 
					        parser.print_help()
 | 
				
			||||||
    elif known_args.version:
 | 
					    elif known_args.version:
 | 
				
			||||||
        logs.version(get_installation_info().version,
 | 
					        logs.version(get_installation_info().version,
 | 
				
			||||||
                     sys.version.split()[0])
 | 
					                     sys.version.split()[0], shell.info())
 | 
				
			||||||
    elif known_args.command or 'TF_HISTORY' in os.environ:
 | 
					    # It's important to check if an alias is being requested before checking if
 | 
				
			||||||
        fix_command(known_args)
 | 
					    # `TF_HISTORY` is in `os.environ`, otherwise it might mess with subshells.
 | 
				
			||||||
 | 
					    # Check https://github.com/nvbn/thefuck/issues/921 for reference
 | 
				
			||||||
    elif known_args.alias:
 | 
					    elif known_args.alias:
 | 
				
			||||||
        print_alias(known_args)
 | 
					        print_alias(known_args)
 | 
				
			||||||
 | 
					    elif known_args.command or 'TF_HISTORY' in os.environ:
 | 
				
			||||||
 | 
					        fix_command(known_args)
 | 
				
			||||||
    elif known_args.shell_logger:
 | 
					    elif known_args.shell_logger:
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            from .shell_logger import shell_logger  # noqa: E402
 | 
					            from .shell_logger import shell_logger  # noqa: E402
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -106,7 +106,7 @@ def how_to_configure_alias(configuration_details):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if configuration_details.can_configure_automatically:
 | 
					        if configuration_details.can_configure_automatically:
 | 
				
			||||||
            print(
 | 
					            print(
 | 
				
			||||||
                u"Or run {bold}fuck{reset} second time for configuring"
 | 
					                u"Or run {bold}fuck{reset} a second time to configure"
 | 
				
			||||||
                u" it automatically.".format(
 | 
					                u" it automatically.".format(
 | 
				
			||||||
                    bold=color(colorama.Style.BRIGHT),
 | 
					                    bold=color(colorama.Style.BRIGHT),
 | 
				
			||||||
                    reset=color(colorama.Style.RESET_ALL)))
 | 
					                    reset=color(colorama.Style.RESET_ALL)))
 | 
				
			||||||
@@ -134,7 +134,8 @@ def configured_successfully(configuration_details):
 | 
				
			|||||||
            reload=configuration_details.reload))
 | 
					            reload=configuration_details.reload))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def version(thefuck_version, python_version):
 | 
					def version(thefuck_version, python_version, shell_info):
 | 
				
			||||||
    sys.stderr.write(
 | 
					    sys.stderr.write(
 | 
				
			||||||
        u'The Fuck {} using Python {}\n'.format(thefuck_version,
 | 
					        u'The Fuck {} using Python {} and {}\n'.format(thefuck_version,
 | 
				
			||||||
                                                python_version))
 | 
					                                                       python_version,
 | 
				
			||||||
 | 
					                                                       shell_info))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
from ..conf import settings
 | 
					from ..conf import settings
 | 
				
			||||||
from . import read_log, rerun
 | 
					from . import read_log, rerun, shell_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_output(script, expanded):
 | 
					def get_output(script, expanded):
 | 
				
			||||||
@@ -12,6 +12,8 @@ def get_output(script, expanded):
 | 
				
			|||||||
    :rtype: str
 | 
					    :rtype: str
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					    if shell_logger.is_available():
 | 
				
			||||||
 | 
					        return shell_logger.get_output(script)
 | 
				
			||||||
    if settings.instant_mode:
 | 
					    if settings.instant_mode:
 | 
				
			||||||
        return read_log.get_output(script)
 | 
					        return read_log.get_output(script)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,25 @@
 | 
				
			|||||||
import os
 | 
					import os
 | 
				
			||||||
import shlex
 | 
					import shlex
 | 
				
			||||||
from subprocess import Popen, PIPE, STDOUT
 | 
					from subprocess import Popen, PIPE, STDOUT
 | 
				
			||||||
from psutil import Process, TimeoutExpired
 | 
					from psutil import AccessDenied, Process, TimeoutExpired
 | 
				
			||||||
from .. import logs
 | 
					from .. import logs
 | 
				
			||||||
from ..conf import settings
 | 
					from ..conf import settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _kill_process(proc):
 | 
				
			||||||
 | 
					    """Tries to kill the process otherwise just logs a debug message, the
 | 
				
			||||||
 | 
					    process will be killed when thefuck terminates.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    :type proc: Process
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        proc.kill()
 | 
				
			||||||
 | 
					    except AccessDenied:
 | 
				
			||||||
 | 
					        logs.debug(u'Rerun: process PID {} ({}) could not be terminated'.format(
 | 
				
			||||||
 | 
					            proc.pid, proc.exe()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _wait_output(popen, is_slow):
 | 
					def _wait_output(popen, is_slow):
 | 
				
			||||||
    """Returns `True` if we can get output of the command in the
 | 
					    """Returns `True` if we can get output of the command in the
 | 
				
			||||||
    `settings.wait_command` time.
 | 
					    `settings.wait_command` time.
 | 
				
			||||||
@@ -23,8 +37,8 @@ def _wait_output(popen, is_slow):
 | 
				
			|||||||
        return True
 | 
					        return True
 | 
				
			||||||
    except TimeoutExpired:
 | 
					    except TimeoutExpired:
 | 
				
			||||||
        for child in proc.children(recursive=True):
 | 
					        for child in proc.children(recursive=True):
 | 
				
			||||||
            child.kill()
 | 
					            _kill_process(child)
 | 
				
			||||||
        proc.kill()
 | 
					        _kill_process(proc)
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,8 +53,9 @@ def get_output(script, expanded):
 | 
				
			|||||||
    env = dict(os.environ)
 | 
					    env = dict(os.environ)
 | 
				
			||||||
    env.update(settings.env)
 | 
					    env.update(settings.env)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    is_slow = shlex.split(expanded) in settings.slow_commands
 | 
					    split_expand = shlex.split(expanded)
 | 
				
			||||||
    with logs.debug_time(u'Call: {}; with env: {}; is slow: '.format(
 | 
					    is_slow = split_expand[0] in settings.slow_commands if split_expand else False
 | 
				
			||||||
 | 
					    with logs.debug_time(u'Call: {}; with env: {}; is slow: {}'.format(
 | 
				
			||||||
            script, env, is_slow)):
 | 
					            script, env, is_slow)):
 | 
				
			||||||
        result = Popen(expanded, shell=True, stdin=PIPE,
 | 
					        result = Popen(expanded, shell=True, stdin=PIPE,
 | 
				
			||||||
                       stdout=PIPE, stderr=STDOUT, env=env)
 | 
					                       stdout=PIPE, stderr=STDOUT, env=env)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										60
									
								
								thefuck/output_readers/shell_logger.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								thefuck/output_readers/shell_logger.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					import json
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import socket
 | 
				
			||||||
 | 
					try:
 | 
				
			||||||
 | 
					    from shutil import get_terminal_size
 | 
				
			||||||
 | 
					except ImportError:
 | 
				
			||||||
 | 
					    from backports.shutil_get_terminal_size import get_terminal_size
 | 
				
			||||||
 | 
					import pyte
 | 
				
			||||||
 | 
					from .. import const, logs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _get_socket_path():
 | 
				
			||||||
 | 
					    return os.environ.get(const.SHELL_LOGGER_SOCKET_ENV)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def is_available():
 | 
				
			||||||
 | 
					    """Returns `True` if shell logger socket available.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    :rtype: book
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    path = _get_socket_path()
 | 
				
			||||||
 | 
					    if not path:
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return os.path.exists(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _get_last_n(n):
 | 
				
			||||||
 | 
					    with socket.socket(socket.AF_UNIX) as client:
 | 
				
			||||||
 | 
					        client.connect(_get_socket_path())
 | 
				
			||||||
 | 
					        request = json.dumps({
 | 
				
			||||||
 | 
					            "type": "list",
 | 
				
			||||||
 | 
					            "count": n,
 | 
				
			||||||
 | 
					        }) + '\n'
 | 
				
			||||||
 | 
					        client.sendall(request.encode('utf-8'))
 | 
				
			||||||
 | 
					        response = client.makefile().readline()
 | 
				
			||||||
 | 
					        return json.loads(response)['commands']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _get_output_lines(output):
 | 
				
			||||||
 | 
					    lines = output.split('\n')
 | 
				
			||||||
 | 
					    screen = pyte.Screen(get_terminal_size().columns, len(lines))
 | 
				
			||||||
 | 
					    stream = pyte.Stream(screen)
 | 
				
			||||||
 | 
					    stream.feed('\n'.join(lines))
 | 
				
			||||||
 | 
					    return screen.display
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_output(script):
 | 
				
			||||||
 | 
					    """Gets command output from shell logger."""
 | 
				
			||||||
 | 
					    with logs.debug_time(u'Read output from external shell logger'):
 | 
				
			||||||
 | 
					        commands = _get_last_n(const.SHELL_LOGGER_LIMIT)
 | 
				
			||||||
 | 
					        for command in commands:
 | 
				
			||||||
 | 
					            if command['command'] == script:
 | 
				
			||||||
 | 
					                lines = _get_output_lines(command['output'])
 | 
				
			||||||
 | 
					                output = '\n'.join(lines).strip()
 | 
				
			||||||
 | 
					                return output
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                logs.warn("Output isn't available in shell logger")
 | 
				
			||||||
 | 
					                return None
 | 
				
			||||||
@@ -6,8 +6,8 @@ from thefuck.utils import for_app, eager, replace_command
 | 
				
			|||||||
enabled_by_default = apt_available
 | 
					enabled_by_default = apt_available
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@for_app('apt', 'apt-get', 'apt-cache')
 | 
					 | 
				
			||||||
@sudo_support
 | 
					@sudo_support
 | 
				
			||||||
 | 
					@for_app('apt', 'apt-get', 'apt-cache')
 | 
				
			||||||
def match(command):
 | 
					def match(command):
 | 
				
			||||||
    return 'E: Invalid operation' in command.output
 | 
					    return 'E: Invalid operation' in command.output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,7 +34,8 @@ def _parse_apt_get_and_cache_operations(help_text_lines):
 | 
				
			|||||||
                return
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            yield line.split()[0]
 | 
					            yield line.split()[0]
 | 
				
			||||||
        elif line.startswith('Commands:'):
 | 
					        elif line.startswith('Commands:') \
 | 
				
			||||||
 | 
					                or line.startswith('Most used commands:'):
 | 
				
			||||||
            is_commands_list = True
 | 
					            is_commands_list = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,5 +54,10 @@ def _get_operations(app):
 | 
				
			|||||||
@sudo_support
 | 
					@sudo_support
 | 
				
			||||||
def get_new_command(command):
 | 
					def get_new_command(command):
 | 
				
			||||||
    invalid_operation = command.output.split()[-1]
 | 
					    invalid_operation = command.output.split()[-1]
 | 
				
			||||||
    operations = _get_operations(command.script_parts[0])
 | 
					
 | 
				
			||||||
    return replace_command(command, invalid_operation, operations)
 | 
					    if invalid_operation == 'uninstall':
 | 
				
			||||||
 | 
					        return [command.script.replace('uninstall', 'remove')]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        operations = _get_operations(command.script_parts[0])
 | 
				
			||||||
 | 
					        return replace_command(command, invalid_operation, operations)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@ enabled_by_default = apt_available
 | 
				
			|||||||
@sudo_support
 | 
					@sudo_support
 | 
				
			||||||
@for_app('apt')
 | 
					@for_app('apt')
 | 
				
			||||||
def match(command):
 | 
					def match(command):
 | 
				
			||||||
    return "Run 'apt list --upgradable' to see them." in command.output
 | 
					    return 'apt list --upgradable' in command.output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@sudo_support
 | 
					@sudo_support
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ import re
 | 
				
			|||||||
from thefuck.utils import for_app, replace_argument
 | 
					from thefuck.utils import for_app, replace_argument
 | 
				
			||||||
 | 
					
 | 
				
			||||||
INVALID_CHOICE = "(?<=Invalid choice: ')(.*)(?=', maybe you meant:)"
 | 
					INVALID_CHOICE = "(?<=Invalid choice: ')(.*)(?=', maybe you meant:)"
 | 
				
			||||||
OPTIONS = "^\s*\*\s(.*)"
 | 
					OPTIONS = "^\\s*\\*\\s(.*)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@for_app('aws')
 | 
					@for_app('aws')
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								thefuck/rules/az_cli.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								thefuck/rules/az_cli.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from thefuck.utils import for_app, replace_argument
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INVALID_CHOICE = "(?=az)(?:.*): '(.*)' is not in the '.*' command group."
 | 
				
			||||||
 | 
					OPTIONS = "^The most similar choice to '.*' is:\n\\s*(.*)$"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@for_app('az')
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return "is not in the" in command.output and "command group" in command.output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    mistake = re.search(INVALID_CHOICE, command.output).group(1)
 | 
				
			||||||
 | 
					    options = re.findall(OPTIONS, command.output, flags=re.MULTILINE)
 | 
				
			||||||
 | 
					    return [replace_argument(command.script, mistake, o) for o in options]
 | 
				
			||||||
@@ -20,7 +20,7 @@ def _get_formulas():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _get_similar_formula(formula_name):
 | 
					def _get_similar_formula(formula_name):
 | 
				
			||||||
    return get_closest(formula_name, _get_formulas(), 1, 0.85)
 | 
					    return get_closest(formula_name, _get_formulas(), cutoff=0.85)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def match(command):
 | 
					def match(command):
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								thefuck/rules/brew_reinstall.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								thefuck/rules/brew_reinstall.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import re
 | 
				
			||||||
 | 
					from thefuck.utils import for_app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					warning_regex = re.compile(r'Warning: (?:.(?!is ))+ is already installed and '
 | 
				
			||||||
 | 
					                           r'up-to-date')
 | 
				
			||||||
 | 
					message_regex = re.compile(r'To reinstall (?:(?!, ).)+, run `brew reinstall '
 | 
				
			||||||
 | 
					                           r'[^`]+`')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@for_app('brew', at_least=2)
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return ('install' in command.script
 | 
				
			||||||
 | 
					            and warning_regex.search(command.output)
 | 
				
			||||||
 | 
					            and message_regex.search(command.output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    return command.script.replace('install', 'reinstall')
 | 
				
			||||||
							
								
								
									
										14
									
								
								thefuck/rules/cat_dir.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								thefuck/rules/cat_dir.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					import os
 | 
				
			||||||
 | 
					from thefuck.utils import for_app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@for_app('cat', at_least=1)
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        command.output.startswith('cat: ') and
 | 
				
			||||||
 | 
					        os.path.isdir(command.script_parts[1])
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    return command.script.replace('cat', 'ls', 1)
 | 
				
			||||||
@@ -2,10 +2,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import six
 | 
					import six
 | 
				
			||||||
from difflib import get_close_matches
 | 
					 | 
				
			||||||
from thefuck.specific.sudo import sudo_support
 | 
					from thefuck.specific.sudo import sudo_support
 | 
				
			||||||
from thefuck.rules import cd_mkdir
 | 
					from thefuck.rules import cd_mkdir
 | 
				
			||||||
from thefuck.utils import for_app
 | 
					from thefuck.utils import for_app, get_close_matches
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__author__ = "mmussomele"
 | 
					__author__ = "mmussomele"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										25
									
								
								thefuck/rules/choco_install.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								thefuck/rules/choco_install.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					from thefuck.utils import for_app, which
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@for_app("choco", "cinst")
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return ((command.script.startswith('choco install') or 'cinst' in command.script_parts)
 | 
				
			||||||
 | 
					            and 'Installing the following packages' in command.output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    # Find the argument that is the package name
 | 
				
			||||||
 | 
					    for script_part in command.script_parts:
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					            script_part not in ["choco", "cinst", "install"]
 | 
				
			||||||
 | 
					            # Need exact match (bc chocolatey is a package)
 | 
				
			||||||
 | 
					            and not script_part.startswith('-')
 | 
				
			||||||
 | 
					            # Leading hyphens are parameters; some packages contain them though
 | 
				
			||||||
 | 
					            and '=' not in script_part and '/' not in script_part
 | 
				
			||||||
 | 
					            # These are certainly parameters
 | 
				
			||||||
 | 
					        ):
 | 
				
			||||||
 | 
					            return command.script.replace(script_part, script_part + ".install")
 | 
				
			||||||
 | 
					    return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enabled_by_default = bool(which("choco")) or bool(which("cinst"))
 | 
				
			||||||
							
								
								
									
										15
									
								
								thefuck/rules/cp_create_destination.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								thefuck/rules/cp_create_destination.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					from thefuck.shells import shell
 | 
				
			||||||
 | 
					from thefuck.utils import for_app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@for_app("cp", "mv")
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        "No such file or directory" in command.output
 | 
				
			||||||
 | 
					        or command.output.startswith("cp: directory")
 | 
				
			||||||
 | 
					        and command.output.rstrip().endswith("does not exist")
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    return shell.and_(u"mkdir -p {}".format(command.script_parts[-1]), command.script)
 | 
				
			||||||
@@ -8,8 +8,8 @@ from thefuck.specific.dnf import dnf_available
 | 
				
			|||||||
regex = re.compile(r'No such command: (.*)\.')
 | 
					regex = re.compile(r'No such command: (.*)\.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@for_app('dnf')
 | 
					 | 
				
			||||||
@sudo_support
 | 
					@sudo_support
 | 
				
			||||||
 | 
					@for_app('dnf')
 | 
				
			||||||
def match(command):
 | 
					def match(command):
 | 
				
			||||||
    return 'no such command' in command.output.lower()
 | 
					    return 'no such command' in command.output.lower()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								thefuck/rules/docker_image_being_used_by_container.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								thefuck/rules/docker_image_being_used_by_container.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					from thefuck.utils import for_app
 | 
				
			||||||
 | 
					from thefuck.shells import shell
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@for_app('docker')
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    '''
 | 
				
			||||||
 | 
					    Matches a command's output with docker's output
 | 
				
			||||||
 | 
					    warning you that you need to remove a container before removing an image.
 | 
				
			||||||
 | 
					    '''
 | 
				
			||||||
 | 
					    return 'image is being used by running container' in command.output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    '''
 | 
				
			||||||
 | 
					    Prepends docker container rm -f {container ID} to
 | 
				
			||||||
 | 
					    the previous docker image rm {image ID} command
 | 
				
			||||||
 | 
					    '''
 | 
				
			||||||
 | 
					    container_id = command.output.strip().split(' ')
 | 
				
			||||||
 | 
					    return shell.and_('docker container rm -f {}', '{}').format(container_id[-1], command.script)
 | 
				
			||||||
							
								
								
									
										12
									
								
								thefuck/rules/docker_login.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								thefuck/rules/docker_login.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					from thefuck.utils import for_app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@for_app('docker')
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return ('docker' in command.script
 | 
				
			||||||
 | 
					            and "access denied" in command.output
 | 
				
			||||||
 | 
					            and "may require 'docker login'" in command.output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    return 'docker login && {}'.format(command.script)
 | 
				
			||||||
@@ -8,16 +8,30 @@ from thefuck.specific.sudo import sudo_support
 | 
				
			|||||||
@sudo_support
 | 
					@sudo_support
 | 
				
			||||||
@for_app('docker')
 | 
					@for_app('docker')
 | 
				
			||||||
def match(command):
 | 
					def match(command):
 | 
				
			||||||
    return 'is not a docker command' in command.output
 | 
					    return 'is not a docker command' in command.output or 'Usage:	docker' in command.output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _parse_commands(lines, starts_with):
 | 
				
			||||||
 | 
					    lines = dropwhile(lambda line: not line.startswith(starts_with), lines)
 | 
				
			||||||
 | 
					    lines = islice(lines, 1, None)
 | 
				
			||||||
 | 
					    lines = list(takewhile(lambda line: line.strip(), lines))
 | 
				
			||||||
 | 
					    return [line.strip().split(' ')[0] for line in lines]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_docker_commands():
 | 
					def get_docker_commands():
 | 
				
			||||||
    proc = subprocess.Popen('docker', stdout=subprocess.PIPE)
 | 
					    proc = subprocess.Popen('docker', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 | 
				
			||||||
    lines = [line.decode('utf-8') for line in proc.stdout.readlines()]
 | 
					
 | 
				
			||||||
    lines = dropwhile(lambda line: not line.startswith('Commands:'), lines)
 | 
					    # Old version docker returns its output to stdout, while newer version returns to stderr.
 | 
				
			||||||
    lines = islice(lines, 1, None)
 | 
					    lines = proc.stdout.readlines() or proc.stderr.readlines()
 | 
				
			||||||
    lines = list(takewhile(lambda line: line != '\n', lines))
 | 
					    lines = [line.decode('utf-8') for line in lines]
 | 
				
			||||||
    return [line.strip().split(' ')[0] for line in lines]
 | 
					
 | 
				
			||||||
 | 
					    # Only newer versions of docker have management commands in the help text.
 | 
				
			||||||
 | 
					    if 'Management Commands:\n' in lines:
 | 
				
			||||||
 | 
					        management_commands = _parse_commands(lines, 'Management Commands:')
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        management_commands = []
 | 
				
			||||||
 | 
					    regular_commands = _parse_commands(lines, 'Commands:')
 | 
				
			||||||
 | 
					    return management_commands + regular_commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if which('docker'):
 | 
					if which('docker'):
 | 
				
			||||||
@@ -26,6 +40,10 @@ if which('docker'):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@sudo_support
 | 
					@sudo_support
 | 
				
			||||||
def get_new_command(command):
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    if 'Usage:' in command.output and len(command.script_parts) > 1:
 | 
				
			||||||
 | 
					        management_subcommands = _parse_commands(command.output.split('\n'), 'Commands:')
 | 
				
			||||||
 | 
					        return replace_command(command, command.script_parts[2], management_subcommands)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    wrong_command = re.findall(
 | 
					    wrong_command = re.findall(
 | 
				
			||||||
        r"docker: '(\w+)' is not a docker command.", command.output)[0]
 | 
					        r"docker: '(\w+)' is not a docker command.", command.output)[0]
 | 
				
			||||||
    return replace_command(command, wrong_command, get_docker_commands())
 | 
					    return replace_command(command, wrong_command, get_docker_commands())
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								thefuck/rules/git_branch_delete_checked_out.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								thefuck/rules/git_branch_delete_checked_out.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					from thefuck.shells import shell
 | 
				
			||||||
 | 
					from thefuck.specific.git import git_support
 | 
				
			||||||
 | 
					from thefuck.utils import replace_argument
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@git_support
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        ("branch -d" in command.script or "branch -D" in command.script)
 | 
				
			||||||
 | 
					        and "error: Cannot delete branch '" in command.output
 | 
				
			||||||
 | 
					        and "' checked out at '" in command.output
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@git_support
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    return shell.and_("git checkout master", "{}").format(
 | 
				
			||||||
 | 
					        replace_argument(command.script, "-d", "-D")
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
@@ -8,7 +8,7 @@ from thefuck.shells import shell
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@git_support
 | 
					@git_support
 | 
				
			||||||
def match(command):
 | 
					def match(command):
 | 
				
			||||||
    return ('did not match any file(s) known to git.' in command.output
 | 
					    return ('did not match any file(s) known to git' in command.output
 | 
				
			||||||
            and "Did you forget to 'git add'?" not in command.output)
 | 
					            and "Did you forget to 'git add'?" not in command.output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,10 +18,12 @@ def get_branches():
 | 
				
			|||||||
        stdout=subprocess.PIPE)
 | 
					        stdout=subprocess.PIPE)
 | 
				
			||||||
    for line in proc.stdout.readlines():
 | 
					    for line in proc.stdout.readlines():
 | 
				
			||||||
        line = line.decode('utf-8')
 | 
					        line = line.decode('utf-8')
 | 
				
			||||||
 | 
					        if '->' in line:    # Remote HEAD like b'  remotes/origin/HEAD -> origin/master'
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
        if line.startswith('*'):
 | 
					        if line.startswith('*'):
 | 
				
			||||||
            line = line.split(' ')[1]
 | 
					            line = line.split(' ')[1]
 | 
				
			||||||
        if '/' in line:
 | 
					        if line.strip().startswith('remotes/'):
 | 
				
			||||||
            line = line.split('/')[-1]
 | 
					            line = '/'.join(line.split('/')[2:])
 | 
				
			||||||
        yield line.strip()
 | 
					        yield line.strip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,13 +31,19 @@ def get_branches():
 | 
				
			|||||||
def get_new_command(command):
 | 
					def get_new_command(command):
 | 
				
			||||||
    missing_file = re.findall(
 | 
					    missing_file = re.findall(
 | 
				
			||||||
        r"error: pathspec '([^']*)' "
 | 
					        r"error: pathspec '([^']*)' "
 | 
				
			||||||
        r"did not match any file\(s\) known to git.", command.output)[0]
 | 
					        r"did not match any file\(s\) known to git", command.output)[0]
 | 
				
			||||||
    closest_branch = utils.get_closest(missing_file, get_branches(),
 | 
					    closest_branch = utils.get_closest(missing_file, get_branches(),
 | 
				
			||||||
                                       fallback_to_first=False)
 | 
					                                       fallback_to_first=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    new_commands = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if closest_branch:
 | 
					    if closest_branch:
 | 
				
			||||||
        return replace_argument(command.script, missing_file, closest_branch)
 | 
					        new_commands.append(replace_argument(command.script, missing_file, closest_branch))
 | 
				
			||||||
    elif command.script_parts[1] == 'checkout':
 | 
					    if command.script_parts[1] == 'checkout':
 | 
				
			||||||
        return replace_argument(command.script, 'checkout', 'checkout -b')
 | 
					        new_commands.append(replace_argument(command.script, 'checkout', 'checkout -b'))
 | 
				
			||||||
    else:
 | 
					
 | 
				
			||||||
        return shell.and_('git branch {}', '{}').format(
 | 
					    if not new_commands:
 | 
				
			||||||
            missing_file, command.script)
 | 
					        new_commands.append(shell.and_('git branch {}', '{}').format(
 | 
				
			||||||
 | 
					            missing_file, command.script))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return new_commands
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								thefuck/rules/git_commit_reset.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								thefuck/rules/git_commit_reset.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 reset HEAD~'
 | 
				
			||||||
@@ -39,6 +39,6 @@ def get_new_command(command):
 | 
				
			|||||||
        while len(command_parts) > push_idx and command_parts[len(command_parts) - 1][0] != '-':
 | 
					        while len(command_parts) > push_idx and command_parts[len(command_parts) - 1][0] != '-':
 | 
				
			||||||
            command_parts.pop(len(command_parts) - 1)
 | 
					            command_parts.pop(len(command_parts) - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    arguments = re.findall(r'git push (.*)', command.output)[0].replace("'", r"\'").strip()
 | 
					    arguments = re.findall(r'git push (.*)', command.output)[-1].replace("'", r"\'").strip()
 | 
				
			||||||
    return replace_argument(" ".join(command_parts), 'push',
 | 
					    return replace_argument(" ".join(command_parts), 'push',
 | 
				
			||||||
                            'push {}'.format(arguments))
 | 
					                            'push {}'.format(arguments))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
from difflib import get_close_matches
 | 
					from thefuck.utils import get_close_matches
 | 
				
			||||||
from thefuck.specific.git import git_support
 | 
					from thefuck.specific.git import git_support
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										28
									
								
								thefuck/rules/go_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								thefuck/rules/go_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					from itertools import dropwhile, islice, takewhile
 | 
				
			||||||
 | 
					import subprocess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from thefuck.utils import get_closest, replace_argument, for_app, which, cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_golang_commands():
 | 
				
			||||||
 | 
					    proc = subprocess.Popen('go', stderr=subprocess.PIPE)
 | 
				
			||||||
 | 
					    lines = [line.decode('utf-8').strip() for line in proc.stderr.readlines()]
 | 
				
			||||||
 | 
					    lines = dropwhile(lambda line: line != 'The commands are:', lines)
 | 
				
			||||||
 | 
					    lines = islice(lines, 2, None)
 | 
				
			||||||
 | 
					    lines = takewhile(lambda line: line, lines)
 | 
				
			||||||
 | 
					    return [line.split(' ')[0] for line in lines]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if which('go'):
 | 
				
			||||||
 | 
					    get_docker_commands = cache(which('go'))(get_golang_commands)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@for_app('go')
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return 'unknown command' in command.output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    closest_subcommand = get_closest(command.script_parts[1], get_golang_commands())
 | 
				
			||||||
 | 
					    return replace_argument(command.script, command.script_parts[1],
 | 
				
			||||||
 | 
					                            closest_subcommand)
 | 
				
			||||||
@@ -8,5 +8,5 @@ def match(command):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_new_command(command):
 | 
					def get_new_command(command):
 | 
				
			||||||
    apps = re.findall('([^ ]*) \([^)]*\)', command.output)
 | 
					    apps = re.findall('([^ ]*) \\([^)]*\\)', command.output)
 | 
				
			||||||
    return [command.script + ' --app ' + app for app in apps]
 | 
					    return [command.script + ' --app ' + app for app in apps]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
from difflib import get_close_matches
 | 
					from thefuck.utils import get_close_matches, get_closest, \
 | 
				
			||||||
from thefuck.utils import get_closest, get_valid_history_without_current
 | 
					    get_valid_history_without_current
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def match(command):
 | 
					def match(command):
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										27
									
								
								thefuck/rules/long_form_help.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								thefuck/rules/long_form_help.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					from thefuck.utils import replace_argument
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# regex to match a suggested help command from the tool output
 | 
				
			||||||
 | 
					help_regex = r"(?:Run|Try) '([^']+)'(?: or '[^']+')? for (?:details|more information)."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    if re.search(help_regex, command.output, re.I) is not None:
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if '--help' in command.output:
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    if re.search(help_regex, command.output) is not None:
 | 
				
			||||||
 | 
					        match_obj = re.search(help_regex, command.output, re.I)
 | 
				
			||||||
 | 
					        return match_obj.group(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return replace_argument(command.script, '-h', '--help')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enabled_by_default = True
 | 
				
			||||||
 | 
					priority = 5000
 | 
				
			||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
from thefuck.utils import replace_command, for_app
 | 
					from thefuck.utils import for_app, get_close_matches, replace_command
 | 
				
			||||||
from difflib import get_close_matches
 | 
					 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,8 +24,7 @@ def get_new_command(command):
 | 
				
			|||||||
    available_lifecycles = _getavailable_lifecycles(command)
 | 
					    available_lifecycles = _getavailable_lifecycles(command)
 | 
				
			||||||
    if available_lifecycles and failed_lifecycle:
 | 
					    if available_lifecycles and failed_lifecycle:
 | 
				
			||||||
        selected_lifecycle = get_close_matches(
 | 
					        selected_lifecycle = get_close_matches(
 | 
				
			||||||
            failed_lifecycle.group(1), available_lifecycles.group(1).split(", "),
 | 
					            failed_lifecycle.group(1), available_lifecycles.group(1).split(", "))
 | 
				
			||||||
            3, 0.6)
 | 
					 | 
				
			||||||
        return replace_command(command, failed_lifecycle.group(1), selected_lifecycle)
 | 
					        return replace_command(command, failed_lifecycle.group(1), selected_lifecycle)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        return []
 | 
					        return []
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								thefuck/rules/nixos_cmd_not_found.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								thefuck/rules/nixos_cmd_not_found.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					import re
 | 
				
			||||||
 | 
					from thefuck.specific.nix import nix_available
 | 
				
			||||||
 | 
					from thefuck.shells import shell
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					regex = re.compile(r'nix-env -iA ([^\s]*)')
 | 
				
			||||||
 | 
					enabled_by_default = nix_available
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return regex.findall(command.output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    name = regex.findall(command.output)[0]
 | 
				
			||||||
 | 
					    return shell.and_('nix-env -iA {}'.format(name), command.script)
 | 
				
			||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
from difflib import get_close_matches
 | 
					from thefuck.utils import get_all_executables, get_close_matches, \
 | 
				
			||||||
from thefuck.utils import get_all_executables, \
 | 
					 | 
				
			||||||
    get_valid_history_without_current, get_closest, which
 | 
					    get_valid_history_without_current, get_closest, which
 | 
				
			||||||
from thefuck.specific.sudo import sudo_support
 | 
					from thefuck.specific.sudo import sudo_support
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -7,7 +6,8 @@ from thefuck.specific.sudo import sudo_support
 | 
				
			|||||||
@sudo_support
 | 
					@sudo_support
 | 
				
			||||||
def match(command):
 | 
					def match(command):
 | 
				
			||||||
    return (not which(command.script_parts[0])
 | 
					    return (not which(command.script_parts[0])
 | 
				
			||||||
            and 'not found' in command.output
 | 
					            and ('not found' in command.output
 | 
				
			||||||
 | 
					                 or 'is not recognized as' in command.output)
 | 
				
			||||||
            and bool(get_close_matches(command.script_parts[0],
 | 
					            and bool(get_close_matches(command.script_parts[0],
 | 
				
			||||||
                                       get_all_executables())))
 | 
					                                       get_all_executables())))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
""" Fixes wrong package names with pacman or yaourt.
 | 
					""" Fixes wrong package names with pacman or yaourt.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For example the `llc` program is in package `llvm` so this:
 | 
					For example the `llc` program is in package `llvm` so this:
 | 
				
			||||||
    yaourt -S llc
 | 
					    yay -S llc
 | 
				
			||||||
should be:
 | 
					should be:
 | 
				
			||||||
    yaourt -S llvm
 | 
					    yay -S llvm
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from thefuck.utils import replace_command
 | 
					from thefuck.utils import replace_command
 | 
				
			||||||
@@ -12,7 +12,7 @@ from thefuck.specific.archlinux import get_pkgfile, archlinux_env
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def match(command):
 | 
					def match(command):
 | 
				
			||||||
    return (command.script_parts
 | 
					    return (command.script_parts
 | 
				
			||||||
            and (command.script_parts[0] in ('pacman', 'yaourt')
 | 
					            and (command.script_parts[0] in ('pacman', 'yay', 'yaourt')
 | 
				
			||||||
                 or command.script_parts[0:2] == ['sudo', 'pacman'])
 | 
					                 or command.script_parts[0:2] == ['sudo', 'pacman'])
 | 
				
			||||||
            and 'error: target not found:' in command.output)
 | 
					            and 'error: target not found:' in command.output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								thefuck/rules/pip_install.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								thefuck/rules/pip_install.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					from thefuck.utils import for_app
 | 
				
			||||||
 | 
					from thefuck.specific.sudo import sudo_support
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@sudo_support
 | 
				
			||||||
 | 
					@for_app('pip')
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return ('pip install' in command.script and 'Permission denied' in command.output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    if '--user' not in command.script:  # add --user (attempt 1)
 | 
				
			||||||
 | 
					        return command.script.replace(' install ', ' install --user ')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 'sudo {}'.format(command.script.replace(' --user', ''))  # since --user didn't fix things, let's try sudo (attempt 2)
 | 
				
			||||||
@@ -12,8 +12,8 @@ def match(command):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_new_command(command):
 | 
					def get_new_command(command):
 | 
				
			||||||
    broken_cmd = re.findall(r'ERROR: unknown command \"([a-z]+)\"',
 | 
					    broken_cmd = re.findall(r'ERROR: unknown command "([^"]+)"',
 | 
				
			||||||
                            command.output)[0]
 | 
					                            command.output)[0]
 | 
				
			||||||
    new_cmd = re.findall(r'maybe you meant \"([a-z]+)\"', command.output)[0]
 | 
					    new_cmd = re.findall(r'maybe you meant "([^"]+)"', command.output)[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return replace_argument(command.script, broken_cmd, new_cmd)
 | 
					    return replace_argument(command.script, broken_cmd, new_cmd)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										33
									
								
								thefuck/rules/pyenv_no_such_command.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								thefuck/rules/pyenv_no_such_command.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					import re
 | 
				
			||||||
 | 
					from subprocess import PIPE, Popen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from thefuck.utils import (cache, for_app, replace_argument, replace_command,
 | 
				
			||||||
 | 
					                           which)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COMMON_TYPOS = {
 | 
				
			||||||
 | 
					    'list': ['versions', 'install --list'],
 | 
				
			||||||
 | 
					    'remove': ['uninstall'],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@for_app('pyenv')
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return 'pyenv: no such command' in command.output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_pyenv_commands():
 | 
				
			||||||
 | 
					    proc = Popen(['pyenv', 'commands'], stdout=PIPE)
 | 
				
			||||||
 | 
					    return [line.decode('utf-8').strip() for line in proc.stdout.readlines()]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if which('pyenv'):
 | 
				
			||||||
 | 
					    get_pyenv_commands = cache(which('pyenv'))(get_pyenv_commands)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@for_app('pyenv')
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    broken = re.findall(r"pyenv: no such command `([^']*)'", command.output)[0]
 | 
				
			||||||
 | 
					    matched = [replace_argument(command.script, broken, common_typo)
 | 
				
			||||||
 | 
					               for common_typo in COMMON_TYPOS.get(broken, [])]
 | 
				
			||||||
 | 
					    matched.extend(replace_command(command, broken, get_pyenv_commands()))
 | 
				
			||||||
 | 
					    return matched
 | 
				
			||||||
							
								
								
									
										22
									
								
								thefuck/rules/remove_shell_prompt_literal.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								thefuck/rules/remove_shell_prompt_literal.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					"""Fixes error for commands containing the shell prompt symbol '$'.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This usually happens when commands are copied from documentations
 | 
				
			||||||
 | 
					including them in their code blocks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Example:
 | 
				
			||||||
 | 
					> $ git clone https://github.com/nvbn/thefuck.git
 | 
				
			||||||
 | 
					bash: $: command not found...
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        "$: command not found" in command.output
 | 
				
			||||||
 | 
					        and re.search(r"^[\s]*\$ [\S]+", command.script) is not None
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    return command.script.replace("$", "", 1).strip()
 | 
				
			||||||
@@ -21,7 +21,7 @@ patterns = ['permission denied',
 | 
				
			|||||||
            'edspermissionerror',
 | 
					            'edspermissionerror',
 | 
				
			||||||
            'you don\'t have write permissions',
 | 
					            'you don\'t have write permissions',
 | 
				
			||||||
            'use `sudo`',
 | 
					            'use `sudo`',
 | 
				
			||||||
            'SudoRequiredError',
 | 
					            'sudorequirederror',
 | 
				
			||||||
            'error: insufficient privileges']
 | 
					            'error: insufficient privileges']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,42 +2,116 @@
 | 
				
			|||||||
from thefuck.utils import memoize, get_alias
 | 
					from thefuck.utils import memoize, get_alias
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_layout = '''qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?'''
 | 
					target_layout = '''qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?'''
 | 
				
			||||||
 | 
					# any new keyboard layout must be appended
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					greek = u''';ςερτυθιοπ[]ασδφγηξκλ΄ζχψωβνμ,./:΅ΕΡΤΥΘΙΟΠ{}ΑΣΔΦΓΗΞΚΛ¨"ΖΧΨΩΒΝΜ<>?'''
 | 
				
			||||||
 | 
					korean = u'''ㅂㅈㄷㄱㅅㅛㅕㅑㅐㅔ[]ㅁㄴㅇㄹㅎㅗㅓㅏㅣ;'ㅋㅌㅊㅍㅠㅜㅡ,./ㅃㅉㄸㄲㅆㅛㅕㅑㅒㅖ{}ㅁㄴㅇㄹㅎㅗㅓㅏㅣ:"ㅋㅌㅊㅍㅠㅜㅡ<>?'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
source_layouts = [u'''йцукенгшщзхъфывапролджэячсмитьбю.ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,''',
 | 
					source_layouts = [u'''йцукенгшщзхъфывапролджэячсмитьбю.ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,''',
 | 
				
			||||||
 | 
					                  u'''йцукенгшщзхїфівапролджєячсмитьбю.ЙЦУКЕНГШЩЗХЇФІВАПРОЛДЖЄЯЧСМИТЬБЮ,''',
 | 
				
			||||||
                  u'''ضصثقفغعهخحجچشسیبلاتنمکگظطزرذدپو./ًٌٍَُِّْ][}{ؤئيإأآة»«:؛كٓژٰٔء><؟''',
 | 
					                  u'''ضصثقفغعهخحجچشسیبلاتنمکگظطزرذدپو./ًٌٍَُِّْ][}{ؤئيإأآة»«:؛كٓژٰٔء><؟''',
 | 
				
			||||||
                  u''';ςερτυθιοπ[]ασδφγηξκλ΄ζχψωβνμ,./:΅ΕΡΤΥΘΙΟΠ{}ΑΣΔΦΓΗΞΚΛ¨"ΖΧΨΩΒΝΜ<>?''',
 | 
					                  u'''/'קראטוןםפ][שדגכעיחלךף,זסבהנמצתץ.QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?''',
 | 
				
			||||||
                  u'''/'קראטוןםפ][שדגכעיחלךף,זסבהנמצתץ.QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?''']
 | 
					                  greek,
 | 
				
			||||||
 | 
					                  korean]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					source_to_target = {
 | 
				
			||||||
 | 
					    greek: {u';': "q", u'ς': "w", u'ε': "e", u'ρ': "r", u'τ': "t", u'υ': "y",
 | 
				
			||||||
 | 
					            u'θ': "u", u'ι': "i", u'ο': "o", u'π': "p", u'[': "[", u']': "]",
 | 
				
			||||||
 | 
					            u'α': "a", u'σ': "s", u'δ': "d", u'φ': "f", u'γ': "g", u'η': "h",
 | 
				
			||||||
 | 
					            u'ξ': "j", u'κ': "k", u'λ': "l", u'΄': "'", u'ζ': "z", u'χ': "x",
 | 
				
			||||||
 | 
					            u'ψ': "c", u'ω': "v", u'β': "b", u'ν': "n", u'μ': "m", u',': ",",
 | 
				
			||||||
 | 
					            u'.': ".", u'/': "/", u':': "Q", u'΅': "W", u'Ε': "E", u'Ρ': "R",
 | 
				
			||||||
 | 
					            u'Τ': "T", u'Υ': "Y", u'Θ': "U", u'Ι': "I", u'Ο': "O", u'Π': "P",
 | 
				
			||||||
 | 
					            u'{': "{", u'}': "}", u'Α': "A", u'Σ': "S", u'Δ': "D", u'Φ': "F",
 | 
				
			||||||
 | 
					            u'Γ': "G", u'Η': "H", u'Ξ': "J", u'Κ': "K", u'Λ': "L", u'¨': ":",
 | 
				
			||||||
 | 
					            u'"': '"', u'Ζ': "Z", u'Χ': "X", u'Ψ': "C", u'Ω': "V", u'Β': "B",
 | 
				
			||||||
 | 
					            u'Ν': "N", u'Μ': "M", u'<': "<", u'>': ">", u'?': "?", u'ά': "a",
 | 
				
			||||||
 | 
					            u'έ': "e", u'ύ': "y", u'ί': "i", u'ό': "o", u'ή': 'h', u'ώ': u"v",
 | 
				
			||||||
 | 
					            u'Ά': "A", u'Έ': "E", u'Ύ': "Y", u'Ί': "I", u'Ό': "O", u'Ή': "H",
 | 
				
			||||||
 | 
					            u'Ώ': "V"},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					'''Lists used for decomposing korean letters.'''
 | 
				
			||||||
 | 
					HEAD_LIST = [u'ㄱ', u'ㄲ', u'ㄴ', u'ㄷ', u'ㄸ', u'ㄹ', u'ㅁ', u'ㅂ', u'ㅃ', u'ㅅ', u'ㅆ',
 | 
				
			||||||
 | 
					             u'ㅇ', u'ㅈ', u'ㅉ', u'ㅊ', u'ㅋ', u'ㅌ', u'ㅍ', u'ㅎ']
 | 
				
			||||||
 | 
					BODY_LIST = [u'ㅏ', u'ㅐ', u'ㅑ', u'ㅒ', u'ㅓ', u'ㅔ', u'ㅕ', u'ㅖ', u'ㅗ', u'ㅘ', u'ㅙ',
 | 
				
			||||||
 | 
					             u'ㅚ', u'ㅛ', u'ㅜ', u'ㅝ', u'ㅞ', u'ㅟ', u'ㅠ', u'ㅡ', u'ㅢ', u'ㅣ']
 | 
				
			||||||
 | 
					TAIL_LIST = [u' ', u'ㄱ', u'ㄲ', u'ㄳ', u'ㄴ', u'ㄵ', u'ㄶ', u'ㄷ', u'ㄹ', u'ㄺ', u'ㄻ',
 | 
				
			||||||
 | 
					             u'ㄼ', u'ㄽ', u'ㄾ', u'ㄿ', u'ㅀ', u'ㅁ', u'ㅂ', u'ㅄ', u'ㅅ', u'ㅆ', u'ㅇ', u'ㅈ',
 | 
				
			||||||
 | 
					             u'ㅊ', u'ㅋ', u'ㅌ', u'ㅍ', u'ㅎ']
 | 
				
			||||||
 | 
					DOUBLE_LIST = [u'ㅘ', u'ㅙ', u'ㅚ', u'ㅝ', u'ㅞ', u'ㅟ', u'ㅢ', u'ㄳ', u'ㄵ', u'ㄶ', u'ㄺ',
 | 
				
			||||||
 | 
					               u'ㄻ', u'ㄼ', u'ㄽ', u'ㄾ', u'ㅀ', u'ㅄ']
 | 
				
			||||||
 | 
					DOUBLE_MOD_LIST = [u'ㅗㅏ', u'ㅗㅐ', u'ㅗㅣ', u'ㅜㅓ', u'ㅜㅔ', u'ㅜㅣ', u'ㅡㅣ', u'ㄱㅅ',
 | 
				
			||||||
 | 
					                   u'ㄴㅈ', u'ㄴㅎ', u'ㄹㄱ', u'ㄹㅁ', u'ㄹㅂ', u'ㄹㅅ', u'ㄹㅌ', u'ㄹㅎ', u'ㅂㅅ']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@memoize
 | 
					@memoize
 | 
				
			||||||
def _get_matched_layout(command):
 | 
					def _get_matched_layout(command):
 | 
				
			||||||
    # don't use command.split_script here because a layout mismatch will likely
 | 
					    # don't use command.split_script here because a layout mismatch will likely
 | 
				
			||||||
    # result in a non-splitable sript as per shlex
 | 
					    # result in a non-splitable script as per shlex
 | 
				
			||||||
    cmd = command.script.split(' ')
 | 
					    cmd = command.script.split(' ')
 | 
				
			||||||
    for source_layout in source_layouts:
 | 
					    for source_layout in source_layouts:
 | 
				
			||||||
        if all([ch in source_layout or ch in '-_' for ch in cmd[0]]):
 | 
					        is_all_match = True
 | 
				
			||||||
 | 
					        for cmd_part in cmd:
 | 
				
			||||||
 | 
					            if not all([ch in source_layout or ch in '-_' for ch in cmd_part]):
 | 
				
			||||||
 | 
					                is_all_match = False
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if is_all_match:
 | 
				
			||||||
            return source_layout
 | 
					            return source_layout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _switch(ch, layout):
 | 
					def _switch(ch, layout):
 | 
				
			||||||
    if ch in layout:
 | 
					    if ch in layout:
 | 
				
			||||||
        return target_layout[layout.index(ch)]
 | 
					        return target_layout[layout.index(ch)]
 | 
				
			||||||
    else:
 | 
					    return ch
 | 
				
			||||||
        return ch
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _switch_command(command, layout):
 | 
					def _switch_command(command, layout):
 | 
				
			||||||
 | 
					    # Layouts with different amount of characters than English
 | 
				
			||||||
 | 
					    if layout in source_to_target:
 | 
				
			||||||
 | 
					        return ''.join(source_to_target[layout].get(ch, ch)
 | 
				
			||||||
 | 
					                       for ch in command.script)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ''.join(_switch(ch, layout) for ch in command.script)
 | 
					    return ''.join(_switch(ch, layout) for ch in command.script)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _decompose_korean(command):
 | 
				
			||||||
 | 
					    def _change_double(ch):
 | 
				
			||||||
 | 
					        if ch in DOUBLE_LIST:
 | 
				
			||||||
 | 
					            return DOUBLE_MOD_LIST[DOUBLE_LIST.index(ch)]
 | 
				
			||||||
 | 
					        return ch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    hg_str = u''
 | 
				
			||||||
 | 
					    for ch in command.script:
 | 
				
			||||||
 | 
					        if u'가' <= ch <= u'힣':
 | 
				
			||||||
 | 
					            ord_ch = ord(ch) - ord(u'가')
 | 
				
			||||||
 | 
					            hd = ord_ch // 588
 | 
				
			||||||
 | 
					            bd = (ord_ch - 588 * hd) // 28
 | 
				
			||||||
 | 
					            tl = ord_ch - 588 * hd - 28 * bd
 | 
				
			||||||
 | 
					            for ch in [HEAD_LIST[hd], BODY_LIST[bd], TAIL_LIST[tl]]:
 | 
				
			||||||
 | 
					                if ch != ' ':
 | 
				
			||||||
 | 
					                    hg_str += _change_double(ch)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            hg_str += _change_double(ch)
 | 
				
			||||||
 | 
					    return hg_str
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def match(command):
 | 
					def match(command):
 | 
				
			||||||
    if 'not found' not in command.output:
 | 
					    if 'not found' not in command.output:
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					    if any(u'ㄱ' <= ch <= u'ㅎ' or u'ㅏ' <= ch <= u'ㅣ' or u'가' <= ch <= u'힣'
 | 
				
			||||||
 | 
					            for ch in command.script):
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    matched_layout = _get_matched_layout(command)
 | 
					    matched_layout = _get_matched_layout(command)
 | 
				
			||||||
    return (matched_layout and
 | 
					    return (matched_layout and
 | 
				
			||||||
            _switch_command(command, matched_layout) != get_alias())
 | 
					            _switch_command(command, matched_layout) != get_alias())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_new_command(command):
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    if any(u'ㄱ' <= ch <= u'ㅎ' or u'ㅏ' <= ch <= u'ㅣ' or u'가' <= ch <= u'힣'
 | 
				
			||||||
 | 
					            for ch in command.script):
 | 
				
			||||||
 | 
					        command.script = _decompose_korean(command)
 | 
				
			||||||
    matched_layout = _get_matched_layout(command)
 | 
					    matched_layout = _get_matched_layout(command)
 | 
				
			||||||
    return _switch_command(command, matched_layout)
 | 
					    return _switch_command(command, matched_layout)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								thefuck/rules/terraform_init.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								thefuck/rules/terraform_init.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					from thefuck.shells import shell
 | 
				
			||||||
 | 
					from thefuck.utils import for_app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@for_app('terraform')
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return ('this module is not yet installed' in command.output.lower() or
 | 
				
			||||||
 | 
					            'initialization required' in command.output.lower()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    return shell.and_('terraform init', command.script)
 | 
				
			||||||
@@ -9,5 +9,6 @@ def match(command):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_new_command(command):
 | 
					def get_new_command(command):
 | 
				
			||||||
    path = re.findall(r"touch: cannot touch '(.+)/.+':", command.output)[0]
 | 
					    path = re.findall(
 | 
				
			||||||
 | 
					        r"touch: (?:cannot touch ')?(.+)/.+'?:", command.output)[0]
 | 
				
			||||||
    return shell.and_(u'mkdir -p {}'.format(path), command.script)
 | 
					    return shell.and_(u'mkdir -p {}'.format(path), command.script)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										39
									
								
								thefuck/rules/yum_invalid_operation.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								thefuck/rules/yum_invalid_operation.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					import subprocess
 | 
				
			||||||
 | 
					from itertools import dropwhile, islice, takewhile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from thefuck.specific.sudo import sudo_support
 | 
				
			||||||
 | 
					from thefuck.specific.yum import yum_available
 | 
				
			||||||
 | 
					from thefuck.utils import for_app, replace_command, which, cache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enabled_by_default = yum_available
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@sudo_support
 | 
				
			||||||
 | 
					@for_app('yum')
 | 
				
			||||||
 | 
					def match(command):
 | 
				
			||||||
 | 
					    return 'No such command: ' in command.output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _get_operations():
 | 
				
			||||||
 | 
					    proc = subprocess.Popen('yum', stdout=subprocess.PIPE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lines = proc.stdout.readlines()
 | 
				
			||||||
 | 
					    lines = [line.decode('utf-8') for line in lines]
 | 
				
			||||||
 | 
					    lines = dropwhile(lambda line: not line.startswith("List of Commands:"), lines)
 | 
				
			||||||
 | 
					    lines = islice(lines, 2, None)
 | 
				
			||||||
 | 
					    lines = list(takewhile(lambda line: line.strip(), lines))
 | 
				
			||||||
 | 
					    return [line.strip().split(' ')[0] for line in lines]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if which('yum'):
 | 
				
			||||||
 | 
					    _get_operations = cache(which('yum'))(_get_operations)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@sudo_support
 | 
				
			||||||
 | 
					def get_new_command(command):
 | 
				
			||||||
 | 
					    invalid_operation = command.script_parts[1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if invalid_operation == 'uninstall':
 | 
				
			||||||
 | 
					        return [command.script.replace('uninstall', 'remove')]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return replace_command(command, invalid_operation, _get_operations())
 | 
				
			||||||
@@ -16,7 +16,8 @@ shells = {'bash': Bash,
 | 
				
			|||||||
          'zsh': Zsh,
 | 
					          'zsh': Zsh,
 | 
				
			||||||
          'csh': Tcsh,
 | 
					          'csh': Tcsh,
 | 
				
			||||||
          'tcsh': Tcsh,
 | 
					          'tcsh': Tcsh,
 | 
				
			||||||
          'powershell': Powershell}
 | 
					          'powershell': Powershell,
 | 
				
			||||||
 | 
					          'pwsh': Powershell}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _get_shell_from_env():
 | 
					def _get_shell_from_env():
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,16 @@
 | 
				
			|||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					from subprocess import Popen, PIPE
 | 
				
			||||||
from tempfile import gettempdir
 | 
					from tempfile import gettempdir
 | 
				
			||||||
from uuid import uuid4
 | 
					from uuid import uuid4
 | 
				
			||||||
from ..conf import settings
 | 
					from ..conf import settings
 | 
				
			||||||
from ..const import ARGUMENT_PLACEHOLDER, USER_COMMAND_MARK
 | 
					from ..const import ARGUMENT_PLACEHOLDER, USER_COMMAND_MARK
 | 
				
			||||||
from ..utils import memoize
 | 
					from ..utils import DEVNULL, memoize
 | 
				
			||||||
from .generic import Generic
 | 
					from .generic import Generic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Bash(Generic):
 | 
					class Bash(Generic):
 | 
				
			||||||
 | 
					    friendly_name = 'Bash'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def app_alias(self, alias_name):
 | 
					    def app_alias(self, alias_name):
 | 
				
			||||||
        # It is VERY important to have the variables declared WITHIN the function
 | 
					        # It is VERY important to have the variables declared WITHIN the function
 | 
				
			||||||
        return '''
 | 
					        return '''
 | 
				
			||||||
@@ -19,8 +22,8 @@ class Bash(Generic):
 | 
				
			|||||||
                export TF_HISTORY=$(fc -ln -10);
 | 
					                export TF_HISTORY=$(fc -ln -10);
 | 
				
			||||||
                export PYTHONIOENCODING=utf-8;
 | 
					                export PYTHONIOENCODING=utf-8;
 | 
				
			||||||
                TF_CMD=$(
 | 
					                TF_CMD=$(
 | 
				
			||||||
                    thefuck {argument_placeholder} $@
 | 
					                    thefuck {argument_placeholder} "$@"
 | 
				
			||||||
                ) && eval $TF_CMD;
 | 
					                ) && eval "$TF_CMD";
 | 
				
			||||||
                unset TF_HISTORY;
 | 
					                unset TF_HISTORY;
 | 
				
			||||||
                export PYTHONIOENCODING=$TF_PYTHONIOENCODING;
 | 
					                export PYTHONIOENCODING=$TF_PYTHONIOENCODING;
 | 
				
			||||||
                {alter_history}
 | 
					                {alter_history}
 | 
				
			||||||
@@ -78,6 +81,12 @@ class Bash(Generic):
 | 
				
			|||||||
            config = 'bash config'
 | 
					            config = 'bash config'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return self._create_shell_configuration(
 | 
					        return self._create_shell_configuration(
 | 
				
			||||||
            content=u'eval $(thefuck --alias)',
 | 
					            content=u'eval "$(thefuck --alias)"',
 | 
				
			||||||
            path=config,
 | 
					            path=config,
 | 
				
			||||||
            reload=u'source {}'.format(config))
 | 
					            reload=u'source {}'.format(config))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_version(self):
 | 
				
			||||||
 | 
					        """Returns the version of the current shell"""
 | 
				
			||||||
 | 
					        proc = Popen(['bash', '-c', 'echo $BASH_VERSION'],
 | 
				
			||||||
 | 
					                     stdout=PIPE, stderr=DEVNULL)
 | 
				
			||||||
 | 
					        return proc.stdout.read().decode('utf-8').strip()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ import sys
 | 
				
			|||||||
import six
 | 
					import six
 | 
				
			||||||
from .. import logs
 | 
					from .. import logs
 | 
				
			||||||
from ..conf import settings
 | 
					from ..conf import settings
 | 
				
			||||||
 | 
					from ..const import ARGUMENT_PLACEHOLDER
 | 
				
			||||||
from ..utils import DEVNULL, cache
 | 
					from ..utils import DEVNULL, cache
 | 
				
			||||||
from .generic import Generic
 | 
					from .generic import Generic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,22 +21,32 @@ def _get_functions(overridden):
 | 
				
			|||||||
def _get_aliases(overridden):
 | 
					def _get_aliases(overridden):
 | 
				
			||||||
    aliases = {}
 | 
					    aliases = {}
 | 
				
			||||||
    proc = Popen(['fish', '-ic', 'alias'], stdout=PIPE, stderr=DEVNULL)
 | 
					    proc = Popen(['fish', '-ic', 'alias'], stdout=PIPE, stderr=DEVNULL)
 | 
				
			||||||
    alias_out = proc.stdout.read().decode('utf-8').strip().split('\n')
 | 
					    alias_out = proc.stdout.read().decode('utf-8').strip()
 | 
				
			||||||
    for alias in alias_out:
 | 
					    if not alias_out:
 | 
				
			||||||
        name, value = alias.replace('alias ', '', 1).split(' ', 1)
 | 
					        return aliases
 | 
				
			||||||
 | 
					    for alias in alias_out.split('\n'):
 | 
				
			||||||
 | 
					        for separator in (' ', '='):
 | 
				
			||||||
 | 
					            split_alias = alias.replace('alias ', '', 1).split(separator, 1)
 | 
				
			||||||
 | 
					            if len(split_alias) == 2:
 | 
				
			||||||
 | 
					                name, value = split_alias
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
        if name not in overridden:
 | 
					        if name not in overridden:
 | 
				
			||||||
            aliases[name] = value
 | 
					            aliases[name] = value
 | 
				
			||||||
    return aliases
 | 
					    return aliases
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Fish(Generic):
 | 
					class Fish(Generic):
 | 
				
			||||||
 | 
					    friendly_name = 'Fish Shell'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _get_overridden_aliases(self):
 | 
					    def _get_overridden_aliases(self):
 | 
				
			||||||
        overridden = os.environ.get('THEFUCK_OVERRIDDEN_ALIASES',
 | 
					        overridden = os.environ.get('THEFUCK_OVERRIDDEN_ALIASES',
 | 
				
			||||||
                                    os.environ.get('TF_OVERRIDDEN_ALIASES', ''))
 | 
					                                    os.environ.get('TF_OVERRIDDEN_ALIASES', ''))
 | 
				
			||||||
        default = {'cd', 'grep', 'ls', 'man', 'open'}
 | 
					        default = {'cd', 'grep', 'ls', 'man', 'open'}
 | 
				
			||||||
        for alias in overridden.split(','):
 | 
					        for alias in overridden.split(','):
 | 
				
			||||||
            default.add(alias.strip())
 | 
					            default.add(alias.strip())
 | 
				
			||||||
        return default
 | 
					        return sorted(default)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def app_alias(self, alias_name):
 | 
					    def app_alias(self, alias_name):
 | 
				
			||||||
        if settings.alter_history:
 | 
					        if settings.alter_history:
 | 
				
			||||||
@@ -48,11 +59,11 @@ class Fish(Generic):
 | 
				
			|||||||
        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_SHELL=fish 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 {2} $argv | read -l unfucked_command\n'
 | 
				
			||||||
                '  if [ "$unfucked_command" != "" ]\n'
 | 
					                '  if [ "$unfucked_command" != "" ]\n'
 | 
				
			||||||
                '    eval $unfucked_command\n{1}'
 | 
					                '    eval $unfucked_command\n{1}'
 | 
				
			||||||
                '  end\n'
 | 
					                '  end\n'
 | 
				
			||||||
                'end').format(alias_name, alter_history)
 | 
					                'end').format(alias_name, alter_history, ARGUMENT_PLACEHOLDER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_aliases(self):
 | 
					    def get_aliases(self):
 | 
				
			||||||
        overridden = self._get_overridden_aliases()
 | 
					        overridden = self._get_overridden_aliases()
 | 
				
			||||||
@@ -95,6 +106,11 @@ class Fish(Generic):
 | 
				
			|||||||
            path='~/.config/fish/config.fish',
 | 
					            path='~/.config/fish/config.fish',
 | 
				
			||||||
            reload='fish')
 | 
					            reload='fish')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_version(self):
 | 
				
			||||||
 | 
					        """Returns the version of the current shell"""
 | 
				
			||||||
 | 
					        proc = Popen(['fish', '--version'], stdout=PIPE, stderr=DEVNULL)
 | 
				
			||||||
 | 
					        return proc.stdout.read().decode('utf-8').split()[-1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def put_to_history(self, command):
 | 
					    def put_to_history(self, command):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            return self._put_to_history(command)
 | 
					            return self._put_to_history(command)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,8 @@ ShellConfiguration = namedtuple('ShellConfiguration', (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Generic(object):
 | 
					class Generic(object):
 | 
				
			||||||
 | 
					    friendly_name = 'Generic Shell'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_aliases(self):
 | 
					    def get_aliases(self):
 | 
				
			||||||
        return {}
 | 
					        return {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -34,8 +36,8 @@ class Generic(object):
 | 
				
			|||||||
        return command_script
 | 
					        return command_script
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def app_alias(self, alias_name):
 | 
					    def app_alias(self, alias_name):
 | 
				
			||||||
        return "alias {0}='eval $(TF_ALIAS={0} PYTHONIOENCODING=utf-8 " \
 | 
					        return """alias {0}='eval "$(TF_ALIAS={0} PYTHONIOENCODING=utf-8 """ \
 | 
				
			||||||
               "thefuck $(fc -ln -1))'".format(alias_name)
 | 
					               """thefuck "$(fc -ln -1)")"'""".format(alias_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def instant_mode_alias(self, alias_name):
 | 
					    def instant_mode_alias(self, alias_name):
 | 
				
			||||||
        warn("Instant mode not supported by your shell")
 | 
					        warn("Instant mode not supported by your shell")
 | 
				
			||||||
@@ -82,7 +84,7 @@ class Generic(object):
 | 
				
			|||||||
        encoded = self.encode_utf8(command)
 | 
					        encoded = self.encode_utf8(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            splitted = [s.replace("??", "\ ") for s in shlex.split(encoded.replace('\ ', '??'))]
 | 
					            splitted = [s.replace("??", "\\ ") for s in shlex.split(encoded.replace('\\ ', '??'))]
 | 
				
			||||||
        except ValueError:
 | 
					        except ValueError:
 | 
				
			||||||
            splitted = encoded.split(' ')
 | 
					            splitted = encoded.split(' ')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -131,6 +133,19 @@ class Generic(object):
 | 
				
			|||||||
                'type', 'typeset', 'ulimit', 'umask', 'unalias', 'unset',
 | 
					                'type', 'typeset', 'ulimit', 'umask', 'unalias', 'unset',
 | 
				
			||||||
                'until', 'wait', 'while']
 | 
					                'until', 'wait', 'while']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_version(self):
 | 
				
			||||||
 | 
					        """Returns the version of the current shell"""
 | 
				
			||||||
 | 
					        return ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def info(self):
 | 
				
			||||||
 | 
					        """Returns the name and version of the current shell"""
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            version = self._get_version()
 | 
				
			||||||
 | 
					        except Exception as e:
 | 
				
			||||||
 | 
					            warn(u'Could not determine shell version: {}'.format(e))
 | 
				
			||||||
 | 
					            version = ''
 | 
				
			||||||
 | 
					        return u'{} {}'.format(self.friendly_name, version).rstrip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _create_shell_configuration(self, content, path, reload):
 | 
					    def _create_shell_configuration(self, content, path, reload):
 | 
				
			||||||
        return ShellConfiguration(
 | 
					        return ShellConfiguration(
 | 
				
			||||||
            content=content,
 | 
					            content=content,
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user