mirror of
				https://github.com/nvbn/thefuck.git
				synced 2025-11-03 16:42:03 +00:00 
			
		
		
		
	Compare commits
	
		
			252 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					d267488520 | ||
| 
						 | 
					e31124335f | ||
| 
						 | 
					71a5182b9a | ||
| 
						 | 
					6a096155dc | ||
| 
						 | 
					5742d2d910 | ||
| 
						 | 
					754bb3e21f | ||
| 
						 | 
					2bbba9a0c8 | ||
| 
						 | 
					b978c3793e | ||
| 
						 | 
					8a83b30e73 | ||
| 
						 | 
					fd20a3f832 | ||
| 
						 | 
					b6ed499103 | ||
| 
						 | 
					76600cf40a | ||
| 
						 | 
					e62666181a | ||
| 
						 | 
					c88b0792b8 | ||
| 
						 | 
					06a89427e2 | ||
| 
						 | 
					3a134f250d | ||
| 
						 | 
					b54cdf7c49 | ||
| 
						 | 
					1b05a497e8 | ||
| 
						 | 
					79602383ec | ||
| 
						 | 
					84c42168df | ||
| 
						 | 
					f53d772ac3 | ||
| 
						 | 
					93d4a4fc3a | ||
| 
						 | 
					2cb23b1805 | ||
| 
						 | 
					33f28cf76d | ||
| 
						 | 
					6322dbd9ed | ||
| 
						 | 
					fc09818351 | ||
| 
						 | 
					2788ef1471 | ||
| 
						 | 
					ef3aabe7c5 | ||
| 
						 | 
					2af54d036d | ||
| 
						 | 
					99c10b50ff | ||
| 
						 | 
					802fcd96fd | ||
| 
						 | 
					900e83e028 | ||
| 
						 | 
					d41cbb6810 | ||
| 
						 | 
					b36cf59b46 | ||
| 
						 | 
					cfa831c88d | ||
| 
						 | 
					818d06fb95 | ||
| 
						 | 
					c3eca8234a | ||
| 
						 | 
					d47ff8cbf2 | ||
| 
						 | 
					1a52e98fbd | ||
| 
						 | 
					53c11d2ef4 | ||
| 
						 | 
					beda1854cf | ||
| 
						 | 
					7532c65c62 | ||
| 
						 | 
					ec37998a10 | ||
| 
						 | 
					58d5eff6d0 | ||
| 
						 | 
					d28567bb31 | ||
| 
						 | 
					b016bb2255 | ||
| 
						 | 
					bf109ee548 | ||
| 
						 | 
					1aaaca1220 | ||
| 
						 | 
					b096560469 | ||
| 
						 | 
					5b1f3ff816 | ||
| 
						 | 
					c5f7c89222 | ||
| 
						 | 
					e61271dae3 | ||
| 
						 | 
					bddb43b987 | ||
| 
						 | 
					b22a3ac891 | ||
| 
						 | 
					f4cc88f6c7 | ||
| 
						 | 
					5734412d82 | ||
| 
						 | 
					24588b23e2 | ||
| 
						 | 
					825f7986c7 | ||
| 
						 | 
					971c7e1b3f | ||
| 
						 | 
					8375b78877 | ||
| 
						 | 
					6f39edc155 | ||
| 
						 | 
					408cb5fa09 | ||
| 
						 | 
					2315929875 | ||
| 
						 | 
					14a9cd85aa | ||
| 
						 | 
					2379573cf2 | ||
| 
						 | 
					350be285b8 | ||
| 
						 | 
					76aa5546df | ||
| 
						 | 
					5179015b84 | ||
| 
						 | 
					dee99ed705 | ||
| 
						 | 
					e101f1fcc9 | ||
| 
						 | 
					73b884df5f | ||
| 
						 | 
					9e8b4f594d | ||
| 
						 | 
					c2b597f22b | ||
| 
						 | 
					8c783b7405 | ||
| 
						 | 
					3efa42ec06 | ||
| 
						 | 
					02bcd8331d | ||
| 
						 | 
					bd750ff9a3 | ||
| 
						 | 
					725ef271b1 | ||
| 
						 | 
					d2f8cebfd8 | ||
| 
						 | 
					c7d7a6d1d7 | ||
| 
						 | 
					4b53b1d3e3 | ||
| 
						 | 
					35ea4dce71 | ||
| 
						 | 
					2fea1f3846 | ||
| 
						 | 
					e009f0a05b | ||
| 
						 | 
					78515c7bbb | ||
| 
						 | 
					62a845fd94 | ||
| 
						 | 
					2c7ce91dd5 | ||
| 
						 | 
					c775937d17 | ||
| 
						 | 
					aaf01394db | ||
| 
						 | 
					0b0a2220a0 | ||
| 
						 | 
					b038ea4541 | ||
| 
						 | 
					7d3ddfc8d9 | ||
| 
						 | 
					02f3250d39 | ||
| 
						 | 
					df5428c5e4 | ||
| 
						 | 
					ef5ff6210a | ||
| 
						 | 
					fbb73f262b | ||
| 
						 | 
					20246e5be6 | ||
| 
						 | 
					4669a033ee | ||
| 
						 | 
					7e16a2eb7c | ||
| 
						 | 
					42ec01dab1 | ||
| 
						 | 
					91c27e1a62 | ||
| 
						 | 
					778f2bdf1a | ||
| 
						 | 
					e893521872 | ||
| 
						 | 
					bbed17fe07 | ||
| 
						 | 
					309fe8f6ee | ||
| 
						 | 
					8a8ade1e6b | ||
| 
						 | 
					7f9025c7ad | ||
| 
						 | 
					6f842ab747 | ||
| 
						 | 
					ae68bcbac1 | ||
| 
						 | 
					fb07cdfb4a | ||
| 
						 | 
					55dcf06569 | ||
| 
						 | 
					28a0150e45 | ||
| 
						 | 
					430a7135af | ||
| 
						 | 
					ff2be6c9a3 | ||
| 
						 | 
					4748776296 | ||
| 
						 | 
					1885196a11 | ||
| 
						 | 
					c127040a4c | ||
| 
						 | 
					ac7b633e28 | ||
| 
						 | 
					4d0388b53c | ||
| 
						 | 
					8da4dce5f2 | ||
| 
						 | 
					ace6e88269 | ||
| 
						 | 
					a015c0f5e2 | ||
| 
						 | 
					dbe324bcd8 | ||
| 
						 | 
					8447b5caa2 | ||
| 
						 | 
					3a9942061d | ||
| 
						 | 
					a65f90813b | ||
| 
						 | 
					a778ea6203 | ||
| 
						 | 
					03a828d586 | ||
| 
						 | 
					4a0d71c1c4 | ||
| 
						 | 
					a6f63c0568 | ||
| 
						 | 
					d1b9492085 | ||
| 
						 | 
					993a661c60 | ||
| 
						 | 
					bc9121cb13 | ||
| 
						 | 
					7db140c456 | ||
| 
						 | 
					e313ff73a9 | ||
| 
						 | 
					8c62706db4 | ||
| 
						 | 
					6baa7f650e | ||
| 
						 | 
					4ae32cf4ee | ||
| 
						 | 
					385746850e | ||
| 
						 | 
					4f87141f0c | ||
| 
						 | 
					dbedcc7aa6 | ||
| 
						 | 
					e0b5d47fa5 | ||
| 
						 | 
					ca44ee0640 | ||
| 
						 | 
					892e8a8e65 | ||
| 
						 | 
					a947259eef | ||
| 
						 | 
					785cb83ff3 | ||
| 
						 | 
					aec8fe3233 | ||
| 
						 | 
					c21dbd2be3 | ||
| 
						 | 
					b4fda04acb | ||
| 
						 | 
					5f6c55d839 | ||
| 
						 | 
					6173913291 | ||
| 
						 | 
					6f0d1e287d | ||
| 
						 | 
					756044e087 | ||
| 
						 | 
					ddd8788353 | ||
| 
						 | 
					76c0e7bc70 | ||
| 
						 | 
					4865bdd81f | ||
| 
						 | 
					fa169c686c | ||
| 
						 | 
					9cae0bffff | ||
| 
						 | 
					b519d317f7 | ||
| 
						 | 
					5b420204c9 | ||
| 
						 | 
					07005b591a | ||
| 
						 | 
					cb99e42e02 | ||
| 
						 | 
					51f77964c6 | ||
| 
						 | 
					30b1c44f91 | ||
| 
						 | 
					af28f0334a | ||
| 
						 | 
					5ee5439c1e | ||
| 
						 | 
					cf006dac2c | ||
| 
						 | 
					5b535077bf | ||
| 
						 | 
					dda9d55989 | ||
| 
						 | 
					f0b9c7cb67 | ||
| 
						 | 
					521eb03d7a | ||
| 
						 | 
					e0cab4fa1b | ||
| 
						 | 
					1b30c00546 | ||
| 
						 | 
					a9d55e9c62 | ||
| 
						 | 
					cf3acbfa2e | ||
| 
						 | 
					4d714994a3 | ||
| 
						 | 
					02f717a0e8 | ||
| 
						 | 
					8f4f2f03a7 | ||
| 
						 | 
					432878bd77 | ||
| 
						 | 
					fb3d8d1e01 | ||
| 
						 | 
					c4c6f506f4 | ||
| 
						 | 
					725605cd20 | ||
| 
						 | 
					797b42cfd7 | ||
| 
						 | 
					37161832aa | ||
| 
						 | 
					b221b04d0f | ||
| 
						 | 
					dcc13bd2d2 | ||
| 
						 | 
					283eb09c19 | ||
| 
						 | 
					10d409e6e2 | ||
| 
						 | 
					93302c74b5 | ||
| 
						 | 
					22b005cebb | ||
| 
						 | 
					feb36ede5c | ||
| 
						 | 
					16a440cb9d | ||
| 
						 | 
					10b20574d1 | ||
| 
						 | 
					91fceb401a | ||
| 
						 | 
					4b79e23ba7 | ||
| 
						 | 
					f915a6ed0c | ||
| 
						 | 
					e9d29726bc | ||
| 
						 | 
					a964af7e95 | ||
| 
						 | 
					77fc021a6c | ||
| 
						 | 
					4822ceb87a | ||
| 
						 | 
					b2947aba8d | ||
| 
						 | 
					d2e0a19aae | ||
| 
						 | 
					0c84eefa55 | ||
| 
						 | 
					8bd6c5da67 | ||
| 
						 | 
					ce6b82c92d | ||
| 
						 | 
					5dbbb3b1ed | ||
| 
						 | 
					db4b37910d | ||
| 
						 | 
					2b88ea11ea | ||
| 
						 | 
					db7dffdb44 | ||
| 
						 | 
					92f3c8fb52 | ||
| 
						 | 
					7c4f0d2e55 | ||
| 
						 | 
					d05eb0a6dc | ||
| 
						 | 
					cf352fd788 | ||
| 
						 | 
					3c1cce6bd2 | ||
| 
						 | 
					5d3a727d1a | ||
| 
						 | 
					ea87d55771 | ||
| 
						 | 
					aa6b18d0ce | ||
| 
						 | 
					934eeaf4fc | ||
| 
						 | 
					3ad8d52a84 | ||
| 
						 | 
					bb5c7c576f | ||
| 
						 | 
					17c3935078 | ||
| 
						 | 
					a734b94fec | ||
| 
						 | 
					7bf405e9c3 | ||
| 
						 | 
					c3bcdd7dee | ||
| 
						 | 
					ad53023860 | ||
| 
						 | 
					8938323229 | ||
| 
						 | 
					92133f77d6 | ||
| 
						 | 
					64eaf96eb8 | ||
| 
						 | 
					c9264aff10 | ||
| 
						 | 
					9660ec7813 | ||
| 
						 | 
					9ac47d8f78 | ||
| 
						 | 
					6e2b82911f | ||
| 
						 | 
					af9d34c299 | ||
| 
						 | 
					bcc11219e6 | ||
| 
						 | 
					495a66088b | ||
| 
						 | 
					4fe64e3dfa | ||
| 
						 | 
					cae76eb55f | ||
| 
						 | 
					afd2ed4e51 | ||
| 
						 | 
					1a4d74d487 | ||
| 
						 | 
					0bd3e85e08 | ||
| 
						 | 
					faeeef7666 | ||
| 
						 | 
					4d65d6a1df | ||
| 
						 | 
					cfa51506fb | ||
| 
						 | 
					5df350254e | ||
| 
						 | 
					612c393ec4 | ||
| 
						 | 
					4d89b3499e | ||
| 
						 | 
					070bb2ff28 | ||
| 
						 | 
					71025dff17 | ||
| 
						 | 
					621b455334 | ||
| 
						 | 
					176924c18d | ||
| 
						 | 
					1f75fc1ea9 | ||
| 
						 | 
					46cb87615e | 
							
								
								
									
										12
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								.travis.yml
									
									
									
									
									
								
							@@ -2,6 +2,9 @@ language: python
 | 
			
		||||
sudo: false
 | 
			
		||||
matrix:
 | 
			
		||||
  include:
 | 
			
		||||
    - os: linux
 | 
			
		||||
      dist: trusty
 | 
			
		||||
      python: "3.6"
 | 
			
		||||
    - os: linux
 | 
			
		||||
      dist: trusty
 | 
			
		||||
      python: "3.5"
 | 
			
		||||
@@ -29,7 +32,7 @@ addons:
 | 
			
		||||
      - python3-commandnotfound
 | 
			
		||||
before_install:
 | 
			
		||||
  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew update ; fi
 | 
			
		||||
  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew install $FORMULA; fi
 | 
			
		||||
  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then if brew ls --versions $FORMULA; then brew upgrade $FORMULA || echo Python is up to date; else brew install $FORMULA; fi; fi
 | 
			
		||||
  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then virtualenv venv -p $FORMULA; fi
 | 
			
		||||
  - if [[ $TRAVIS_OS_NAME == "osx" ]]; then source venv/bin/activate; fi
 | 
			
		||||
  - pip install -U pip
 | 
			
		||||
@@ -39,9 +42,10 @@ install:
 | 
			
		||||
  - python setup.py develop
 | 
			
		||||
  - rm -rf build
 | 
			
		||||
script:
 | 
			
		||||
  - flake8
 | 
			
		||||
  - 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"
 | 
			
		||||
  - if [[ $TRAVIS_PYTHON_VERSION == 3.5 && $TRAVIS_OS_NAME != "osx" ]]; then $RUN_TESTS --enable-functional; fi
 | 
			
		||||
  - if [[ $TRAVIS_PYTHON_VERSION != 3.5 || $TRAVIS_OS_NAME == "osx" ]]; then $RUN_TESTS; fi
 | 
			
		||||
  - if [[ $TRAVIS_PYTHON_VERSION == 3.6 && $TRAVIS_OS_NAME != "osx" ]]; then $RUN_TESTS --enable-functional; fi
 | 
			
		||||
  - if [[ $TRAVIS_PYTHON_VERSION != 3.6 || $TRAVIS_OS_NAME == "osx" ]]; then $RUN_TESTS; fi
 | 
			
		||||
after_success:
 | 
			
		||||
  - coveralls
 | 
			
		||||
  - if [[ $TRAVIS_PYTHON_VERSION == 3.6 && $TRAVIS_OS_NAME != "osx" ]]; then coveralls; fi
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										60
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								README.md
									
									
									
									
									
								
							@@ -103,17 +103,16 @@ brew install thefuck
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
On Ubuntu you can install `The Fuck` with:
 | 
			
		||||
 
 | 
			
		||||
```bash
 | 
			
		||||
sudo apt update
 | 
			
		||||
sudo apt install python3-dev python3-pip
 | 
			
		||||
sudo -H pip3 install thefuck
 | 
			
		||||
sudo pip3 install thefuck
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
On other systems you can install `The Fuck` with `pip`:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
sudo -H pip install thefuck
 | 
			
		||||
pip install thefuck
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
[Or using an OS package manager (OS X, Ubuntu, Arch).](https://github.com/nvbn/thefuck/wiki/Installation)
 | 
			
		||||
@@ -121,9 +120,9 @@ sudo -H pip install thefuck
 | 
			
		||||
You should place this command in your `.bash_profile`, `.bashrc`, `.zshrc` or other startup script:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
eval "$(thefuck --alias)"
 | 
			
		||||
eval $(thefuck --alias)
 | 
			
		||||
# You can use whatever you want as an alias, like for Mondays:
 | 
			
		||||
eval "$(thefuck --alias FUCK)"
 | 
			
		||||
eval $(thefuck --alias FUCK)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
[Or in your shell config (Bash, Zsh, Fish, Powershell, tcsh).](https://github.com/nvbn/thefuck/wiki/Shell-aliases)
 | 
			
		||||
@@ -131,11 +130,16 @@ eval "$(thefuck --alias FUCK)"
 | 
			
		||||
Changes will be available only in a new shell session.
 | 
			
		||||
To make them available immediately, run `source ~/.bashrc` (or your shell config file like `.zshrc`).
 | 
			
		||||
 | 
			
		||||
If you want separate alias for running fixed command without confirmation you can use alias like:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
alias fuck-it='export THEFUCK_REQUIRE_CONFIRMATION=False; fuck; export THEFUCK_REQUIRE_CONFIRMATION=True'
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Update
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
sudo pip install thefuck --upgrade
 | 
			
		||||
pip install thefuck --upgrade
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Aliases changed in 1.34.**
 | 
			
		||||
@@ -145,6 +149,8 @@ sudo pip install thefuck --upgrade
 | 
			
		||||
The Fuck tries to match a rule for the previous command, creates a new command
 | 
			
		||||
using the matched rule and runs it. Rules enabled by default are as follows:
 | 
			
		||||
 | 
			
		||||
* `ag_literal` – adds `-Q` to `ag` when suggested;
 | 
			
		||||
* `aws_cli` – fixes misspelled commands like `aws dynamdb scan`;
 | 
			
		||||
* `cargo` – runs `cargo build` instead of `cargo`;
 | 
			
		||||
* `cargo_no_command` – fixes wrongs commands like `cargo buid`;
 | 
			
		||||
* `cd_correction` – spellchecks and correct failed cd commands;
 | 
			
		||||
@@ -163,23 +169,35 @@ using the matched rule and runs it. Rules enabled by default are as follows:
 | 
			
		||||
* `fab_command_not_found` – fix misspelled fabric commands;
 | 
			
		||||
* `fix_alt_space` – replaces Alt+Space with Space character;
 | 
			
		||||
* `fix_file` – opens a file with an error in your `$EDITOR`;
 | 
			
		||||
* `gem_unknown_command` – fixes wrong `gem` commands;
 | 
			
		||||
* `git_add` – fixes *"pathspec 'foo' did not match any file(s) known to git."*;
 | 
			
		||||
* `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_branch_delete` – changes `git branch -d` to `git branch -D`;
 | 
			
		||||
* `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_checkout` – fixes branch name or creates new branch;
 | 
			
		||||
* `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_fix_stash` – fixes `git stash` commands (misspelled subcommand and missing `save`);
 | 
			
		||||
* `git_flag_after_filename` – fixes `fatal: bad flag '...' after filename`
 | 
			
		||||
* `git_help_aliased` – fixes `git help <alias>` commands replacing <alias> with the aliased command;
 | 
			
		||||
* `git_not_command` – fixes wrong git commands like `git brnch`;
 | 
			
		||||
* `git_pull` – sets upstream before executing previous `git pull`;
 | 
			
		||||
* `git_pull_clone` – clones instead of pulling when the repo does not exist;
 | 
			
		||||
* `git_pull_uncommitted_changes` – stashes changes before pulling and pops them afterwards;
 | 
			
		||||
* `git_push` – adds `--set-upstream origin $branch` to previous failed `git push`;
 | 
			
		||||
* `git_push_pull` – runs `git pull` when `push` was rejected;
 | 
			
		||||
* `git_push_without_commits` – Creates an initial commit if you forget and only `git add .`, when setting up a new project;
 | 
			
		||||
* `git_rebase_no_changes` – runs `git rebase --skip` instead of `git rebase --continue` when there are no changes;
 | 
			
		||||
* `git_rm_local_modifications` –  adds `-f` or `--cached` when you try to `rm` a locally modified file;
 | 
			
		||||
* `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_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_stash` – stashes you 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_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`;
 | 
			
		||||
* `go_run` – appends `.go` extension when compiling/running Go programs;
 | 
			
		||||
* `gradle_no_task` – fixes not found or ambiguous `gradle` task;
 | 
			
		||||
@@ -191,15 +209,19 @@ using the matched rule and runs it. Rules enabled by default are as follows:
 | 
			
		||||
* `has_exists_script` – prepends `./` when script/binary exists;
 | 
			
		||||
* `heroku_not_command` – fixes wrong `heroku` commands like `heroku log`;
 | 
			
		||||
* `history` – tries to replace command with most similar command from history;
 | 
			
		||||
* `hostscli` – tries to fix `hostscli` usage;
 | 
			
		||||
* `ifconfig_device_not_found` – fixes wrong device names like `wlan0` to `wlp2s0`;
 | 
			
		||||
* `java` – removes `.java` extension when running Java programs;
 | 
			
		||||
* `javac` – appends missing `.java` when compiling Java files;
 | 
			
		||||
* `lein_not_task` – fixes wrong `lein` tasks like `lein rpl`;
 | 
			
		||||
* `ln_no_hard_link` – catches hard link creation on directories, suggest symbolic link;
 | 
			
		||||
* `ln_s_order` – fixes `ln -s` arguments order;
 | 
			
		||||
* `ls_all` – adds `-A` to `ls` when output is empty;
 | 
			
		||||
* `ls_lah` – adds `-lah` to `ls`;
 | 
			
		||||
* `man` – changes manual section;
 | 
			
		||||
* `man_no_space` – fixes man commands without spaces, for example `mandiff`;
 | 
			
		||||
* `mercurial` – fixes wrong `hg` commands;
 | 
			
		||||
* `missing_space_before_subcommand` – fixes command with missing space like `npminstall`;
 | 
			
		||||
* `mkdir_p` – adds `-p` when you trying to create directory without parent;
 | 
			
		||||
* `mvn_no_command` – adds `clean package` to `mvn`;
 | 
			
		||||
* `mvn_unknown_lifecycle_phase` – fixes misspelled lifecycle phases with `mvn`;
 | 
			
		||||
@@ -214,12 +236,16 @@ using the matched rule and runs it. Rules enabled by default are as follows:
 | 
			
		||||
* `python_command` – prepends `python` when you trying to run not executable/without `./` python script;
 | 
			
		||||
* `python_execute` – appends missing `.py` when executing Python files;
 | 
			
		||||
* `quotation_marks` – fixes uneven usage of `'` and `"` when containing args';
 | 
			
		||||
* `path_from_history` – replaces not found path with similar absolute path from history;
 | 
			
		||||
* `react_native_command_unrecognized` – fixes unrecognized `react-native` commands;
 | 
			
		||||
* `remove_trailing_cedilla` – remove trailling cedillas `ç`, a common typo for european keyboard layouts;
 | 
			
		||||
* `rm_dir` – adds `-rf` when you trying to remove directory;
 | 
			
		||||
* `scm_correction` – corrects wrong scm like `hg log` to `git log`;
 | 
			
		||||
* `sed_unterminated_s` – adds missing '/' to `sed`'s `s` commands;
 | 
			
		||||
* `sl_ls` – changes `sl` to `ls`;
 | 
			
		||||
* `ssh_known_hosts` – removes host from `known_hosts` on warning;
 | 
			
		||||
* `sudo` – prepends `sudo` to previous command if it failed because of permissions;
 | 
			
		||||
* `sudo_command_from_user_path` – runs commands from users `$PATH` with `sudo`;
 | 
			
		||||
* `switch_lang` – switches command from your local layout to en;
 | 
			
		||||
* `systemctl` – correctly orders parameters of confusing `systemctl`;
 | 
			
		||||
* `test.py` – runs `py.test` instead of `test.py`;
 | 
			
		||||
@@ -231,6 +257,10 @@ using the matched rule and runs it. Rules enabled by default are as follows:
 | 
			
		||||
* `vagrant_up` – starts up the vagrant instance;
 | 
			
		||||
* `whois` – fixes `whois` command;
 | 
			
		||||
* `workon_doesnt_exists` – fixes `virtualenvwrapper` env name os suggests to create new.
 | 
			
		||||
* `yarn_alias` – fixes aliased `yarn` commands like `yarn ls`;
 | 
			
		||||
* `yarn_command_not_found` – fixes misspelled `yarn` commands;
 | 
			
		||||
* `yarn_command_replaced` – fixes replaced `yarn` commands;
 | 
			
		||||
* `yarn_help` – makes it easier to open `yarn` documentation;
 | 
			
		||||
 | 
			
		||||
Enabled by default only on specific platforms:
 | 
			
		||||
 | 
			
		||||
@@ -238,6 +268,8 @@ Enabled by default only on specific platforms:
 | 
			
		||||
* `apt_get_search` – changes trying to search using `apt-get` with searching using `apt-cache`;
 | 
			
		||||
* `apt_invalid_operation` – fixes invalid `apt` and `apt-get` calls, like `apt-get isntall vim`;
 | 
			
		||||
* `brew_install` – fixes formula name for `brew install`;
 | 
			
		||||
* `brew_link` – adds `--overwrite --dry-run` if linking fails;
 | 
			
		||||
* `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_update_formula` – turns `brew update <formula>` into `brew upgrade <formula>`;
 | 
			
		||||
* `brew_upgrade` – appends `--all` to `brew upgrade` as per Homebrew's new behaviour;
 | 
			
		||||
@@ -266,7 +298,9 @@ side_effect(old_command: Command, fixed_command: str) -> None
 | 
			
		||||
```
 | 
			
		||||
and optional `enabled_by_default`, `requires_output` and `priority` variables.
 | 
			
		||||
 | 
			
		||||
`Command` has three attributes: `script`, `stdout` and `stderr`.
 | 
			
		||||
`Command` has three attributes: `script`, `stdout`, `stderr` and `script_parts`.
 | 
			
		||||
Rule shouldn't change `Command`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
*Rules api changed in 3.0:* For accessing settings in rule you need to import it with `from thefuck.conf import settings`.
 | 
			
		||||
`settings` is a special object filled with `~/.config/thefuck/settings.py` and values from env ([see more below](#settings)).
 | 
			
		||||
@@ -364,6 +398,12 @@ pip install -r requirements.txt
 | 
			
		||||
python setup.py develop
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Run code style checks:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
flake8
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Run unit tests:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
@@ -389,9 +429,9 @@ Project License can be found [here](LICENSE.md).
 | 
			
		||||
 | 
			
		||||
[version-badge]:   https://img.shields.io/pypi/v/thefuck.svg?label=version
 | 
			
		||||
[version-link]:    https://pypi.python.org/pypi/thefuck/
 | 
			
		||||
[travis-badge]:    https://img.shields.io/travis/nvbn/thefuck.svg
 | 
			
		||||
[travis-badge]:    https://travis-ci.org/nvbn/thefuck.svg?branch=master
 | 
			
		||||
[travis-link]:     https://travis-ci.org/nvbn/thefuck
 | 
			
		||||
[appveyor-badge]:  https://img.shields.io/appveyor/ci/nvbn/thefuck.svg?label=windows%20build
 | 
			
		||||
[appveyor-badge]:  https://ci.appveyor.com/api/projects/status/1sskj4imj02um0gu/branch/master?svg=true
 | 
			
		||||
[appveyor-link]:   https://ci.appveyor.com/project/nvbn/thefuck
 | 
			
		||||
[coverage-badge]:  https://img.shields.io/coveralls/nvbn/thefuck.svg
 | 
			
		||||
[coverage-link]:   https://coveralls.io/github/nvbn/thefuck
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ environment:
 | 
			
		||||
    - PYTHON: "C:/Python33"
 | 
			
		||||
    - PYTHON: "C:/Python34"
 | 
			
		||||
    - PYTHON: "C:/Python35"
 | 
			
		||||
    - PYTHON: "C:/Python36"
 | 
			
		||||
 | 
			
		||||
init:
 | 
			
		||||
  - "ECHO %PYTHON%"
 | 
			
		||||
@@ -19,4 +20,5 @@ install:
 | 
			
		||||
  - "%PYTHON%/Scripts/pip.exe install -U -r requirements.txt"
 | 
			
		||||
 | 
			
		||||
test_script:
 | 
			
		||||
  - "%PYTHON%/python.exe -m flake8"
 | 
			
		||||
  - "%PYTHON%/Scripts/py.test.exe -sv"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
pip
 | 
			
		||||
flake8
 | 
			
		||||
pytest
 | 
			
		||||
mock
 | 
			
		||||
pytest-mock
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								setup.py
									
									
									
									
									
								
							@@ -29,7 +29,7 @@ elif (3, 0) < version < (3, 3):
 | 
			
		||||
          ' ({}.{} detected).'.format(*version))
 | 
			
		||||
    sys.exit(-1)
 | 
			
		||||
 | 
			
		||||
VERSION = '3.11'
 | 
			
		||||
VERSION = '3.20'
 | 
			
		||||
 | 
			
		||||
install_requires = ['psutil', 'colorama', 'six', 'decorator']
 | 
			
		||||
extras_require = {':python_version<"3.4"': ['pathlib2'],
 | 
			
		||||
@@ -51,5 +51,4 @@ setup(name='thefuck',
 | 
			
		||||
      extras_require=extras_require,
 | 
			
		||||
      entry_points={'console_scripts': [
 | 
			
		||||
          'thefuck = thefuck.main:main',
 | 
			
		||||
          'thefuck-alias = thefuck.main:print_alias',
 | 
			
		||||
          'fuck = thefuck.main:how_to_configure_alias']})
 | 
			
		||||
          'fuck = thefuck.not_configured:main']})
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,14 @@
 | 
			
		||||
try:
 | 
			
		||||
    from pathlib import Path
 | 
			
		||||
except ImportError:
 | 
			
		||||
    from pathlib2 import Path
 | 
			
		||||
import os
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck import shells
 | 
			
		||||
from thefuck import conf, const
 | 
			
		||||
from thefuck.system import Path
 | 
			
		||||
 | 
			
		||||
shells.shell = shells.Generic()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def pytest_addoption(parser):
 | 
			
		||||
    """Adds `--run-without-docker` argument."""
 | 
			
		||||
    """Adds `--enable-functional` argument."""
 | 
			
		||||
    group = parser.getgroup("thefuck")
 | 
			
		||||
    group.addoption('--enable-functional', action="store_true", default=False,
 | 
			
		||||
                    help="Enable functional tests")
 | 
			
		||||
@@ -59,7 +57,13 @@ def set_shell(monkeypatch, request):
 | 
			
		||||
    def _set(cls):
 | 
			
		||||
        shell = cls()
 | 
			
		||||
        monkeypatch.setattr('thefuck.shells.shell', shell)
 | 
			
		||||
        request.addfinalizer()
 | 
			
		||||
        return shell
 | 
			
		||||
 | 
			
		||||
    return _set
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def os_environ(monkeypatch):
 | 
			
		||||
    env = {'PATH': os.environ['PATH']}
 | 
			
		||||
    monkeypatch.setattr('os.environ', env)
 | 
			
		||||
    return env
 | 
			
		||||
 
 | 
			
		||||
@@ -81,6 +81,5 @@ def without_confirmation(proc, TIMEOUT):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def how_to_configure(proc, TIMEOUT):
 | 
			
		||||
    proc.sendline(u'unalias fuck')
 | 
			
		||||
    proc.sendline(u'fuck')
 | 
			
		||||
    assert proc.expect([TIMEOUT, u"alias isn't configured"])
 | 
			
		||||
 
 | 
			
		||||
@@ -3,18 +3,11 @@ from tests.functional.plots import with_confirmation, without_confirmation, \
 | 
			
		||||
    refuse_with_confirmation, history_changed, history_not_changed, \
 | 
			
		||||
    select_command_with_arrows, how_to_configure
 | 
			
		||||
 | 
			
		||||
containers = ((u'thefuck/ubuntu-python3-bash',
 | 
			
		||||
               u'''FROM ubuntu:latest
 | 
			
		||||
                   RUN apt-get update
 | 
			
		||||
                   RUN apt-get install -yy python3 python3-pip python3-dev git
 | 
			
		||||
                   RUN pip3 install -U setuptools
 | 
			
		||||
                   RUN ln -s /usr/bin/pip3 /usr/bin/pip''',
 | 
			
		||||
containers = ((u'thefuck/python3-bash',
 | 
			
		||||
               u'FROM python:3',
 | 
			
		||||
               u'bash'),
 | 
			
		||||
              (u'thefuck/ubuntu-python2-bash',
 | 
			
		||||
               u'''FROM ubuntu:latest
 | 
			
		||||
                   RUN apt-get update
 | 
			
		||||
                   RUN apt-get install -yy python python-pip python-dev git
 | 
			
		||||
                   RUN pip2 install -U pip setuptools''',
 | 
			
		||||
              (u'thefuck/python2-bash',
 | 
			
		||||
               u'FROM python:2',
 | 
			
		||||
               u'bash'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -55,4 +48,5 @@ def test_without_confirmation(proc, TIMEOUT):
 | 
			
		||||
 | 
			
		||||
@pytest.mark.functional
 | 
			
		||||
def test_how_to_configure_alias(proc, TIMEOUT):
 | 
			
		||||
    proc.sendline('unset -f fuck')
 | 
			
		||||
    how_to_configure(proc, TIMEOUT)
 | 
			
		||||
 
 | 
			
		||||
@@ -2,19 +2,20 @@ import pytest
 | 
			
		||||
from tests.functional.plots import with_confirmation, without_confirmation, \
 | 
			
		||||
    refuse_with_confirmation, select_command_with_arrows
 | 
			
		||||
 | 
			
		||||
containers = (('thefuck/ubuntu-python3-fish',
 | 
			
		||||
               u'''FROM ubuntu:latest
 | 
			
		||||
containers = (('thefuck/python3-fish',
 | 
			
		||||
               u'''FROM python:3
 | 
			
		||||
                   # Use jessie-backports since it has the fish package. See here for details:
 | 
			
		||||
                   # https://github.com/tianon/docker-brew-debian/blob/88ae21052affd8a14553bb969f9d41c464032122/jessie/backports/Dockerfile
 | 
			
		||||
                   RUN awk '$1 ~ "^deb" { $3 = $3 "-backports"; print; exit }' /etc/apt/sources.list > /etc/apt/sources.list.d/backports.list
 | 
			
		||||
                   RUN apt-get update
 | 
			
		||||
                   RUN apt-get install -yy python3 python3-pip python3-dev fish git
 | 
			
		||||
                   RUN pip3 install -U setuptools
 | 
			
		||||
                   RUN ln -s /usr/bin/pip3 /usr/bin/pip
 | 
			
		||||
                   RUN apt-get install -yy fish''',
 | 
			
		||||
               u'fish'),
 | 
			
		||||
              ('thefuck/ubuntu-python2-fish',
 | 
			
		||||
               u'''FROM ubuntu:latest
 | 
			
		||||
              ('thefuck/python2-fish',
 | 
			
		||||
               u'''FROM python:2
 | 
			
		||||
                   # Use jessie-backports since it has the fish package. See here for details:
 | 
			
		||||
                   # https://github.com/tianon/docker-brew-debian/blob/88ae21052affd8a14553bb969f9d41c464032122/jessie/backports/Dockerfile
 | 
			
		||||
                   RUN awk '$1 ~ "^deb" { $3 = $3 "-backports"; print; exit }' /etc/apt/sources.list > /etc/apt/sources.list.d/backports.list
 | 
			
		||||
                   RUN apt-get update
 | 
			
		||||
                   RUN apt-get install -yy python python-pip python-dev git
 | 
			
		||||
                   RUN pip2 install -U pip setuptools
 | 
			
		||||
                   RUN apt-get install -yy fish''',
 | 
			
		||||
               u'fish'))
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,7 @@ import pytest
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
dockerfile = u'''
 | 
			
		||||
FROM ubuntu:latest
 | 
			
		||||
RUN apt-get update
 | 
			
		||||
RUN apt-get install -yy python3 python3-pip python3-dev git
 | 
			
		||||
RUN pip3 install -U setuptools
 | 
			
		||||
RUN ln -s /usr/bin/pip3 /usr/bin/pip
 | 
			
		||||
FROM python:3
 | 
			
		||||
RUN adduser --disabled-password --gecos '' test
 | 
			
		||||
ENV SEED "{seed}"
 | 
			
		||||
WORKDIR /src
 | 
			
		||||
@@ -42,7 +38,7 @@ def plot(proc, TIMEOUT):
 | 
			
		||||
@pytest.mark.functional
 | 
			
		||||
@pytest.mark.benchmark(min_rounds=10)
 | 
			
		||||
def test_performance(spawnu, TIMEOUT, benchmark):
 | 
			
		||||
    proc = spawnu(u'thefuck/ubuntu-python3-bash-performance',
 | 
			
		||||
    proc = spawnu(u'thefuck/python3-bash-performance',
 | 
			
		||||
                  dockerfile, u'bash')
 | 
			
		||||
    proc.sendline(u'pip install /src')
 | 
			
		||||
    proc.sendline(u'su test')
 | 
			
		||||
 
 | 
			
		||||
@@ -2,19 +2,14 @@ import pytest
 | 
			
		||||
from tests.functional.plots import with_confirmation, without_confirmation, \
 | 
			
		||||
    refuse_with_confirmation, select_command_with_arrows
 | 
			
		||||
 | 
			
		||||
containers = (('thefuck/ubuntu-python3-tcsh',
 | 
			
		||||
               u'''FROM ubuntu:latest
 | 
			
		||||
containers = (('thefuck/python3-tcsh',
 | 
			
		||||
               u'''FROM python:3
 | 
			
		||||
                   RUN apt-get update
 | 
			
		||||
                   RUN apt-get install -yy python3 python3-pip python3-dev git
 | 
			
		||||
                   RUN pip3 install -U setuptools
 | 
			
		||||
                   RUN ln -s /usr/bin/pip3 /usr/bin/pip
 | 
			
		||||
                   RUN apt-get install -yy tcsh''',
 | 
			
		||||
               u'tcsh'),
 | 
			
		||||
              ('thefuck/ubuntu-python2-tcsh',
 | 
			
		||||
               u'''FROM ubuntu:latest
 | 
			
		||||
              ('thefuck/python2-tcsh',
 | 
			
		||||
               u'''FROM python:2
 | 
			
		||||
                   RUN apt-get update
 | 
			
		||||
                   RUN apt-get install -yy python python-pip python-dev git
 | 
			
		||||
                   RUN pip2 install -U pip setuptools
 | 
			
		||||
                   RUN apt-get install -yy tcsh''',
 | 
			
		||||
               u'tcsh'))
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,19 +3,14 @@ from tests.functional.plots import with_confirmation, without_confirmation, \
 | 
			
		||||
    refuse_with_confirmation, history_changed, history_not_changed, \
 | 
			
		||||
    select_command_with_arrows, how_to_configure
 | 
			
		||||
 | 
			
		||||
containers = (('thefuck/ubuntu-python3-zsh',
 | 
			
		||||
               u'''FROM ubuntu:latest
 | 
			
		||||
containers = (('thefuck/python3-zsh',
 | 
			
		||||
               u'''FROM python:3
 | 
			
		||||
                   RUN apt-get update
 | 
			
		||||
                   RUN apt-get install -yy python3 python3-pip python3-dev git
 | 
			
		||||
                   RUN pip3 install -U setuptools
 | 
			
		||||
                   RUN ln -s /usr/bin/pip3 /usr/bin/pip
 | 
			
		||||
                   RUN apt-get install -yy zsh''',
 | 
			
		||||
               u'zsh'),
 | 
			
		||||
              ('thefuck/ubuntu-python2-zsh',
 | 
			
		||||
               u'''FROM ubuntu:latest
 | 
			
		||||
              ('thefuck/python2-zsh',
 | 
			
		||||
               u'''FROM python:2
 | 
			
		||||
                   RUN apt-get update
 | 
			
		||||
                   RUN apt-get install -yy python python-pip python-dev git
 | 
			
		||||
                   RUN pip2 install -U pip setuptools
 | 
			
		||||
                   RUN apt-get install -yy zsh''',
 | 
			
		||||
               u'zsh'))
 | 
			
		||||
 | 
			
		||||
@@ -60,4 +55,5 @@ def test_without_confirmation(proc, TIMEOUT):
 | 
			
		||||
 | 
			
		||||
@pytest.mark.functional
 | 
			
		||||
def test_how_to_configure_alias(proc, TIMEOUT):
 | 
			
		||||
    proc.sendline(u'unfunction fuck')
 | 
			
		||||
    how_to_configure(proc, TIMEOUT)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								tests/rules/test_ag_literal.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/rules/test_ag_literal.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.ag_literal import get_new_command, match
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr():
 | 
			
		||||
    return ('ERR: Bad regex! pcre_compile() failed at position 1: missing )\n'
 | 
			
		||||
            'If you meant to search for a literal string, run ag with -Q\n')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', ['ag \('])
 | 
			
		||||
def test_match(script, stderr):
 | 
			
		||||
    assert match(Command(script=script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', ['ag foo'])
 | 
			
		||||
def test_not_match(script):
 | 
			
		||||
    assert not match(Command(script=script))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, new_cmd', [
 | 
			
		||||
    ('ag \(', 'ag -Q \(')])
 | 
			
		||||
def test_get_new_command(script, new_cmd, stderr):
 | 
			
		||||
    assert get_new_command((Command(script=script, stderr=stderr))) == new_cmd
 | 
			
		||||
@@ -7,6 +7,8 @@ from tests.utils import Command
 | 
			
		||||
    (Command(script='vim', stderr='vim: command not found'),
 | 
			
		||||
     [('vim', 'main'), ('vim-tiny', 'main')]),
 | 
			
		||||
    (Command(script='sudo vim', stderr='vim: command not found'),
 | 
			
		||||
     [('vim', 'main'), ('vim-tiny', 'main')]),
 | 
			
		||||
    (Command(script='vim', stderr="The program 'vim' is currently not installed. You can install it by typing: sudo apt install vim"),
 | 
			
		||||
     [('vim', 'main'), ('vim-tiny', 'main')])])
 | 
			
		||||
def test_match(mocker, command, packages):
 | 
			
		||||
    mocker.patch('thefuck.rules.apt_get.which', return_value=None)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										101
									
								
								tests/rules/test_aws_cli.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								tests/rules/test_aws_cli.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
from thefuck.rules.aws_cli import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
no_suggestions = '''\
 | 
			
		||||
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
 | 
			
		||||
To see help text, you can run:
 | 
			
		||||
 | 
			
		||||
  aws help
 | 
			
		||||
  aws <command> help
 | 
			
		||||
  aws <command> <subcommand> help
 | 
			
		||||
aws: error: argument command: Invalid choice, valid choices are:
 | 
			
		||||
 | 
			
		||||
dynamodb                                 | dynamodbstreams
 | 
			
		||||
ec2                                      | ecr
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
misspelled_command = '''\
 | 
			
		||||
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
 | 
			
		||||
To see help text, you can run:
 | 
			
		||||
 | 
			
		||||
  aws help
 | 
			
		||||
  aws <command> help
 | 
			
		||||
  aws <command> <subcommand> help
 | 
			
		||||
aws: error: argument command: Invalid choice, valid choices are:
 | 
			
		||||
 | 
			
		||||
dynamodb                                 | dynamodbstreams
 | 
			
		||||
ec2                                      | ecr
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Invalid choice: 'dynamdb', maybe you meant:
 | 
			
		||||
 | 
			
		||||
  * dynamodb
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
misspelled_subcommand = '''\
 | 
			
		||||
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
 | 
			
		||||
To see help text, you can run:
 | 
			
		||||
 | 
			
		||||
  aws help
 | 
			
		||||
  aws <command> help
 | 
			
		||||
  aws <command> <subcommand> help
 | 
			
		||||
aws: error: argument operation: Invalid choice, valid choices are:
 | 
			
		||||
 | 
			
		||||
query                                    | scan
 | 
			
		||||
update-item                              | update-table
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Invalid choice: 'scn', maybe you meant:
 | 
			
		||||
 | 
			
		||||
  * scan
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
misspelled_subcommand_with_multiple_options = '''\
 | 
			
		||||
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
 | 
			
		||||
To see help text, you can run:
 | 
			
		||||
 | 
			
		||||
  aws help
 | 
			
		||||
  aws <command> help
 | 
			
		||||
  aws <command> <subcommand> help
 | 
			
		||||
aws: error: argument operation: Invalid choice, valid choices are:
 | 
			
		||||
 | 
			
		||||
describe-table                           | get-item
 | 
			
		||||
list-tables                              | put-item
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Invalid choice: 't-item', maybe you meant:
 | 
			
		||||
 | 
			
		||||
  * put-item
 | 
			
		||||
  * get-item
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command('aws dynamdb scan', stderr=misspelled_command),
 | 
			
		||||
    Command('aws dynamodb scn', stderr=misspelled_subcommand),
 | 
			
		||||
    Command('aws dynamodb t-item',
 | 
			
		||||
            stderr=misspelled_subcommand_with_multiple_options)])
 | 
			
		||||
def test_match(command):
 | 
			
		||||
    assert match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_not_match():
 | 
			
		||||
    assert not match(Command('aws dynamodb invalid', stderr=no_suggestions))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, result', [
 | 
			
		||||
    (Command('aws dynamdb scan', stderr=misspelled_command),
 | 
			
		||||
     ['aws dynamodb scan']),
 | 
			
		||||
    (Command('aws dynamodb scn', stderr=misspelled_subcommand),
 | 
			
		||||
     ['aws dynamodb scan']),
 | 
			
		||||
    (Command('aws dynamodb t-item',
 | 
			
		||||
             stderr=misspelled_subcommand_with_multiple_options),
 | 
			
		||||
     ['aws dynamodb put-item', 'aws dynamodb get-item'])])
 | 
			
		||||
def test_get_new_command(command, result):
 | 
			
		||||
    assert get_new_command(command) == result
 | 
			
		||||
							
								
								
									
										38
									
								
								tests/rules/test_brew_link.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								tests/rules/test_brew_link.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
from thefuck.rules.brew_link import get_new_command, match
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr():
 | 
			
		||||
    return ("Error: Could not symlink bin/gcp\n"
 | 
			
		||||
            "Target /usr/local/bin/gcp\n"
 | 
			
		||||
            "already exists. You may want to remove it:\n"
 | 
			
		||||
            "  rm '/usr/local/bin/gcp'\n"
 | 
			
		||||
            "\n"
 | 
			
		||||
            "To force the link and overwrite all conflicting files:\n"
 | 
			
		||||
            "  brew link --overwrite coreutils\n"
 | 
			
		||||
            "\n"
 | 
			
		||||
            "To list all files that would be deleted:\n"
 | 
			
		||||
            "  brew link --overwrite --dry-run coreutils\n")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def new_command(formula):
 | 
			
		||||
    return 'brew link --overwrite --dry-run {}'.format(formula)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', ['brew link coreutils', 'brew ln coreutils'])
 | 
			
		||||
def test_match(stderr, script):
 | 
			
		||||
    assert match(Command(script=script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', ['brew link coreutils'])
 | 
			
		||||
def test_not_match(script):
 | 
			
		||||
    stderr = ''
 | 
			
		||||
    assert not match(Command(script=script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, formula, ', [('brew link coreutils', 'coreutils')])
 | 
			
		||||
def test_get_new_command(stderr, new_command, script, formula):
 | 
			
		||||
    assert get_new_command(Command(script=script, stderr=stderr)) == new_command
 | 
			
		||||
							
								
								
									
										31
									
								
								tests/rules/test_brew_uninstall.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								tests/rules/test_brew_uninstall.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
from thefuck.rules.brew_uninstall import get_new_command, match
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stdout():
 | 
			
		||||
    return ("Uninstalling /usr/local/Cellar/tbb/4.4-20160916... (118 files, 1.9M)\n"
 | 
			
		||||
            "tbb 4.4-20160526, 4.4-20160722 are still installed.\n"
 | 
			
		||||
            "Remove all versions with `brew uninstall --force tbb`.\n")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def new_command(formula):
 | 
			
		||||
    return 'brew uninstall --force {}'.format(formula)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', ['brew uninstall tbb', 'brew rm tbb', 'brew remove tbb'])
 | 
			
		||||
def test_match(stdout, script):
 | 
			
		||||
    assert match(Command(script=script, stdout=stdout))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', ['brew remove gnuplot'])
 | 
			
		||||
def test_not_match(script):
 | 
			
		||||
    stdout = 'Uninstalling /usr/local/Cellar/gnuplot/5.0.4_1... (44 files, 2.3M)\n'
 | 
			
		||||
    assert not match(Command(script=script, stdout=stdout))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, formula, ', [('brew uninstall tbb', 'tbb')])
 | 
			
		||||
def test_get_new_command(stdout, new_command, script, formula):
 | 
			
		||||
    assert get_new_command(Command(script=script, stdout=stdout)) == new_command
 | 
			
		||||
@@ -21,8 +21,8 @@ def test_match(brew_unknown_cmd):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command(brew_unknown_cmd, brew_unknown_cmd2):
 | 
			
		||||
    assert get_new_command(Command('brew inst', stderr=brew_unknown_cmd)) \
 | 
			
		||||
           == ['brew list', 'brew install', 'brew uninstall']
 | 
			
		||||
    assert (get_new_command(Command('brew inst', stderr=brew_unknown_cmd))
 | 
			
		||||
            == ['brew list', 'brew install', 'brew uninstall'])
 | 
			
		||||
 | 
			
		||||
    cmds = get_new_command(Command('brew instaa', stderr=brew_unknown_cmd2))
 | 
			
		||||
    assert 'brew install' in cmds
 | 
			
		||||
 
 | 
			
		||||
@@ -48,9 +48,9 @@ def test_match(composer_not_command, composer_not_command_one_of_this):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command(composer_not_command, composer_not_command_one_of_this):
 | 
			
		||||
    assert get_new_command(Command('composer udpate',
 | 
			
		||||
                                   stderr=composer_not_command)) \
 | 
			
		||||
           == 'composer update'
 | 
			
		||||
    assert get_new_command(
 | 
			
		||||
        Command('composer pdate', stderr=composer_not_command_one_of_this)) \
 | 
			
		||||
           == 'composer selfupdate'
 | 
			
		||||
    assert (get_new_command(Command('composer udpate',
 | 
			
		||||
                                    stderr=composer_not_command))
 | 
			
		||||
            == 'composer update')
 | 
			
		||||
    assert (get_new_command(Command('composer pdate',
 | 
			
		||||
                                    stderr=composer_not_command_one_of_this))
 | 
			
		||||
            == 'composer selfupdate')
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ import os
 | 
			
		||||
import pytest
 | 
			
		||||
import tarfile
 | 
			
		||||
from thefuck.rules.dirty_untar import match, get_new_command, side_effect, \
 | 
			
		||||
                                      tar_extensions
 | 
			
		||||
                                      tar_extensions  # noqa: E126
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -33,12 +33,12 @@ def tar_error(tmpdir):
 | 
			
		||||
 | 
			
		||||
    return fixture
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
parametrize_extensions = pytest.mark.parametrize('ext', tar_extensions)
 | 
			
		||||
 | 
			
		||||
# (filename as typed by the user, unquoted filename, quoted filename as per shells.quote)
 | 
			
		||||
parametrize_filename = pytest.mark.parametrize('filename, unquoted, quoted', [
 | 
			
		||||
    ('foo{}', 'foo{}', 'foo{}'),
 | 
			
		||||
    ('foo\ bar{}', 'foo bar{}', "'foo bar{}'"),
 | 
			
		||||
    ('"foo bar{}"', 'foo bar{}', "'foo bar{}'")])
 | 
			
		||||
 | 
			
		||||
parametrize_script = pytest.mark.parametrize('script, fixed', [
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,6 @@ def test_side_effect(zip_error, script, filename):
 | 
			
		||||
@pytest.mark.parametrize('script,fixed,filename', [
 | 
			
		||||
    (u'unzip café', u"unzip café -d 'café'", u'café.zip'),
 | 
			
		||||
    (u'unzip foo', u'unzip foo -d foo', u'foo.zip'),
 | 
			
		||||
    (u"unzip foo\\ bar.zip", u"unzip foo\\ bar.zip -d 'foo bar'", u'foo.zip'),
 | 
			
		||||
    (u"unzip 'foo bar.zip'", u"unzip 'foo bar.zip' -d 'foo bar'", u'foo.zip'),
 | 
			
		||||
    (u'unzip foo.zip', u'unzip foo.zip -d foo', u'foo.zip')])
 | 
			
		||||
def test_get_new_command(zip_error, script, fixed, filename):
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,7 @@ south.exceptions.GhostMigrations:
 | 
			
		||||
 ! I'm not trusting myself; either fix this yourself by fiddling
 | 
			
		||||
 ! with the south_migrationhistory table, or pass --delete-ghost-migrations
 | 
			
		||||
 ! to South to have it delete ALL of these records (this may not be good).
 | 
			
		||||
'''
 | 
			
		||||
'''  # noqa
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_match(stderr):
 | 
			
		||||
 
 | 
			
		||||
@@ -39,5 +39,5 @@ def test_match(stderr):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command():
 | 
			
		||||
    assert get_new_command(Command('./manage.py migrate auth')) \
 | 
			
		||||
           == './manage.py migrate auth --merge'
 | 
			
		||||
    assert (get_new_command(Command('./manage.py migrate auth'))
 | 
			
		||||
            == './manage.py migrate auth --merge')
 | 
			
		||||
 
 | 
			
		||||
@@ -45,5 +45,5 @@ def test_not_match(command):
 | 
			
		||||
     'fab prepare_extension:version=2016 deploy:beta=true -H the.fuck'),
 | 
			
		||||
])
 | 
			
		||||
def test_get_new_command(script, result):
 | 
			
		||||
    command = Command(script, stdout,stderr)
 | 
			
		||||
    command = Command(script, stdout, stderr)
 | 
			
		||||
    assert get_new_command(command) == result
 | 
			
		||||
 
 | 
			
		||||
@@ -18,5 +18,5 @@ def test_match():
 | 
			
		||||
 | 
			
		||||
def test_get_new_command():
 | 
			
		||||
    """ Replace the Alt+Space character by a simple space """
 | 
			
		||||
    assert get_new_command(Command(u'ps -ef | grep foo'))\
 | 
			
		||||
           == 'ps -ef | grep foo'
 | 
			
		||||
    assert (get_new_command(Command(u'ps -ef | grep foo'))
 | 
			
		||||
            == 'ps -ef | grep foo')
 | 
			
		||||
 
 | 
			
		||||
@@ -191,7 +191,7 @@ E       NameError: name 'mocker' is not defined
 | 
			
		||||
 | 
			
		||||
/home/thefuck/tests/rules/test_fix_file.py:218: NameError
 | 
			
		||||
""", ''),
 | 
			
		||||
)
 | 
			
		||||
)  # noqa
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('test', tests)
 | 
			
		||||
@@ -227,10 +227,6 @@ def test_get_new_command(mocker, monkeypatch, test):
 | 
			
		||||
    mocker.patch('os.path.isfile', return_value=True)
 | 
			
		||||
    monkeypatch.setenv('EDITOR', 'dummy_editor')
 | 
			
		||||
 | 
			
		||||
    cmd = Command(script=test[0], stdout=test[4], stderr=test[5])
 | 
			
		||||
    #assert (get_new_command(cmd, Settings({})) ==
 | 
			
		||||
    #    'dummy_editor {} +{} && {}'.format(test[1], test[2], test[0]))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('test', tests)
 | 
			
		||||
@pytest.mark.usefixtures('no_memoize')
 | 
			
		||||
@@ -243,7 +239,7 @@ def test_get_new_command_with_settings(mocker, monkeypatch, test, settings):
 | 
			
		||||
 | 
			
		||||
    if test[3]:
 | 
			
		||||
        assert (get_new_command(cmd) ==
 | 
			
		||||
            u'dummy_editor {} +{}:{} && {}'.format(test[1], test[2], test[3], test[0]))
 | 
			
		||||
                u'dummy_editor {} +{}:{} && {}'.format(test[1], test[2], test[3], test[0]))
 | 
			
		||||
    else:
 | 
			
		||||
        assert (get_new_command(cmd) ==
 | 
			
		||||
            u'dummy_editor {} +{} && {}'.format(test[1], test[2], test[0]))
 | 
			
		||||
                u'dummy_editor {} +{} && {}'.format(test[1], test[2], test[0]))
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										82
									
								
								tests/rules/test_gem_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								tests/rules/test_gem_unknown_command.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from six import BytesIO
 | 
			
		||||
from thefuck.rules.gem_unknown_command import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
stderr = '''
 | 
			
		||||
ERROR:  While executing gem ... (Gem::CommandLineError)
 | 
			
		||||
    Unknown command {}
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
gem_help_commands_stdout = b'''
 | 
			
		||||
GEM commands are:
 | 
			
		||||
 | 
			
		||||
    build             Build a gem from a gemspec
 | 
			
		||||
    cert              Manage RubyGems certificates and signing settings
 | 
			
		||||
    check             Check a gem repository for added or missing files
 | 
			
		||||
    cleanup           Clean up old versions of installed gems
 | 
			
		||||
    contents          Display the contents of the installed gems
 | 
			
		||||
    dependency        Show the dependencies of an installed gem
 | 
			
		||||
    environment       Display information about the RubyGems environment
 | 
			
		||||
    fetch             Download a gem and place it in the current directory
 | 
			
		||||
    generate_index    Generates the index files for a gem server directory
 | 
			
		||||
    help              Provide help on the 'gem' command
 | 
			
		||||
    install           Install a gem into the local repository
 | 
			
		||||
    list              Display local gems whose name matches REGEXP
 | 
			
		||||
    lock              Generate a lockdown list of gems
 | 
			
		||||
    mirror            Mirror all gem files (requires rubygems-mirror)
 | 
			
		||||
    open              Open gem sources in editor
 | 
			
		||||
    outdated          Display all gems that need updates
 | 
			
		||||
    owner             Manage gem owners of a gem on the push server
 | 
			
		||||
    pristine          Restores installed gems to pristine condition from files
 | 
			
		||||
                      located in the gem cache
 | 
			
		||||
    push              Push a gem up to the gem server
 | 
			
		||||
    query             Query gem information in local or remote repositories
 | 
			
		||||
    rdoc              Generates RDoc for pre-installed gems
 | 
			
		||||
    search            Display remote gems whose name matches REGEXP
 | 
			
		||||
    server            Documentation and gem repository HTTP server
 | 
			
		||||
    sources           Manage the sources and cache file RubyGems uses to search
 | 
			
		||||
                      for gems
 | 
			
		||||
    specification     Display gem specification (in yaml)
 | 
			
		||||
    stale             List gems along with access times
 | 
			
		||||
    uninstall         Uninstall gems from the local repository
 | 
			
		||||
    unpack            Unpack an installed gem to the current directory
 | 
			
		||||
    update            Update installed gems to the latest version
 | 
			
		||||
    which             Find the location of a library file you can require
 | 
			
		||||
    yank              Remove a pushed gem from the index
 | 
			
		||||
 | 
			
		||||
For help on a particular command, use 'gem help COMMAND'.
 | 
			
		||||
 | 
			
		||||
Commands may be abbreviated, so long as they are unambiguous.
 | 
			
		||||
e.g. 'gem i rake' is short for 'gem install rake'.
 | 
			
		||||
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def gem_help_commands(mocker):
 | 
			
		||||
    patch = mocker.patch('subprocess.Popen')
 | 
			
		||||
    patch.return_value.stdout = BytesIO(gem_help_commands_stdout)
 | 
			
		||||
    return patch
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, command', [
 | 
			
		||||
    ('gem isntall jekyll', 'isntall'),
 | 
			
		||||
    ('gem last --local', 'last')])
 | 
			
		||||
def test_match(script, command):
 | 
			
		||||
    assert match(Command(script, stderr=stderr.format(command)))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr', [
 | 
			
		||||
    ('gem install jekyll', ''),
 | 
			
		||||
    ('git log', stderr.format('log'))])
 | 
			
		||||
def test_not_match(script, stderr):
 | 
			
		||||
    assert not match(Command(script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr, result', [
 | 
			
		||||
    ('gem isntall jekyll', stderr.format('isntall'), 'gem install jekyll'),
 | 
			
		||||
    ('gem last --local', stderr.format('last'), 'gem list --local')])
 | 
			
		||||
def test_get_new_command(script, stderr, result):
 | 
			
		||||
    new_command = get_new_command(Command(script, stderr=stderr))
 | 
			
		||||
    assert new_command[0] == result
 | 
			
		||||
@@ -3,6 +3,12 @@ from thefuck.rules.git_add import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def path_exists(mocker):
 | 
			
		||||
    return mocker.patch('thefuck.rules.git_add.Path.exists',
 | 
			
		||||
                        return_value=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr(target):
 | 
			
		||||
    return ("error: pathspec '{}' did not match any "
 | 
			
		||||
@@ -16,10 +22,13 @@ def test_match(stderr, script, target):
 | 
			
		||||
    assert match(Command(script=script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', [
 | 
			
		||||
    'git submodule update known', 'git commit known'])
 | 
			
		||||
def test_not_match(script):
 | 
			
		||||
    assert not match(Command(script=script, stderr=''))
 | 
			
		||||
@pytest.mark.parametrize('script, target, exists', [
 | 
			
		||||
    ('git submodule update known', '', True),
 | 
			
		||||
    ('git commit known', '', True),
 | 
			
		||||
    ('git submodule update known', stderr, False)])
 | 
			
		||||
def test_not_match(path_exists, stderr, script, target, exists):
 | 
			
		||||
    path_exists.return_value = exists
 | 
			
		||||
    assert not match(Command(script=script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, target, new_command', [
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								tests/rules/test_git_add_force.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/rules/test_git_add_force.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.git_add_force import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr():
 | 
			
		||||
    return ('The following paths are ignored by one of your .gitignore files:\n'
 | 
			
		||||
            'dist/app.js\n'
 | 
			
		||||
            'dist/background.js\n'
 | 
			
		||||
            'dist/options.js\n'
 | 
			
		||||
            'Use -f if you really want to add them.\n')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_match(stderr):
 | 
			
		||||
    assert match(Command('git add dist/*.js', stderr=stderr))
 | 
			
		||||
    assert not match(Command('git add dist/*.js'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command(stderr):
 | 
			
		||||
    assert (get_new_command(Command('git add dist/*.js', stderr=stderr))
 | 
			
		||||
            == "git add --force dist/*.js")
 | 
			
		||||
							
								
								
									
										30
									
								
								tests/rules/test_git_bisect_usage.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								tests/rules/test_git_bisect_usage.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
from thefuck.rules.git_bisect_usage import match, get_new_command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr():
 | 
			
		||||
    return ("usage: git bisect [help|start|bad|good|new|old"
 | 
			
		||||
            "|terms|skip|next|reset|visualize|replay|log|run]")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', [
 | 
			
		||||
    'git bisect strt', 'git bisect rset', 'git bisect goood'])
 | 
			
		||||
def test_match(stderr, script):
 | 
			
		||||
    assert match(Command(script=script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', [
 | 
			
		||||
    'git bisect', 'git bisect start', 'git bisect good'])
 | 
			
		||||
def test_not_match(script):
 | 
			
		||||
    assert not match(Command(script=script, stderr=''))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, new_cmd, ', [
 | 
			
		||||
    ('git bisect goood', ['good', 'old', 'log']),
 | 
			
		||||
    ('git bisect strt', ['start', 'terms', 'reset']),
 | 
			
		||||
    ('git bisect rset', ['reset', 'next', 'start'])])
 | 
			
		||||
def test_get_new_command(stderr, script, new_cmd):
 | 
			
		||||
    new_cmd = ['git bisect %s' % cmd for cmd in new_cmd]
 | 
			
		||||
    assert get_new_command(Command(script=script, stderr=stderr)) == new_cmd
 | 
			
		||||
							
								
								
									
										23
									
								
								tests/rules/test_git_diff_no_index.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								tests/rules/test_git_diff_no_index.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.git_diff_no_index import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command(script='git diff foo bar')])
 | 
			
		||||
def test_match(command):
 | 
			
		||||
    assert match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command(script='git diff --no-index foo bar'),
 | 
			
		||||
    Command(script='git diff foo'),
 | 
			
		||||
    Command(script='git diff foo bar baz')])
 | 
			
		||||
def test_not_match(command):
 | 
			
		||||
    assert not match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, new_command', [
 | 
			
		||||
    (Command('git diff foo bar'), 'git diff --no-index foo bar')])
 | 
			
		||||
def test_get_new_command(command, new_command):
 | 
			
		||||
    assert get_new_command(command) == new_command
 | 
			
		||||
							
								
								
									
										31
									
								
								tests/rules/test_git_flag_after_filename.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								tests/rules/test_git_flag_after_filename.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.git_flag_after_filename import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
command1 = Command('git log README.md -p',
 | 
			
		||||
                   stderr="fatal: bad flag '-p' used after filename")
 | 
			
		||||
command2 = Command('git log README.md -p CONTRIBUTING.md',
 | 
			
		||||
                   stderr="fatal: bad flag '-p' used after filename")
 | 
			
		||||
command3 = Command('git log -p README.md --name-only',
 | 
			
		||||
                   stderr="fatal: bad flag '--name-only' used after filename")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    command1, command2, command3])
 | 
			
		||||
def test_match(command):
 | 
			
		||||
    assert match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command('git log README.md'),
 | 
			
		||||
    Command('git log -p README.md')])
 | 
			
		||||
def test_not_match(command):
 | 
			
		||||
    assert not match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, result', [
 | 
			
		||||
    (command1, "git log -p README.md"),
 | 
			
		||||
    (command2, "git log -p README.md CONTRIBUTING.md"),
 | 
			
		||||
    (command3, "git log -p --name-only README.md")])
 | 
			
		||||
def test_get_new_command(command, result):
 | 
			
		||||
    assert get_new_command(command) == result
 | 
			
		||||
@@ -7,7 +7,7 @@ from tests.utils import Command
 | 
			
		||||
def git_not_command():
 | 
			
		||||
    return """git: 'brnch' is not a git command. See 'git --help'.
 | 
			
		||||
 | 
			
		||||
Did you mean this?
 | 
			
		||||
The most similar command is
 | 
			
		||||
branch
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
@@ -16,7 +16,7 @@ branch
 | 
			
		||||
def git_not_command_one_of_this():
 | 
			
		||||
    return """git: 'st' is not a git command. See 'git --help'.
 | 
			
		||||
 | 
			
		||||
Did you mean one of these?
 | 
			
		||||
The most similar commands are
 | 
			
		||||
status
 | 
			
		||||
reset
 | 
			
		||||
stage
 | 
			
		||||
@@ -29,7 +29,7 @@ stats
 | 
			
		||||
def git_not_command_closest():
 | 
			
		||||
    return '''git: 'tags' is not a git command. See 'git --help'.
 | 
			
		||||
 | 
			
		||||
Did you mean one of these?
 | 
			
		||||
The most similar commands are
 | 
			
		||||
\tstage
 | 
			
		||||
\ttag
 | 
			
		||||
'''
 | 
			
		||||
@@ -49,9 +49,9 @@ def test_match(git_not_command, git_command, git_not_command_one_of_this):
 | 
			
		||||
 | 
			
		||||
def test_get_new_command(git_not_command, git_not_command_one_of_this,
 | 
			
		||||
                         git_not_command_closest):
 | 
			
		||||
    assert get_new_command(Command('git brnch', stderr=git_not_command)) \
 | 
			
		||||
           == ['git branch']
 | 
			
		||||
    assert get_new_command(Command('git st', stderr=git_not_command_one_of_this)) \
 | 
			
		||||
           == ['git stats', 'git stash', 'git stage']
 | 
			
		||||
    assert get_new_command(Command('git tags', stderr=git_not_command_closest)) \
 | 
			
		||||
           == ['git tag', 'git stage']
 | 
			
		||||
    assert (get_new_command(Command('git brnch', stderr=git_not_command))
 | 
			
		||||
            == ['git branch'])
 | 
			
		||||
    assert (get_new_command(Command('git st', stderr=git_not_command_one_of_this))
 | 
			
		||||
            == ['git stats', 'git stash', 'git stage'])
 | 
			
		||||
    assert (get_new_command(Command('git tags', stderr=git_not_command_closest))
 | 
			
		||||
            == ['git tag', 'git stage'])
 | 
			
		||||
 
 | 
			
		||||
@@ -25,5 +25,5 @@ def test_match(stderr):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command(stderr):
 | 
			
		||||
    assert get_new_command(Command('git pull', stderr=stderr)) \
 | 
			
		||||
           == "git branch --set-upstream-to=origin/master master && git pull"
 | 
			
		||||
    assert (get_new_command(Command('git pull', stderr=stderr))
 | 
			
		||||
            == "git branch --set-upstream-to=origin/master master && git pull")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								tests/rules/test_git_pull_uncommitted_changes.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tests/rules/test_git_pull_uncommitted_changes.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.git_pull_uncommitted_changes import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr():
 | 
			
		||||
    return '''error: Cannot pull with rebase: You have unstaged changes.'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_match(stderr):
 | 
			
		||||
    assert match(Command('git pull', stderr=stderr))
 | 
			
		||||
    assert not match(Command('git pull'))
 | 
			
		||||
    assert not match(Command('ls', stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command(stderr):
 | 
			
		||||
    assert (get_new_command(Command('git pull', stderr=stderr))
 | 
			
		||||
            == "git stash && git pull && git stash pop")
 | 
			
		||||
							
								
								
									
										19
									
								
								tests/rules/test_git_pull_unstaged_changes.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tests/rules/test_git_pull_unstaged_changes.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.git_pull_uncommitted_changes import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr():
 | 
			
		||||
    return '''error: Cannot pull with rebase: Your index contains uncommitted changes.'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_match(stderr):
 | 
			
		||||
    assert match(Command('git pull', stderr=stderr))
 | 
			
		||||
    assert not match(Command('git pull'))
 | 
			
		||||
    assert not match(Command('ls', stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command(stderr):
 | 
			
		||||
    assert (get_new_command(Command('git pull', stderr=stderr))
 | 
			
		||||
            == "git stash && git pull && git stash pop")
 | 
			
		||||
@@ -14,6 +14,7 @@ To push the current branch and set the remote as upstream, use
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_match(stderr):
 | 
			
		||||
    assert match(Command('git push', stderr=stderr))
 | 
			
		||||
    assert match(Command('git push master', stderr=stderr))
 | 
			
		||||
    assert not match(Command('git push master'))
 | 
			
		||||
    assert not match(Command('ls', stderr=stderr))
 | 
			
		||||
@@ -22,3 +23,11 @@ def test_match(stderr):
 | 
			
		||||
def test_get_new_command(stderr):
 | 
			
		||||
    assert get_new_command(Command('git push', stderr=stderr))\
 | 
			
		||||
        == "git push --set-upstream origin master"
 | 
			
		||||
    assert get_new_command(Command('git push -u', stderr=stderr))\
 | 
			
		||||
        == "git push --set-upstream origin master"
 | 
			
		||||
    assert get_new_command(Command('git push -u origin', stderr=stderr))\
 | 
			
		||||
        == "git push --set-upstream origin master"
 | 
			
		||||
    assert get_new_command(Command('git push --set-upstream origin', stderr=stderr))\
 | 
			
		||||
        == "git push --set-upstream origin master"
 | 
			
		||||
    assert get_new_command(Command('git push --quiet', stderr=stderr))\
 | 
			
		||||
        == "git push --set-upstream origin master --quiet"
 | 
			
		||||
 
 | 
			
		||||
@@ -39,12 +39,7 @@ To /tmp/bar
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command(script='git push', stderr=git_err),
 | 
			
		||||
    Command(script='git push nvbn', stderr=git_err),
 | 
			
		||||
    Command(script='git push nvbn master', stderr=git_err)])
 | 
			
		||||
def test_match(command):
 | 
			
		||||
    assert match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command(script='git push nvbn master', stderr=git_err),
 | 
			
		||||
    Command(script='git push', stderr=git_err2),
 | 
			
		||||
    Command(script='git push nvbn', stderr=git_err2),
 | 
			
		||||
    Command(script='git push nvbn master', stderr=git_err2)])
 | 
			
		||||
@@ -68,12 +63,7 @@ def test_not_match(command):
 | 
			
		||||
    (Command(script='git push nvbn', stderr=git_err),
 | 
			
		||||
     'git pull nvbn && git push nvbn'),
 | 
			
		||||
    (Command(script='git push nvbn master', stderr=git_err),
 | 
			
		||||
     'git pull nvbn master && git push nvbn master')])
 | 
			
		||||
def test_get_new_command(command, output):
 | 
			
		||||
    assert get_new_command(command) == output
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, output', [
 | 
			
		||||
     'git pull nvbn master && git push nvbn master'),
 | 
			
		||||
    (Command(script='git push', stderr=git_err2), 'git pull && git push'),
 | 
			
		||||
    (Command(script='git push nvbn', stderr=git_err2),
 | 
			
		||||
     'git pull nvbn && git push nvbn'),
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								tests/rules/test_git_push_without_commits.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								tests/rules/test_git_push_without_commits.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
from thefuck.rules.git_push_without_commits import (
 | 
			
		||||
    fix,
 | 
			
		||||
    get_new_command,
 | 
			
		||||
    match,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
command = 'git push -u origin master'
 | 
			
		||||
expected_error = '''
 | 
			
		||||
error: src refspec master does not match any.
 | 
			
		||||
error: failed to push some refs to 'git@github.com:User/repo.git'
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [Command(command, stderr=expected_error)])
 | 
			
		||||
def test_match(command):
 | 
			
		||||
    assert match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, result', [(
 | 
			
		||||
    Command(command, stderr=expected_error),
 | 
			
		||||
    fix.format(command=command),
 | 
			
		||||
)])
 | 
			
		||||
def test_get_new_command(command, result):
 | 
			
		||||
    assert get_new_command(command) == result
 | 
			
		||||
							
								
								
									
										40
									
								
								tests/rules/test_git_rebase_merge_dir.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								tests/rules/test_git_rebase_merge_dir.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.git_rebase_merge_dir import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr():
 | 
			
		||||
    return ('\n\nIt seems that there is already a rebase-merge directory, and\n'
 | 
			
		||||
            'I wonder if you are in the middle of another rebase.  If that is the\n'
 | 
			
		||||
            'case, please try\n'
 | 
			
		||||
            '\tgit rebase (--continue | --abort | --skip)\n'
 | 
			
		||||
            'If that is not the case, please\n'
 | 
			
		||||
            '\trm -fr "/foo/bar/baz/egg/.git/rebase-merge"\n'
 | 
			
		||||
            'and run me again.  I am stopping in case you still have something\n'
 | 
			
		||||
            'valuable there.\n')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', [
 | 
			
		||||
    ('git rebase master'), ('git rebase -skip'), ('git rebase')])
 | 
			
		||||
def test_match(stderr, script):
 | 
			
		||||
    assert match(Command(script=script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', ['git rebase master', 'git rebase -abort'])
 | 
			
		||||
def test_not_match(script):
 | 
			
		||||
    assert not match(Command(script=script))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, result', [
 | 
			
		||||
    ('git rebase master', [
 | 
			
		||||
        'git rebase --abort', 'git rebase --skip', 'git rebase --continue',
 | 
			
		||||
        'rm -fr "/foo/bar/baz/egg/.git/rebase-merge"']),
 | 
			
		||||
    ('git rebase -skip', [
 | 
			
		||||
        'git rebase --skip', 'git rebase --abort', 'git rebase --continue',
 | 
			
		||||
        'rm -fr "/foo/bar/baz/egg/.git/rebase-merge"']),
 | 
			
		||||
    ('git rebase', [
 | 
			
		||||
        'git rebase --skip', 'git rebase --abort', 'git rebase --continue',
 | 
			
		||||
        'rm -fr "/foo/bar/baz/egg/.git/rebase-merge"'])])
 | 
			
		||||
def test_get_new_command(stderr, script, result):
 | 
			
		||||
    assert get_new_command(Command(script=script, stderr=stderr)) == result
 | 
			
		||||
@@ -14,11 +14,11 @@ def test_match(command):
 | 
			
		||||
    Command('git remote add origin url'),
 | 
			
		||||
    Command('git remote remove origin'),
 | 
			
		||||
    Command('git remote prune origin'),
 | 
			
		||||
    Command('git remote set-branches origin branch')
 | 
			
		||||
    ])
 | 
			
		||||
    Command('git remote set-branches origin branch')])
 | 
			
		||||
def test_not_match(command):
 | 
			
		||||
    assert not match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, new_command', [
 | 
			
		||||
    (Command('git remote set-url origin git@github.com:nvbn/thefuck.git'),
 | 
			
		||||
     'git remote add origin git@github.com:nvbn/thefuck.git')])
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								tests/rules/test_git_rm_local_modifications.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								tests/rules/test_git_rm_local_modifications.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.git_rm_local_modifications import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr(target):
 | 
			
		||||
    return ('error: the following file has local modifications:\n    {}\n(use '
 | 
			
		||||
            '--cached to keep the file, or -f to force removal)').format(target)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, target', [
 | 
			
		||||
    ('git rm foo', 'foo'),
 | 
			
		||||
    ('git rm foo bar', 'bar')])
 | 
			
		||||
def test_match(stderr, script, target):
 | 
			
		||||
    assert match(Command(script=script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', ['git rm foo', 'git rm foo bar', 'git rm'])
 | 
			
		||||
def test_not_match(script):
 | 
			
		||||
    assert not match(Command(script=script, stderr=''))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, target, new_command', [
 | 
			
		||||
    ('git rm foo', 'foo', ['git rm --cached foo', 'git rm -f foo']),
 | 
			
		||||
    ('git rm foo bar', 'bar', ['git rm --cached foo bar', 'git rm -f foo bar'])])
 | 
			
		||||
def test_get_new_command(stderr, script, target, new_command):
 | 
			
		||||
    assert get_new_command(Command(script=script, stderr=stderr)) == new_command
 | 
			
		||||
							
								
								
									
										28
									
								
								tests/rules/test_git_rm_staged.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								tests/rules/test_git_rm_staged.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.git_rm_staged import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr(target):
 | 
			
		||||
    return ('error: the following file has changes staged in the index:\n    {}\n(use '
 | 
			
		||||
            '--cached to keep the file, or -f to force removal)').format(target)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, target', [
 | 
			
		||||
    ('git rm foo', 'foo'),
 | 
			
		||||
    ('git rm foo bar', 'bar')])
 | 
			
		||||
def test_match(stderr, script, target):
 | 
			
		||||
    assert match(Command(script=script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', ['git rm foo', 'git rm foo bar', 'git rm'])
 | 
			
		||||
def test_not_match(script):
 | 
			
		||||
    assert not match(Command(script=script, stderr=''))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, target, new_command', [
 | 
			
		||||
    ('git rm foo', 'foo', ['git rm --cached foo', 'git rm -f foo']),
 | 
			
		||||
    ('git rm foo bar', 'bar', ['git rm --cached foo bar', 'git rm -f foo bar'])])
 | 
			
		||||
def test_get_new_command(stderr, script, target, new_command):
 | 
			
		||||
    assert get_new_command(Command(script=script, stderr=stderr)) == new_command
 | 
			
		||||
@@ -4,14 +4,14 @@ from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
cherry_pick_error = (
 | 
			
		||||
        'error: Your local changes would be overwritten by cherry-pick.\n'
 | 
			
		||||
        'hint: Commit your changes or stash them to proceed.\n'
 | 
			
		||||
        'fatal: cherry-pick failed')
 | 
			
		||||
    'error: Your local changes would be overwritten by cherry-pick.\n'
 | 
			
		||||
    'hint: Commit your changes or stash them to proceed.\n'
 | 
			
		||||
    'fatal: cherry-pick failed')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
rebase_error = (
 | 
			
		||||
        'Cannot rebase: Your index contains uncommitted changes.\n'
 | 
			
		||||
        'Please commit or stash them.')
 | 
			
		||||
    'Cannot rebase: Your index contains uncommitted changes.\n'
 | 
			
		||||
    'Please commit or stash them.')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								tests/rules/test_git_stash_pop.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								tests/rules/test_git_stash_pop.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.git_stash_pop import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr():
 | 
			
		||||
    return '''error: Your local changes to the following files would be overwritten by merge:'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_match(stderr):
 | 
			
		||||
    assert match(Command('git stash pop', stderr=stderr))
 | 
			
		||||
    assert not match(Command('git stash'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command(stderr):
 | 
			
		||||
    assert (get_new_command(Command('git stash pop', stderr=stderr))
 | 
			
		||||
            == "git add --update && git stash pop && git reset .")
 | 
			
		||||
							
								
								
									
										18
									
								
								tests/rules/test_git_tag_force.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								tests/rules/test_git_tag_force.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.git_tag_force import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def stderr():
 | 
			
		||||
    return '''fatal: tag 'alert' already exists'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_match(stderr):
 | 
			
		||||
    assert match(Command('git tag alert', stderr=stderr))
 | 
			
		||||
    assert not match(Command('git tag alert'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command(stderr):
 | 
			
		||||
    assert (get_new_command(Command('git tag alert', stderr=stderr))
 | 
			
		||||
            == "git tag --force alert")
 | 
			
		||||
@@ -7,7 +7,7 @@ def test_match():
 | 
			
		||||
    with patch('os.path.exists', return_value=True):
 | 
			
		||||
        assert match(Command(script='main', stderr='main: command not found'))
 | 
			
		||||
        assert match(Command(script='main --help',
 | 
			
		||||
                          stderr='main: command not found'))
 | 
			
		||||
                             stderr='main: command not found'))
 | 
			
		||||
        assert not match(Command(script='main', stderr=''))
 | 
			
		||||
 | 
			
		||||
    with patch('os.path.exists', return_value=False):
 | 
			
		||||
 
 | 
			
		||||
@@ -1,34 +1,31 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
from thefuck.rules.heroku_not_command import match, get_new_command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def suggest_stderr(cmd):
 | 
			
		||||
    return ''' !    `{}` is not a heroku command.
 | 
			
		||||
     !    Perhaps you meant `logs`, `pg`.
 | 
			
		||||
     !    See `heroku help` for a list of available commands.'''.format(cmd)
 | 
			
		||||
suggest_stderr = '''
 | 
			
		||||
 ▸    log is not a heroku command.
 | 
			
		||||
 ▸    Perhaps you meant logs?
 | 
			
		||||
 ▸    Run heroku _ to run heroku logs.
 | 
			
		||||
 ▸    Run heroku help for a list of available commands.'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
no_suggest_stderr = ''' !    `aaaaa` is not a heroku command.
 | 
			
		||||
 !    See `heroku help` for a list of available commands.'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('cmd', ['log', 'pge'])
 | 
			
		||||
@pytest.mark.parametrize('cmd', ['log'])
 | 
			
		||||
def test_match(cmd):
 | 
			
		||||
    assert match(
 | 
			
		||||
        Command('heroku {}'.format(cmd), stderr=suggest_stderr(cmd)))
 | 
			
		||||
        Command('heroku {}'.format(cmd), stderr=suggest_stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr', [
 | 
			
		||||
    ('cat log', suggest_stderr('log')),
 | 
			
		||||
    ('heroku aaa', no_suggest_stderr)])
 | 
			
		||||
    ('cat log', suggest_stderr)])
 | 
			
		||||
def test_not_match(script, stderr):
 | 
			
		||||
    assert not match(Command(script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('cmd, result', [
 | 
			
		||||
    ('log', ['heroku logs', 'heroku pg']),
 | 
			
		||||
    ('pge', ['heroku pg', 'heroku logs'])])
 | 
			
		||||
    ('log', 'heroku logs')])
 | 
			
		||||
def test_get_new_command(cmd, result):
 | 
			
		||||
    command = Command('heroku {}'.format(cmd), stderr=suggest_stderr(cmd))
 | 
			
		||||
    command = Command('heroku {}'.format(cmd), stderr=suggest_stderr)
 | 
			
		||||
    assert get_new_command(command) == result
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								tests/rules/test_hostscli.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								tests/rules/test_hostscli.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.hostscli import no_website, get_new_command, match
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
no_website_long = '''
 | 
			
		||||
{}:
 | 
			
		||||
 | 
			
		||||
No Domain list found for website: a_website_that_does_not_exist
 | 
			
		||||
 | 
			
		||||
Please raise a Issue here: https://github.com/dhilipsiva/hostscli/issues/new
 | 
			
		||||
if you think we should add domains for this website.
 | 
			
		||||
 | 
			
		||||
type `hostscli websites` to see a list of websites that you can block/unblock
 | 
			
		||||
'''.format(no_website)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command('hostscli block a_website_that_does_not_exist',
 | 
			
		||||
            stderr=no_website_long)])
 | 
			
		||||
def test_match(command):
 | 
			
		||||
    assert match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, result', [(
 | 
			
		||||
    Command('hostscli block a_website_that_does_not_exist',
 | 
			
		||||
            stderr=no_website_long),
 | 
			
		||||
    ['hostscli websites'])])
 | 
			
		||||
def test_get_new_command(command, result):
 | 
			
		||||
    assert get_new_command(command) == result
 | 
			
		||||
							
								
								
									
										53
									
								
								tests/rules/test_ifconfig_device_not_found.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								tests/rules/test_ifconfig_device_not_found.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from six import BytesIO
 | 
			
		||||
from thefuck.rules.ifconfig_device_not_found import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
stderr = '{}: error fetching interface information: Device not found'
 | 
			
		||||
 | 
			
		||||
stdout = b'''
 | 
			
		||||
wlp2s0    Link encap:Ethernet  HWaddr 5c:51:4f:7c:58:5d
 | 
			
		||||
          inet addr:192.168.0.103  Bcast:192.168.0.255  Mask:255.255.255.0
 | 
			
		||||
          inet6 addr: fe80::be23:69b9:96d2:6d39/64 Scope:Link
 | 
			
		||||
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
 | 
			
		||||
          RX packets:23581604 errors:0 dropped:0 overruns:0 frame:0
 | 
			
		||||
          TX packets:17017655 errors:0 dropped:0 overruns:0 carrier:0
 | 
			
		||||
          collisions:0 txqueuelen:1000
 | 
			
		||||
          RX bytes:16148429061 (16.1 GB)  TX bytes:7067533695 (7.0 GB)
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def ifconfig(mocker):
 | 
			
		||||
    mock = mocker.patch(
 | 
			
		||||
        'thefuck.rules.ifconfig_device_not_found.subprocess.Popen')
 | 
			
		||||
    mock.return_value.stdout = BytesIO(stdout)
 | 
			
		||||
    return mock
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr', [
 | 
			
		||||
    ('ifconfig wlan0', stderr.format('wlan0')),
 | 
			
		||||
    ('ifconfig -s eth0', stderr.format('eth0')),
 | 
			
		||||
])
 | 
			
		||||
def test_match(script, stderr):
 | 
			
		||||
    assert match(Command(script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr', [
 | 
			
		||||
    ('config wlan0',
 | 
			
		||||
     'wlan0: error fetching interface information: Device not found'),
 | 
			
		||||
    ('ifconfig eth0', ''),
 | 
			
		||||
])
 | 
			
		||||
def test_not_match(script, stderr):
 | 
			
		||||
    assert not match(Command(script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, result', [
 | 
			
		||||
    ('ifconfig wlan0', ['ifconfig wlp2s0']),
 | 
			
		||||
    ('ifconfig -s wlan0', ['ifconfig -s wlp2s0']),
 | 
			
		||||
])
 | 
			
		||||
def test_get_new_comman(script, result):
 | 
			
		||||
    new_command = get_new_command(
 | 
			
		||||
        Command(script, stderr=stderr.format('wlan0')))
 | 
			
		||||
    assert new_command == result
 | 
			
		||||
@@ -19,5 +19,5 @@ def test_match(is_not_task):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command(is_not_task):
 | 
			
		||||
    assert get_new_command(Command(script='lein rpl --help', stderr=is_not_task)) \
 | 
			
		||||
           == ['lein repl --help', 'lein jar --help']
 | 
			
		||||
    assert (get_new_command(Command(script='lein rpl --help', stderr=is_not_task))
 | 
			
		||||
            == ['lein repl --help', 'lein jar --help'])
 | 
			
		||||
 
 | 
			
		||||
@@ -11,16 +11,6 @@ def file_exists(mocker):
 | 
			
		||||
get_stderr = "ln: failed to create symbolic link '{}': File exists".format
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.usefixtures('file_exists')
 | 
			
		||||
@pytest.mark.parametrize('script', [
 | 
			
		||||
    'ln -s dest source',
 | 
			
		||||
    'ln dest -s source',
 | 
			
		||||
    'ln dest source -s'])
 | 
			
		||||
def test_match(script):
 | 
			
		||||
    stderr = get_stderr('source')
 | 
			
		||||
    assert match(Command(script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr, exists', [
 | 
			
		||||
    ('ln dest source', get_stderr('source'), True),
 | 
			
		||||
    ('ls -s dest source', get_stderr('source'), True),
 | 
			
		||||
@@ -38,4 +28,5 @@ def test_not_match(file_exists, script, stderr, exists):
 | 
			
		||||
    ('ln dest source -s', 'ln source -s dest')])
 | 
			
		||||
def test_match(script, result):
 | 
			
		||||
    stderr = get_stderr('source')
 | 
			
		||||
    assert match(Command(script, stderr=stderr))
 | 
			
		||||
    assert get_new_command(Command(script, stderr=stderr)) == result
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								tests/rules/test_ls_all.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								tests/rules/test_ls_all.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
from thefuck.rules.ls_all import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_match():
 | 
			
		||||
    assert match(Command(script='ls'))
 | 
			
		||||
    assert not match(Command(script='ls', stdout='file.py\n'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command():
 | 
			
		||||
    assert get_new_command(Command(script='ls empty_dir')) == 'ls -A empty_dir'
 | 
			
		||||
    assert get_new_command(Command(script='ls')) == 'ls -A'
 | 
			
		||||
@@ -23,7 +23,8 @@ def test_not_match(command):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, new_command', [
 | 
			
		||||
    (Command('man read'), ['man 3 read', 'man 2 read']),
 | 
			
		||||
    (Command('man read'), ['man 3 read', 'man 2 read', 'read --help']),
 | 
			
		||||
    (Command('man missing', stderr="No manual entry for missing\n"), ['missing --help']),
 | 
			
		||||
    (Command('man 2 read'), 'man 3 read'),
 | 
			
		||||
    (Command('man 3 read'), 'man 2 read'),
 | 
			
		||||
    (Command('man -s2 read'), 'man -s3 read'),
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								tests/rules/test_missing_space_before_subcommand.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								tests/rules/test_missing_space_before_subcommand.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.missing_space_before_subcommand import (
 | 
			
		||||
    match, get_new_command)
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def all_executables(mocker):
 | 
			
		||||
    return mocker.patch(
 | 
			
		||||
        'thefuck.rules.missing_space_before_subcommand.get_all_executables',
 | 
			
		||||
        return_value=['git', 'ls', 'npm'])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', [
 | 
			
		||||
    'gitbranch', 'ls-la', 'npminstall'])
 | 
			
		||||
def test_match(script):
 | 
			
		||||
    assert match(Command(script))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script', ['git branch', 'vimfile'])
 | 
			
		||||
def test_not_match(script):
 | 
			
		||||
    assert not match(Command(script))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, result', [
 | 
			
		||||
    ('gitbranch', 'git branch'),
 | 
			
		||||
    ('ls-la', 'ls -la'),
 | 
			
		||||
    ('npminstall webpack', 'npm install webpack')])
 | 
			
		||||
def test_get_new_command(script, result):
 | 
			
		||||
    assert get_new_command(Command(script)) == result
 | 
			
		||||
@@ -25,7 +25,7 @@ def test_match(command):
 | 
			
		||||
[INFO] Finished at: Wed Aug 26 13:05:47 BST 2015
 | 
			
		||||
[INFO] Final Memory: 6M/240M
 | 
			
		||||
[INFO] ------------------------------------------------------------------------
 | 
			
		||||
"""),
 | 
			
		||||
"""),  # noqa
 | 
			
		||||
    Command(script='mvn --help'),
 | 
			
		||||
    Command(script='mvn -v')
 | 
			
		||||
])
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ def test_match(command):
 | 
			
		||||
[INFO] Finished at: Wed Aug 26 13:05:47 BST 2015
 | 
			
		||||
[INFO] Final Memory: 6M/240M
 | 
			
		||||
[INFO] ------------------------------------------------------------------------
 | 
			
		||||
"""),
 | 
			
		||||
"""),  # noqa
 | 
			
		||||
    Command(script='mvn --help'),
 | 
			
		||||
    Command(script='mvn -v')
 | 
			
		||||
])
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										43
									
								
								tests/rules/test_path_from_history.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								tests/rules/test_path_from_history.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.path_from_history import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def history(mocker):
 | 
			
		||||
    return mocker.patch(
 | 
			
		||||
        'thefuck.rules.path_from_history.get_valid_history_without_current',
 | 
			
		||||
        return_value=['cd /opt/java', 'ls ~/work/project/'])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def path_exists(mocker):
 | 
			
		||||
    path_mock = mocker.patch('thefuck.rules.path_from_history.Path')
 | 
			
		||||
    exists_mock = path_mock.return_value.expanduser.return_value.exists
 | 
			
		||||
    exists_mock.return_value = True
 | 
			
		||||
    return exists_mock
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr', [
 | 
			
		||||
    ('ls project', 'no such file or directory: project'),
 | 
			
		||||
    ('cd project', "can't cd to project"),
 | 
			
		||||
])
 | 
			
		||||
def test_match(script, stderr):
 | 
			
		||||
    assert match(Command(script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr', [
 | 
			
		||||
    ('myapp cats', 'no such file or directory: project'),
 | 
			
		||||
    ('cd project', ""),
 | 
			
		||||
])
 | 
			
		||||
def test_not_match(script, stderr):
 | 
			
		||||
    assert not match(Command(script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr, result', [
 | 
			
		||||
    ('ls project', 'no such file or directory: project', 'ls ~/work/project'),
 | 
			
		||||
    ('cd java', "can't cd to java", 'cd /opt/java'),
 | 
			
		||||
])
 | 
			
		||||
def test_get_new_command(script, stderr, result):
 | 
			
		||||
    new_command = get_new_command(Command(script, stderr=stderr))
 | 
			
		||||
    assert new_command[0] == result
 | 
			
		||||
@@ -8,5 +8,5 @@ def test_match():
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command():
 | 
			
		||||
    assert get_new_command(Command('./test_sudo.py'))\
 | 
			
		||||
           == 'python ./test_sudo.py'
 | 
			
		||||
    assert (get_new_command(Command('./test_sudo.py'))
 | 
			
		||||
            == 'python ./test_sudo.py')
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								tests/rules/test_remove_trailing_cedilla.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								tests/rules/test_remove_trailing_cedilla.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.remove_trailing_cedilla import match, get_new_command, CEDILLA
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command(script='wrong' + CEDILLA),
 | 
			
		||||
    Command(script='wrong with args' + CEDILLA)])
 | 
			
		||||
def test_match(command):
 | 
			
		||||
    assert match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, new_command', [
 | 
			
		||||
    (Command('wrong' + CEDILLA), 'wrong'),
 | 
			
		||||
    (Command('wrong with args' + CEDILLA), 'wrong with args')])
 | 
			
		||||
def test_get_new_command(command, new_command):
 | 
			
		||||
    assert get_new_command(command) == new_command
 | 
			
		||||
@@ -17,5 +17,5 @@ def test_not_match(command):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command():
 | 
			
		||||
    assert get_new_command(Command(script='rm -rf /')) \
 | 
			
		||||
           == 'rm -rf / --no-preserve-root'
 | 
			
		||||
    assert (get_new_command(Command(script='rm -rf /'))
 | 
			
		||||
            == 'rm -rf / --no-preserve-root')
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										46
									
								
								tests/rules/test_scm_correction.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								tests/rules/test_scm_correction.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.scm_correction import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def get_actual_scm_mock(mocker):
 | 
			
		||||
    return mocker.patch('thefuck.rules.scm_correction._get_actual_scm',
 | 
			
		||||
                        return_value=None)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr, actual_scm', [
 | 
			
		||||
    ('git log', 'fatal: Not a git repository '
 | 
			
		||||
                '(or any of the parent directories): .git',
 | 
			
		||||
     'hg'),
 | 
			
		||||
    ('hg log', "abort: no repository found in '/home/nvbn/exp/thefuck' "
 | 
			
		||||
               "(.hg not found)!",
 | 
			
		||||
     'git')])
 | 
			
		||||
def test_match(get_actual_scm_mock, script, stderr, actual_scm):
 | 
			
		||||
    get_actual_scm_mock.return_value = actual_scm
 | 
			
		||||
    assert match(Command(script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr, actual_scm', [
 | 
			
		||||
    ('git log', '', 'hg'),
 | 
			
		||||
    ('git log', 'fatal: Not a git repository '
 | 
			
		||||
                '(or any of the parent directories): .git',
 | 
			
		||||
     None),
 | 
			
		||||
    ('hg log', "abort: no repository found in '/home/nvbn/exp/thefuck' "
 | 
			
		||||
               "(.hg not found)!",
 | 
			
		||||
     None),
 | 
			
		||||
    ('not-scm log', "abort: no repository found in '/home/nvbn/exp/thefuck' "
 | 
			
		||||
                    "(.hg not found)!",
 | 
			
		||||
     'git')])
 | 
			
		||||
def test_not_match(get_actual_scm_mock, script, stderr, actual_scm):
 | 
			
		||||
    get_actual_scm_mock.return_value = actual_scm
 | 
			
		||||
    assert not match(Command(script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, actual_scm, result', [
 | 
			
		||||
    ('git log', 'hg', 'hg log'),
 | 
			
		||||
    ('hg log', 'git', 'git log')])
 | 
			
		||||
def test_get_new_command(get_actual_scm_mock, script, actual_scm, result):
 | 
			
		||||
    get_actual_scm_mock.return_value = actual_scm
 | 
			
		||||
    new_command = get_new_command(Command(script))
 | 
			
		||||
    assert new_command == result
 | 
			
		||||
@@ -18,11 +18,11 @@ def test_match(sed_unterminated_s):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_get_new_command(sed_unterminated_s):
 | 
			
		||||
    assert get_new_command(Command('sed -e s/foo/bar', stderr=sed_unterminated_s)) \
 | 
			
		||||
            == 'sed -e s/foo/bar/'
 | 
			
		||||
    assert get_new_command(Command('sed -es/foo/bar', stderr=sed_unterminated_s)) \
 | 
			
		||||
            == 'sed -es/foo/bar/'
 | 
			
		||||
    assert get_new_command(Command(r"sed -e 's/\/foo/bar'", stderr=sed_unterminated_s)) \
 | 
			
		||||
            == r"sed -e 's/\/foo/bar/'"
 | 
			
		||||
    assert get_new_command(Command(r"sed -e s/foo/bar -es/baz/quz", stderr=sed_unterminated_s)) \
 | 
			
		||||
            == r"sed -e s/foo/bar/ -es/baz/quz/"
 | 
			
		||||
    assert (get_new_command(Command('sed -e s/foo/bar', stderr=sed_unterminated_s))
 | 
			
		||||
            == 'sed -e s/foo/bar/')
 | 
			
		||||
    assert (get_new_command(Command('sed -es/foo/bar', stderr=sed_unterminated_s))
 | 
			
		||||
            == 'sed -es/foo/bar/')
 | 
			
		||||
    assert (get_new_command(Command(r"sed -e 's/\/foo/bar'", stderr=sed_unterminated_s))
 | 
			
		||||
            == r"sed -e 's/\/foo/bar/'")
 | 
			
		||||
    assert (get_new_command(Command(r"sed -e s/foo/bar -es/baz/quz", stderr=sed_unterminated_s))
 | 
			
		||||
            == r"sed -e s/foo/bar/ -es/baz/quz/")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										39
									
								
								tests/rules/test_sudo_command_from_user_path.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								tests/rules/test_sudo_command_from_user_path.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.sudo_command_from_user_path import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
stderr = 'sudo: {}: command not found'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def which(mocker):
 | 
			
		||||
    return mocker.patch('thefuck.rules.sudo_command_from_user_path.which',
 | 
			
		||||
                        return_value='/usr/bin/app')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr', [
 | 
			
		||||
    ('sudo npm install -g react-native-cli', stderr.format('npm')),
 | 
			
		||||
    ('sudo -u app appcfg update .', stderr.format('appcfg'))])
 | 
			
		||||
def test_match(script, stderr):
 | 
			
		||||
    assert match(Command(script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr, which_result', [
 | 
			
		||||
    ('npm --version', stderr.format('npm'), '/usr/bin/npm'),
 | 
			
		||||
    ('sudo npm --version', '', '/usr/bin/npm'),
 | 
			
		||||
    ('sudo npm --version', stderr.format('npm'), None)])
 | 
			
		||||
def test_not_match(which, script, stderr, which_result):
 | 
			
		||||
    which.return_value = which_result
 | 
			
		||||
    assert not match(Command(script, stderr=stderr))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('script, stderr, result', [
 | 
			
		||||
    ('sudo npm install -g react-native-cli',
 | 
			
		||||
     stderr.format('npm'),
 | 
			
		||||
     'sudo env "PATH=$PATH" npm install -g react-native-cli'),
 | 
			
		||||
    ('sudo -u app appcfg update .',
 | 
			
		||||
     stderr.format('appcfg'),
 | 
			
		||||
     'sudo -u app env "PATH=$PATH" appcfg update .')])
 | 
			
		||||
def test_get_new_command(script, stderr, result):
 | 
			
		||||
    assert get_new_command(Command(script, stderr=stderr)) == result
 | 
			
		||||
@@ -23,12 +23,12 @@ def test_not_match(command):
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, new_command', [
 | 
			
		||||
    (Command('hdfs dfs ls',
 | 
			
		||||
        stderr='ls: Unknown command\nDid you mean -ls?  This command begins with a dash.'), ['hdfs dfs -ls']),
 | 
			
		||||
             stderr='ls: Unknown command\nDid you mean -ls?  This command begins with a dash.'), ['hdfs dfs -ls']),
 | 
			
		||||
    (Command('hdfs dfs rm /foo/bar',
 | 
			
		||||
        stderr='rm: Unknown command\nDid you mean -rm?  This command begins with a dash.'), ['hdfs dfs -rm /foo/bar']),
 | 
			
		||||
             stderr='rm: Unknown command\nDid you mean -rm?  This command begins with a dash.'), ['hdfs dfs -rm /foo/bar']),
 | 
			
		||||
    (Command('./bin/hdfs dfs ls -R /foo/bar',
 | 
			
		||||
        stderr='ls: Unknown command\nDid you mean -ls?  This command begins with a dash.'), ['./bin/hdfs dfs -ls -R /foo/bar']),
 | 
			
		||||
             stderr='ls: Unknown command\nDid you mean -ls?  This command begins with a dash.'), ['./bin/hdfs dfs -ls -R /foo/bar']),
 | 
			
		||||
    (Command('./bin/hdfs dfs -Dtest=fred ls -R /foo/bar',
 | 
			
		||||
        stderr='ls: Unknown command\nDid you mean -ls?  This command begins with a dash.'), ['./bin/hdfs dfs -Dtest=fred -ls -R /foo/bar'])])
 | 
			
		||||
             stderr='ls: Unknown command\nDid you mean -ls?  This command begins with a dash.'), ['./bin/hdfs dfs -Dtest=fred -ls -R /foo/bar'])])
 | 
			
		||||
def test_get_new_command(command, new_command):
 | 
			
		||||
    assert get_new_command(command) == new_command
 | 
			
		||||
 
 | 
			
		||||
@@ -27,8 +27,8 @@ def test_not_match(command):
 | 
			
		||||
    (Command(script='vagrant ssh', stderr='VM must be running to open SSH connection. Run `vagrant up`\nto start the virtual machine.'), 'vagrant up && vagrant ssh'),
 | 
			
		||||
    (Command(script='vagrant ssh devbox', stderr='VM must be running to open SSH connection. Run `vagrant up`\nto start the virtual machine.'), ['vagrant up devbox && vagrant ssh devbox', 'vagrant up && vagrant ssh devbox']),
 | 
			
		||||
    (Command(script='vagrant rdp',
 | 
			
		||||
            stderr='VM must be created before running this command. Run `vagrant up` first.'), 'vagrant up && vagrant rdp'),
 | 
			
		||||
             stderr='VM must be created before running this command. Run `vagrant up` first.'), 'vagrant up && vagrant rdp'),
 | 
			
		||||
    (Command(script='vagrant rdp devbox',
 | 
			
		||||
            stderr='VM must be created before running this command. Run `vagrant up` first.'), ['vagrant up devbox && vagrant rdp devbox', 'vagrant up && vagrant rdp devbox'])])
 | 
			
		||||
             stderr='VM must be created before running this command. Run `vagrant up` first.'), ['vagrant up devbox && vagrant rdp devbox', 'vagrant up && vagrant rdp devbox'])])
 | 
			
		||||
def test_get_new_command(command, new_command):
 | 
			
		||||
    assert get_new_command(command) == new_command
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								tests/rules/test_yarn_alias.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								tests/rules/test_yarn_alias.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.yarn_alias import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
stderr_remove = 'error Did you mean `yarn remove`?'
 | 
			
		||||
stderr_etl = 'error Command "etil" not found. Did you mean "etl"?'
 | 
			
		||||
stderr_list = 'error Did you mean `yarn list`?'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command(script='yarn rm', stderr=stderr_remove),
 | 
			
		||||
    Command(script='yarn etil', stderr=stderr_etl),
 | 
			
		||||
    Command(script='yarn ls', stderr=stderr_list)])
 | 
			
		||||
def test_match(command):
 | 
			
		||||
    assert match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, new_command', [
 | 
			
		||||
    (Command('yarn rm', stderr=stderr_remove), 'yarn remove'),
 | 
			
		||||
    (Command('yarn etil', stderr=stderr_etl), 'yarn etl'),
 | 
			
		||||
    (Command('yarn ls', stderr=stderr_list), 'yarn list')])
 | 
			
		||||
def test_get_new_command(command, new_command):
 | 
			
		||||
    assert get_new_command(command) == new_command
 | 
			
		||||
							
								
								
									
										118
									
								
								tests/rules/test_yarn_command_not_found.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								tests/rules/test_yarn_command_not_found.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
			
		||||
# -*- encoding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
from io import BytesIO
 | 
			
		||||
import pytest
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
from thefuck.rules.yarn_command_not_found import match, get_new_command
 | 
			
		||||
 | 
			
		||||
stderr = '''
 | 
			
		||||
error Command "{}" not found.
 | 
			
		||||
'''.format
 | 
			
		||||
 | 
			
		||||
yarn_help_stdout = b'''
 | 
			
		||||
 | 
			
		||||
  Usage: yarn [command] [flags]
 | 
			
		||||
 | 
			
		||||
  Options:
 | 
			
		||||
 | 
			
		||||
    -h, --help                      output usage information
 | 
			
		||||
    -V, --version                   output the version number
 | 
			
		||||
    --verbose                       output verbose messages on internal operations
 | 
			
		||||
    --offline                       trigger an error if any required dependencies are not available in local cache
 | 
			
		||||
    --prefer-offline                use network only if dependencies are not available in local cache
 | 
			
		||||
    --strict-semver                 
 | 
			
		||||
    --json                          
 | 
			
		||||
    --ignore-scripts                don't run lifecycle scripts
 | 
			
		||||
    --har                           save HAR output of network traffic
 | 
			
		||||
    --ignore-platform               ignore platform checks
 | 
			
		||||
    --ignore-engines                ignore engines check
 | 
			
		||||
    --ignore-optional               ignore optional dependencies
 | 
			
		||||
    --force                         ignore all caches
 | 
			
		||||
    --no-bin-links                  don't generate bin links when setting up packages
 | 
			
		||||
    --flat                          only allow one version of a package
 | 
			
		||||
    --prod, --production [prod]     
 | 
			
		||||
    --no-lockfile                   don't read or generate a lockfile
 | 
			
		||||
    --pure-lockfile                 don't generate a lockfile
 | 
			
		||||
    --frozen-lockfile               don't generate a lockfile and fail if an update is needed
 | 
			
		||||
    --link-duplicates               create hardlinks to the repeated modules in node_modules
 | 
			
		||||
    --global-folder <path>          
 | 
			
		||||
    --modules-folder <path>         rather than installing modules into the node_modules folder relative to the cwd, output them here
 | 
			
		||||
    --cache-folder <path>           specify a custom folder to store the yarn cache
 | 
			
		||||
    --mutex <type>[:specifier]      use a mutex to ensure only one yarn instance is executing
 | 
			
		||||
    --no-emoji                      disable emoji in output
 | 
			
		||||
    --proxy <host>                  
 | 
			
		||||
    --https-proxy <host>            
 | 
			
		||||
    --no-progress                   disable progress bar
 | 
			
		||||
    --network-concurrency <number>  maximum number of concurrent network requests
 | 
			
		||||
 | 
			
		||||
  Commands:
 | 
			
		||||
 | 
			
		||||
    - access
 | 
			
		||||
    - add
 | 
			
		||||
    - bin
 | 
			
		||||
    - cache
 | 
			
		||||
    - check
 | 
			
		||||
    - clean
 | 
			
		||||
    - config
 | 
			
		||||
    - generate-lock-entry
 | 
			
		||||
    - global
 | 
			
		||||
    - import
 | 
			
		||||
    - info
 | 
			
		||||
    - init
 | 
			
		||||
    - install
 | 
			
		||||
    - licenses
 | 
			
		||||
    - link
 | 
			
		||||
    - list
 | 
			
		||||
    - login
 | 
			
		||||
    - logout
 | 
			
		||||
    - outdated
 | 
			
		||||
    - owner
 | 
			
		||||
    - pack
 | 
			
		||||
    - publish
 | 
			
		||||
    - remove
 | 
			
		||||
    - run
 | 
			
		||||
    - tag
 | 
			
		||||
    - team
 | 
			
		||||
    - unlink
 | 
			
		||||
    - upgrade
 | 
			
		||||
    - upgrade-interactive
 | 
			
		||||
    - version
 | 
			
		||||
    - versions
 | 
			
		||||
    - why
 | 
			
		||||
 | 
			
		||||
  Run `yarn help COMMAND` for more information on specific commands.
 | 
			
		||||
  Visit https://yarnpkg.com/en/docs/cli/ to learn more about Yarn.
 | 
			
		||||
''' # noqa
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def yarn_help(mocker):
 | 
			
		||||
    patch = mocker.patch('thefuck.rules.yarn_command_not_found.Popen')
 | 
			
		||||
    patch.return_value.stdout = BytesIO(yarn_help_stdout)
 | 
			
		||||
    return patch
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command('yarn whyy webpack', stderr=stderr('whyy'))])
 | 
			
		||||
def test_match(command):
 | 
			
		||||
    assert match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command('npm nuild', stderr=stderr('nuild')),
 | 
			
		||||
    Command('yarn install')])
 | 
			
		||||
def test_not_match(command):
 | 
			
		||||
    assert not match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, result', [
 | 
			
		||||
    (Command('yarn whyy webpack', stderr=stderr('whyy')),
 | 
			
		||||
     'yarn why webpack'),
 | 
			
		||||
    (Command('yarn require lodash', stderr=stderr('require')),
 | 
			
		||||
     'yarn add lodash')])
 | 
			
		||||
def test_get_new_command(command, result):
 | 
			
		||||
    fixed_command = get_new_command(command)
 | 
			
		||||
    if isinstance(fixed_command, list):
 | 
			
		||||
        fixed_command = fixed_command[0]
 | 
			
		||||
 | 
			
		||||
    assert fixed_command == result
 | 
			
		||||
							
								
								
									
										32
									
								
								tests/rules/test_yarn_command_replaced.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								tests/rules/test_yarn_command_replaced.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
from thefuck.rules.yarn_command_replaced import match, get_new_command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
stderr = ('error `install` has been replaced with `add` to add new '
 | 
			
		||||
          'dependencies. Run "yarn add {}" instead.').format
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command(script='yarn install redux', stderr=stderr('redux')),
 | 
			
		||||
    Command(script='yarn install moment', stderr=stderr('moment')),
 | 
			
		||||
    Command(script='yarn install lodash', stderr=stderr('lodash'))])
 | 
			
		||||
def test_match(command):
 | 
			
		||||
    assert match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command('yarn install')])
 | 
			
		||||
def test_not_match(command):
 | 
			
		||||
    assert not match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, new_command', [
 | 
			
		||||
    (Command('yarn install redux', stderr=stderr('redux')),
 | 
			
		||||
     'yarn add redux'),
 | 
			
		||||
    (Command('yarn install moment', stderr=stderr('moment')),
 | 
			
		||||
     'yarn add moment'),
 | 
			
		||||
    (Command('yarn install lodash', stderr=stderr('lodash')),
 | 
			
		||||
     'yarn add lodash')])
 | 
			
		||||
def test_get_new_command(command, new_command):
 | 
			
		||||
    assert get_new_command(command) == new_command
 | 
			
		||||
							
								
								
									
										57
									
								
								tests/rules/test_yarn_help.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								tests/rules/test_yarn_help.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.rules.yarn_help import match, get_new_command
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
from thefuck.system import open_command
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
stdout_clean = '''
 | 
			
		||||
 | 
			
		||||
  Usage: yarn [command] [flags]
 | 
			
		||||
 | 
			
		||||
  Options:
 | 
			
		||||
 | 
			
		||||
    -h, --help                      output usage information
 | 
			
		||||
    -V, --version                   output the version number
 | 
			
		||||
    --verbose                       output verbose messages on internal operations
 | 
			
		||||
    --offline                       trigger an error if any required dependencies are not available in local cache
 | 
			
		||||
    --prefer-offline                use network only if dependencies are not available in local cache
 | 
			
		||||
    --strict-semver                 
 | 
			
		||||
    --json                          
 | 
			
		||||
    --ignore-scripts                don't run lifecycle scripts
 | 
			
		||||
    --har                           save HAR output of network traffic
 | 
			
		||||
    --ignore-platform               ignore platform checks
 | 
			
		||||
    --ignore-engines                ignore engines check
 | 
			
		||||
    --ignore-optional               ignore optional dependencies
 | 
			
		||||
    --force                         ignore all caches
 | 
			
		||||
    --no-bin-links                  don't generate bin links when setting up packages
 | 
			
		||||
    --flat                          only allow one version of a package
 | 
			
		||||
    --prod, --production [prod]     
 | 
			
		||||
    --no-lockfile                   don't read or generate a lockfile
 | 
			
		||||
    --pure-lockfile                 don't generate a lockfile
 | 
			
		||||
    --frozen-lockfile               don't generate a lockfile and fail if an update is needed
 | 
			
		||||
    --link-duplicates               create hardlinks to the repeated modules in node_modules
 | 
			
		||||
    --global-folder <path>          
 | 
			
		||||
    --modules-folder <path>         rather than installing modules into the node_modules folder relative to the cwd, output them here
 | 
			
		||||
    --cache-folder <path>           specify a custom folder to store the yarn cache
 | 
			
		||||
    --mutex <type>[:specifier]      use a mutex to ensure only one yarn instance is executing
 | 
			
		||||
    --no-emoji                      disable emoji in output
 | 
			
		||||
    --proxy <host>                  
 | 
			
		||||
    --https-proxy <host>            
 | 
			
		||||
    --no-progress                   disable progress bar
 | 
			
		||||
    --network-concurrency <number>  maximum number of concurrent network requests
 | 
			
		||||
 | 
			
		||||
  Visit https://yarnpkg.com/en/docs/cli/clean for documentation about this command.
 | 
			
		||||
'''  # noqa
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command', [
 | 
			
		||||
    Command(script='yarn help clean', stdout=stdout_clean)])
 | 
			
		||||
def test_match(command):
 | 
			
		||||
    assert match(command)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('command, url', [
 | 
			
		||||
    (Command('yarn help clean', stdout=stdout_clean),
 | 
			
		||||
     'https://yarnpkg.com/en/docs/cli/clean')])
 | 
			
		||||
def test_get_new_command(command, url):
 | 
			
		||||
    assert get_new_command(command) == open_command(url)
 | 
			
		||||
@@ -20,3 +20,11 @@ def history_lines(mocker):
 | 
			
		||||
            .return_value.readlines.return_value = lines
 | 
			
		||||
 | 
			
		||||
    return aux
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def config_exists(mocker):
 | 
			
		||||
    path_mock = mocker.patch('thefuck.shells.generic.Path')
 | 
			
		||||
    return path_mock.return_value \
 | 
			
		||||
        .expanduser.return_value \
 | 
			
		||||
        .exists
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,9 @@ class TestBash(object):
 | 
			
		||||
    def test_and_(self, shell):
 | 
			
		||||
        assert shell.and_('ls', 'cd') == 'ls && cd'
 | 
			
		||||
 | 
			
		||||
    def test_or_(self, shell):
 | 
			
		||||
        assert shell.or_('ls', 'cd') == 'ls || cd'
 | 
			
		||||
 | 
			
		||||
    def test_get_aliases(self, shell):
 | 
			
		||||
        assert shell.get_aliases() == {'fuck': 'eval $(thefuck $(fc -ln -1))',
 | 
			
		||||
                                       'l': 'ls -CF',
 | 
			
		||||
@@ -40,19 +43,32 @@ class TestBash(object):
 | 
			
		||||
                                       'll': 'ls -alF'}
 | 
			
		||||
 | 
			
		||||
    def test_app_alias(self, shell):
 | 
			
		||||
        assert 'alias fuck' in shell.app_alias('fuck')
 | 
			
		||||
        assert 'alias FUCK' in shell.app_alias('FUCK')
 | 
			
		||||
        assert 'fuck () {' in shell.app_alias('fuck')
 | 
			
		||||
        assert 'FUCK () {' in shell.app_alias('FUCK')
 | 
			
		||||
        assert 'thefuck' in shell.app_alias('fuck')
 | 
			
		||||
        assert 'TF_ALIAS=fuck' in shell.app_alias('fuck')
 | 
			
		||||
        assert 'PYTHONIOENCODING=utf-8' in shell.app_alias('fuck')
 | 
			
		||||
        assert 'PYTHONIOENCODING' in shell.app_alias('fuck')
 | 
			
		||||
 | 
			
		||||
    def test_app_alias_variables_correctly_set(self, shell):
 | 
			
		||||
        alias = shell.app_alias('fuck')
 | 
			
		||||
        assert "alias fuck='TF_CMD=$(TF_ALIAS" in alias
 | 
			
		||||
        assert '$(TF_ALIAS=fuck PYTHONIOENCODING' in alias
 | 
			
		||||
        assert 'PYTHONIOENCODING=utf-8 TF_SHELL_ALIASES' in alias
 | 
			
		||||
        assert 'ALIASES=$(alias) thefuck' in alias
 | 
			
		||||
        assert "fuck () {" in alias
 | 
			
		||||
        assert "TF_ALIAS=fuck" in alias
 | 
			
		||||
        assert 'PYTHONIOENCODING=utf-8' in alias
 | 
			
		||||
        assert 'TF_SHELL_ALIASES=$(alias)' in alias
 | 
			
		||||
 | 
			
		||||
    def test_get_history(self, history_lines, shell):
 | 
			
		||||
        history_lines(['ls', 'rm'])
 | 
			
		||||
        assert list(shell.get_history()) == ['ls', 'rm']
 | 
			
		||||
 | 
			
		||||
    def test_split_command(self, shell):
 | 
			
		||||
        command = 'git log -p'
 | 
			
		||||
        command_parts = ['git', 'log', '-p']
 | 
			
		||||
        assert shell.split_command(command) == command_parts
 | 
			
		||||
 | 
			
		||||
    def test_how_to_configure(self, shell, config_exists):
 | 
			
		||||
        config_exists.return_value = True
 | 
			
		||||
        assert shell.how_to_configure().can_configure_automatically
 | 
			
		||||
 | 
			
		||||
    def test_how_to_configure_when_config_not_found(self, shell,
 | 
			
		||||
                                                    config_exists):
 | 
			
		||||
        config_exists.return_value = False
 | 
			
		||||
        assert not shell.how_to_configure().can_configure_automatically
 | 
			
		||||
 
 | 
			
		||||
@@ -18,17 +18,14 @@ class TestFish(object):
 | 
			
		||||
            b'man\nmath\npopd\npushd\nruby')
 | 
			
		||||
        return mock
 | 
			
		||||
 | 
			
		||||
    @pytest.fixture
 | 
			
		||||
    def os_environ(self, monkeypatch, key, value):
 | 
			
		||||
        monkeypatch.setattr('os.environ', {key: value})
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize('key, value', [
 | 
			
		||||
        ('TF_OVERRIDDEN_ALIASES', 'cut,git,sed'),  # legacy
 | 
			
		||||
        ('THEFUCK_OVERRIDDEN_ALIASES', 'cut,git,sed'),
 | 
			
		||||
        ('THEFUCK_OVERRIDDEN_ALIASES', 'cut, git, sed'),
 | 
			
		||||
        ('THEFUCK_OVERRIDDEN_ALIASES', ' cut,\tgit,sed\n'),
 | 
			
		||||
        ('THEFUCK_OVERRIDDEN_ALIASES', '\ncut,\n\ngit,\tsed\r')])
 | 
			
		||||
    def test_get_overridden_aliases(self, shell, os_environ):
 | 
			
		||||
    def test_get_overridden_aliases(self, shell, os_environ, key, value):
 | 
			
		||||
        os_environ[key] = value
 | 
			
		||||
        assert shell._get_overridden_aliases() == {'cd', 'cut', 'git', 'grep',
 | 
			
		||||
                                                   'ls', 'man', 'open', 'sed'}
 | 
			
		||||
 | 
			
		||||
@@ -55,6 +52,9 @@ class TestFish(object):
 | 
			
		||||
    def test_and_(self, shell):
 | 
			
		||||
        assert shell.and_('foo', 'bar') == 'foo; and bar'
 | 
			
		||||
 | 
			
		||||
    def test_or_(self, shell):
 | 
			
		||||
        assert shell.or_('foo', 'bar') == 'foo; or bar'
 | 
			
		||||
 | 
			
		||||
    def test_get_aliases(self, shell):
 | 
			
		||||
        assert shell.get_aliases() == {'fish_config': 'fish_config',
 | 
			
		||||
                                       'fuck': 'fuck',
 | 
			
		||||
@@ -76,11 +76,11 @@ class TestFish(object):
 | 
			
		||||
 | 
			
		||||
    def test_app_alias_alter_history(self, settings, shell):
 | 
			
		||||
        settings.alter_history = True
 | 
			
		||||
        assert 'history --delete' in shell.app_alias('FUCK')
 | 
			
		||||
        assert 'history --merge' in shell.app_alias('FUCK')
 | 
			
		||||
        assert 'builtin history delete' in shell.app_alias('FUCK')
 | 
			
		||||
        assert 'builtin history merge' in shell.app_alias('FUCK')
 | 
			
		||||
        settings.alter_history = False
 | 
			
		||||
        assert 'history --delete' not in shell.app_alias('FUCK')
 | 
			
		||||
        assert 'history --merge' not in shell.app_alias('FUCK')
 | 
			
		||||
        assert 'builtin history delete' not in shell.app_alias('FUCK')
 | 
			
		||||
        assert 'builtin history merge' not in shell.app_alias('FUCK')
 | 
			
		||||
 | 
			
		||||
    def test_get_history(self, history_lines, shell):
 | 
			
		||||
        history_lines(['- cmd: ls', '  when: 1432613911',
 | 
			
		||||
@@ -95,3 +95,12 @@ class TestFish(object):
 | 
			
		||||
        shell.put_to_history(entry)
 | 
			
		||||
        builtins_open.return_value.__enter__.return_value. \
 | 
			
		||||
            write.assert_called_once_with(entry_utf8)
 | 
			
		||||
 | 
			
		||||
    def test_how_to_configure(self, shell, config_exists):
 | 
			
		||||
        config_exists.return_value = True
 | 
			
		||||
        assert shell.how_to_configure().can_configure_automatically
 | 
			
		||||
 | 
			
		||||
    def test_how_to_configure_when_config_not_found(self, shell,
 | 
			
		||||
                                                    config_exists):
 | 
			
		||||
        config_exists.return_value = False
 | 
			
		||||
        assert not shell.how_to_configure().can_configure_automatically
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,9 @@ class TestGeneric(object):
 | 
			
		||||
    def test_and_(self, shell):
 | 
			
		||||
        assert shell.and_('ls', 'cd') == 'ls && cd'
 | 
			
		||||
 | 
			
		||||
    def test_or_(self, shell):
 | 
			
		||||
        assert shell.or_('ls', 'cd') == 'ls || cd'
 | 
			
		||||
 | 
			
		||||
    def test_get_aliases(self, shell):
 | 
			
		||||
        assert shell.get_aliases() == {}
 | 
			
		||||
 | 
			
		||||
@@ -37,3 +40,6 @@ class TestGeneric(object):
 | 
			
		||||
    def test_split_command(self, shell):
 | 
			
		||||
        assert shell.split_command('ls') == ['ls']
 | 
			
		||||
        assert shell.split_command(u'echo café') == [u'echo', u'café']
 | 
			
		||||
 | 
			
		||||
    def test_how_to_configure(self, shell):
 | 
			
		||||
        assert shell.how_to_configure() is None
 | 
			
		||||
 
 | 
			
		||||
@@ -17,3 +17,6 @@ class TestPowershell(object):
 | 
			
		||||
        assert 'function fuck' in shell.app_alias('fuck')
 | 
			
		||||
        assert 'function FUCK' in shell.app_alias('FUCK')
 | 
			
		||||
        assert 'thefuck' in shell.app_alias('fuck')
 | 
			
		||||
 | 
			
		||||
    def test_how_to_configure(self, shell):
 | 
			
		||||
        assert not shell.how_to_configure().can_configure_automatically
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,9 @@ class TestTcsh(object):
 | 
			
		||||
    def test_and_(self, shell):
 | 
			
		||||
        assert shell.and_('ls', 'cd') == 'ls && cd'
 | 
			
		||||
 | 
			
		||||
    def test_or_(self, shell):
 | 
			
		||||
        assert shell.or_('ls', 'cd') == 'ls || cd'
 | 
			
		||||
 | 
			
		||||
    def test_get_aliases(self, shell):
 | 
			
		||||
        assert shell.get_aliases() == {'fuck': 'eval $(thefuck $(fc -ln -1))',
 | 
			
		||||
                                       'l': 'ls -CF',
 | 
			
		||||
@@ -48,3 +51,12 @@ class TestTcsh(object):
 | 
			
		||||
    def test_get_history(self, history_lines, shell):
 | 
			
		||||
        history_lines(['ls', 'rm'])
 | 
			
		||||
        assert list(shell.get_history()) == ['ls', 'rm']
 | 
			
		||||
 | 
			
		||||
    def test_how_to_configure(self, shell, config_exists):
 | 
			
		||||
        config_exists.return_value = True
 | 
			
		||||
        assert shell.how_to_configure().can_configure_automatically
 | 
			
		||||
 | 
			
		||||
    def test_how_to_configure_when_config_not_found(self, shell,
 | 
			
		||||
                                                    config_exists):
 | 
			
		||||
        config_exists.return_value = False
 | 
			
		||||
        assert not shell.how_to_configure().can_configure_automatically
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,9 @@ class TestZsh(object):
 | 
			
		||||
    def test_and_(self, shell):
 | 
			
		||||
        assert shell.and_('ls', 'cd') == 'ls && cd'
 | 
			
		||||
 | 
			
		||||
    def test_or_(self, shell):
 | 
			
		||||
        assert shell.or_('ls', 'cd') == 'ls || cd'
 | 
			
		||||
 | 
			
		||||
    def test_get_aliases(self, shell):
 | 
			
		||||
        assert shell.get_aliases() == {
 | 
			
		||||
            'fuck': 'eval $(thefuck $(fc -ln -1 | tail -n 1))',
 | 
			
		||||
@@ -40,18 +43,27 @@ class TestZsh(object):
 | 
			
		||||
            'll': 'ls -alF'}
 | 
			
		||||
 | 
			
		||||
    def test_app_alias(self, shell):
 | 
			
		||||
        assert 'alias fuck' in shell.app_alias('fuck')
 | 
			
		||||
        assert 'alias FUCK' in shell.app_alias('FUCK')
 | 
			
		||||
        assert 'fuck () {' in shell.app_alias('fuck')
 | 
			
		||||
        assert 'FUCK () {' in shell.app_alias('FUCK')
 | 
			
		||||
        assert 'thefuck' in shell.app_alias('fuck')
 | 
			
		||||
        assert 'PYTHONIOENCODING' in shell.app_alias('fuck')
 | 
			
		||||
 | 
			
		||||
    def test_app_alias_variables_correctly_set(self, shell):
 | 
			
		||||
        alias = shell.app_alias('fuck')
 | 
			
		||||
        assert "alias fuck='TF_CMD=$(TF_ALIAS" in alias
 | 
			
		||||
        assert '$(TF_ALIAS=fuck PYTHONIOENCODING' in alias
 | 
			
		||||
        assert 'PYTHONIOENCODING=utf-8 TF_SHELL_ALIASES' in alias
 | 
			
		||||
        assert 'ALIASES=$(alias) thefuck' in alias
 | 
			
		||||
        assert "fuck () {" in alias
 | 
			
		||||
        assert "TF_ALIAS=fuck" in alias
 | 
			
		||||
        assert 'PYTHONIOENCODING=utf-8' in alias
 | 
			
		||||
        assert 'TF_SHELL_ALIASES=$(alias)' in alias
 | 
			
		||||
 | 
			
		||||
    def test_get_history(self, history_lines, shell):
 | 
			
		||||
        history_lines([': 1432613911:0;ls', ': 1432613916:0;rm'])
 | 
			
		||||
        assert list(shell.get_history()) == ['ls', 'rm']
 | 
			
		||||
 | 
			
		||||
    def test_how_to_configure(self, shell, config_exists):
 | 
			
		||||
        config_exists.return_value = True
 | 
			
		||||
        assert shell.how_to_configure().can_configure_automatically
 | 
			
		||||
 | 
			
		||||
    def test_how_to_configure_when_config_not_found(self, shell,
 | 
			
		||||
                                                    config_exists):
 | 
			
		||||
        config_exists.return_value = False
 | 
			
		||||
        assert not shell.how_to_configure().can_configure_automatically
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								tests/test_argument_parser.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								tests/test_argument_parser.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
import pytest
 | 
			
		||||
from thefuck.argument_parser import Parser
 | 
			
		||||
from thefuck.const import ARGUMENT_PLACEHOLDER
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _args(**override):
 | 
			
		||||
    args = {'alias': None, 'command': [], 'yes': False,
 | 
			
		||||
            'help': False, 'version': False, 'debug': False,
 | 
			
		||||
            'force_command': None, 'repeat': False}
 | 
			
		||||
    args.update(override)
 | 
			
		||||
    return args
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('argv, result', [
 | 
			
		||||
    (['thefuck'], _args()),
 | 
			
		||||
    (['thefuck', '-a'], _args(alias='fuck')),
 | 
			
		||||
    (['thefuck', '-a', 'fix'], _args(alias='fix')),
 | 
			
		||||
    (['thefuck', 'git', 'branch', ARGUMENT_PLACEHOLDER, '-y'],
 | 
			
		||||
     _args(command=['git', 'branch'], yes=True)),
 | 
			
		||||
    (['thefuck', 'git', 'branch', '-a', ARGUMENT_PLACEHOLDER, '-y'],
 | 
			
		||||
     _args(command=['git', 'branch', '-a'], yes=True)),
 | 
			
		||||
    (['thefuck', ARGUMENT_PLACEHOLDER, '-v'], _args(version=True)),
 | 
			
		||||
    (['thefuck', ARGUMENT_PLACEHOLDER, '--help'], _args(help=True)),
 | 
			
		||||
    (['thefuck', 'git', 'branch', '-a', ARGUMENT_PLACEHOLDER, '-y', '-d'],
 | 
			
		||||
     _args(command=['git', 'branch', '-a'], yes=True, debug=True)),
 | 
			
		||||
    (['thefuck', 'git', 'branch', '-a', ARGUMENT_PLACEHOLDER, '-r', '-d'],
 | 
			
		||||
     _args(command=['git', 'branch', '-a'], repeat=True, debug=True))])
 | 
			
		||||
def test_parse(argv, result):
 | 
			
		||||
    assert vars(Parser().parse(argv)) == result
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
import pytest
 | 
			
		||||
import six
 | 
			
		||||
import os
 | 
			
		||||
from mock import Mock
 | 
			
		||||
from thefuck import const
 | 
			
		||||
 | 
			
		||||
@@ -9,14 +10,6 @@ def load_source(mocker):
 | 
			
		||||
    return mocker.patch('thefuck.conf.load_source')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def environ(monkeypatch):
 | 
			
		||||
    data = {}
 | 
			
		||||
    monkeypatch.setattr('thefuck.conf.os.environ', data)
 | 
			
		||||
    return data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.usefixture('environ')
 | 
			
		||||
def test_settings_defaults(load_source, settings):
 | 
			
		||||
    load_source.return_value = object()
 | 
			
		||||
    settings.init()
 | 
			
		||||
@@ -24,7 +17,6 @@ def test_settings_defaults(load_source, settings):
 | 
			
		||||
        assert getattr(settings, key) == val
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.usefixture('environ')
 | 
			
		||||
class TestSettingsFromFile(object):
 | 
			
		||||
    def test_from_file(self, load_source, settings):
 | 
			
		||||
        load_source.return_value = Mock(rules=['test'],
 | 
			
		||||
@@ -53,15 +45,15 @@ class TestSettingsFromFile(object):
 | 
			
		||||
 | 
			
		||||
@pytest.mark.usefixture('load_source')
 | 
			
		||||
class TestSettingsFromEnv(object):
 | 
			
		||||
    def test_from_env(self, environ, settings):
 | 
			
		||||
        environ.update({'THEFUCK_RULES': 'bash:lisp',
 | 
			
		||||
                        'THEFUCK_EXCLUDE_RULES': 'git:vim',
 | 
			
		||||
                        'THEFUCK_WAIT_COMMAND': '55',
 | 
			
		||||
                        'THEFUCK_REQUIRE_CONFIRMATION': 'true',
 | 
			
		||||
                        'THEFUCK_NO_COLORS': 'false',
 | 
			
		||||
                        'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15',
 | 
			
		||||
                        'THEFUCK_WAIT_SLOW_COMMAND': '999',
 | 
			
		||||
                        'THEFUCK_SLOW_COMMANDS': 'lein:react-native:./gradlew'})
 | 
			
		||||
    def test_from_env(self, os_environ, settings):
 | 
			
		||||
        os_environ.update({'THEFUCK_RULES': 'bash:lisp',
 | 
			
		||||
                           'THEFUCK_EXCLUDE_RULES': 'git:vim',
 | 
			
		||||
                           'THEFUCK_WAIT_COMMAND': '55',
 | 
			
		||||
                           'THEFUCK_REQUIRE_CONFIRMATION': 'true',
 | 
			
		||||
                           'THEFUCK_NO_COLORS': 'false',
 | 
			
		||||
                           'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15',
 | 
			
		||||
                           'THEFUCK_WAIT_SLOW_COMMAND': '999',
 | 
			
		||||
                           'THEFUCK_SLOW_COMMANDS': 'lein:react-native:./gradlew'})
 | 
			
		||||
        settings.init()
 | 
			
		||||
        assert settings.rules == ['bash', 'lisp']
 | 
			
		||||
        assert settings.exclude_rules == ['git', 'vim']
 | 
			
		||||
@@ -72,12 +64,19 @@ class TestSettingsFromEnv(object):
 | 
			
		||||
        assert settings.wait_slow_command == 999
 | 
			
		||||
        assert settings.slow_commands == ['lein', 'react-native', './gradlew']
 | 
			
		||||
 | 
			
		||||
    def test_from_env_with_DEFAULT(self, environ, settings):
 | 
			
		||||
        environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'})
 | 
			
		||||
    def test_from_env_with_DEFAULT(self, os_environ, settings):
 | 
			
		||||
        os_environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'})
 | 
			
		||||
        settings.init()
 | 
			
		||||
        assert settings.rules == const.DEFAULT_RULES + ['bash', 'lisp']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_settings_from_args(settings):
 | 
			
		||||
    settings.init(Mock(yes=True, debug=True, repeat=True))
 | 
			
		||||
    assert not settings.require_confirmation
 | 
			
		||||
    assert settings.debug
 | 
			
		||||
    assert settings.repeat
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestInitializeSettingsFile(object):
 | 
			
		||||
    def test_ignore_if_exists(self, settings):
 | 
			
		||||
        settings_path_mock = Mock(is_file=Mock(return_value=True), open=Mock())
 | 
			
		||||
@@ -101,3 +100,22 @@ class TestInitializeSettingsFile(object):
 | 
			
		||||
        for setting in const.DEFAULT_SETTINGS.items():
 | 
			
		||||
            assert '# {} = {}\n'.format(*setting) in settings_file_contents
 | 
			
		||||
        settings_file.close()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize('legacy_dir_exists, xdg_config_home, result', [
 | 
			
		||||
    (False, '~/.config', '~/.config/thefuck'),
 | 
			
		||||
    (False, '/user/test/config/', '/user/test/config/thefuck'),
 | 
			
		||||
    (True, '~/.config', '~/.thefuck'),
 | 
			
		||||
    (True, '/user/test/config/', '~/.thefuck')])
 | 
			
		||||
def test_get_user_dir_path(mocker, os_environ, settings, legacy_dir_exists,
 | 
			
		||||
                           xdg_config_home, result):
 | 
			
		||||
    mocker.patch('thefuck.conf.Path.is_dir',
 | 
			
		||||
                 return_value=legacy_dir_exists)
 | 
			
		||||
 | 
			
		||||
    if xdg_config_home is not None:
 | 
			
		||||
        os_environ['XDG_CONFIG_HOME'] = xdg_config_home
 | 
			
		||||
    else:
 | 
			
		||||
        os_environ.pop('XDG_CONFIG_HOME', None)
 | 
			
		||||
 | 
			
		||||
    path = settings._get_user_dir_path().as_posix()
 | 
			
		||||
    assert path == os.path.expanduser(result)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,8 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
try:
 | 
			
		||||
    from pathlib import Path
 | 
			
		||||
    pathlib_name = 'pathlib'
 | 
			
		||||
except ImportError:
 | 
			
		||||
    from pathlib2 import Path
 | 
			
		||||
    pathlib_name = 'pathlib2'
 | 
			
		||||
from thefuck import corrector, const
 | 
			
		||||
from thefuck.system import Path
 | 
			
		||||
from tests.utils import Rule, Command, CorrectedCommand
 | 
			
		||||
from thefuck.corrector import get_corrected_commands, organize_commands
 | 
			
		||||
 | 
			
		||||
@@ -16,7 +11,7 @@ class TestGetRules(object):
 | 
			
		||||
    @pytest.fixture
 | 
			
		||||
    def glob(self, mocker):
 | 
			
		||||
        results = {}
 | 
			
		||||
        mocker.patch(pathlib_name + '.Path.glob',
 | 
			
		||||
        mocker.patch('thefuck.system.Path.glob',
 | 
			
		||||
                     new_callable=lambda: lambda *_: results.pop('value', []))
 | 
			
		||||
        return lambda value: results.update({'value': value})
 | 
			
		||||
 | 
			
		||||
@@ -52,8 +47,8 @@ def test_get_corrected_commands(mocker):
 | 
			
		||||
                  get_new_command=lambda x: [x.script + '@', x.script + ';'],
 | 
			
		||||
                  priority=60)]
 | 
			
		||||
    mocker.patch('thefuck.corrector.get_rules', return_value=rules)
 | 
			
		||||
    assert [cmd.script for cmd in get_corrected_commands(command)] \
 | 
			
		||||
           == ['test!', 'test@', 'test;']
 | 
			
		||||
    assert ([cmd.script for cmd in get_corrected_commands(command)]
 | 
			
		||||
            == ['test!', 'test@', 'test;'])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_organize_commands():
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										140
									
								
								tests/test_not_configured.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								tests/test_not_configured.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,140 @@
 | 
			
		||||
import pytest
 | 
			
		||||
import json
 | 
			
		||||
from six import StringIO
 | 
			
		||||
from mock import MagicMock
 | 
			
		||||
from thefuck.shells.generic import ShellConfiguration
 | 
			
		||||
from thefuck.not_configured import main
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def usage_tracker(mocker):
 | 
			
		||||
    return mocker.patch(
 | 
			
		||||
        'thefuck.not_configured._get_not_configured_usage_tracker_path',
 | 
			
		||||
        new_callable=MagicMock)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def usage_tracker_io(usage_tracker):
 | 
			
		||||
    io = StringIO()
 | 
			
		||||
    usage_tracker.return_value \
 | 
			
		||||
                 .open.return_value \
 | 
			
		||||
                 .__enter__.return_value = io
 | 
			
		||||
    return io
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def usage_tracker_exists(usage_tracker):
 | 
			
		||||
    usage_tracker.return_value \
 | 
			
		||||
                 .exists.return_value = True
 | 
			
		||||
    return usage_tracker.return_value.exists
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _assert_tracker_updated(usage_tracker_io, pid):
 | 
			
		||||
    usage_tracker_io.seek(0)
 | 
			
		||||
    info = json.load(usage_tracker_io)
 | 
			
		||||
    assert info['pid'] == pid
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _change_tracker(usage_tracker_io, pid):
 | 
			
		||||
    usage_tracker_io.truncate(0)
 | 
			
		||||
    info = {'pid': pid, 'time': 0}
 | 
			
		||||
    json.dump(info, usage_tracker_io)
 | 
			
		||||
    usage_tracker_io.seek(0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def shell_pid(mocker):
 | 
			
		||||
    return mocker.patch('thefuck.not_configured._get_shell_pid',
 | 
			
		||||
                        new_callable=MagicMock)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def shell(mocker):
 | 
			
		||||
    shell = mocker.patch('thefuck.not_configured.shell',
 | 
			
		||||
                         new_callable=MagicMock)
 | 
			
		||||
    shell.get_history.return_value = []
 | 
			
		||||
    shell.how_to_configure.return_value = ShellConfiguration(
 | 
			
		||||
        content='eval $(thefuck --alias)',
 | 
			
		||||
        path='/tmp/.bashrc',
 | 
			
		||||
        reload='bash',
 | 
			
		||||
        can_configure_automatically=True)
 | 
			
		||||
    return shell
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def shell_config(mocker):
 | 
			
		||||
    path_mock = mocker.patch('thefuck.not_configured.Path',
 | 
			
		||||
                             new_callable=MagicMock)
 | 
			
		||||
    return path_mock.return_value \
 | 
			
		||||
        .expanduser.return_value \
 | 
			
		||||
        .open.return_value \
 | 
			
		||||
        .__enter__.return_value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(autouse=True)
 | 
			
		||||
def logs(mocker):
 | 
			
		||||
    return mocker.patch('thefuck.not_configured.logs',
 | 
			
		||||
                        new_callable=MagicMock)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_for_generic_shell(shell, logs):
 | 
			
		||||
    shell.how_to_configure.return_value = None
 | 
			
		||||
    main()
 | 
			
		||||
    logs.how_to_configure_alias.assert_called_once()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_on_first_run(usage_tracker_io, usage_tracker_exists, shell_pid, logs):
 | 
			
		||||
    shell_pid.return_value = 12
 | 
			
		||||
    main()
 | 
			
		||||
    usage_tracker_exists.return_value = False
 | 
			
		||||
    _assert_tracker_updated(usage_tracker_io, 12)
 | 
			
		||||
    logs.how_to_configure_alias.assert_called_once()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_on_run_after_other_commands(usage_tracker_io, shell_pid, shell, logs):
 | 
			
		||||
    shell_pid.return_value = 12
 | 
			
		||||
    shell.get_history.return_value = ['fuck', 'ls']
 | 
			
		||||
    _change_tracker(usage_tracker_io, 12)
 | 
			
		||||
    main()
 | 
			
		||||
    logs.how_to_configure_alias.assert_called_once()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_on_first_run_from_current_shell(usage_tracker_io, shell_pid,
 | 
			
		||||
                                         shell, logs):
 | 
			
		||||
    shell.get_history.return_value = ['fuck']
 | 
			
		||||
    shell_pid.return_value = 12
 | 
			
		||||
    main()
 | 
			
		||||
    _assert_tracker_updated(usage_tracker_io, 12)
 | 
			
		||||
    logs.how_to_configure_alias.assert_called_once()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_when_cant_configure_automatically(shell_pid, shell, logs):
 | 
			
		||||
    shell_pid.return_value = 12
 | 
			
		||||
    shell.how_to_configure.return_value = ShellConfiguration(
 | 
			
		||||
        content='eval $(thefuck --alias)',
 | 
			
		||||
        path='/tmp/.bashrc',
 | 
			
		||||
        reload='bash',
 | 
			
		||||
        can_configure_automatically=False)
 | 
			
		||||
    main()
 | 
			
		||||
    logs.how_to_configure_alias.assert_called_once()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_when_already_configured(usage_tracker_io, shell_pid,
 | 
			
		||||
                                 shell, shell_config, logs):
 | 
			
		||||
    shell.get_history.return_value = ['fuck']
 | 
			
		||||
    shell_pid.return_value = 12
 | 
			
		||||
    _change_tracker(usage_tracker_io, 12)
 | 
			
		||||
    shell_config.read.return_value = 'eval $(thefuck --alias)'
 | 
			
		||||
    main()
 | 
			
		||||
    logs.already_configured.assert_called_once()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_when_successfully_configured(usage_tracker_io, shell_pid,
 | 
			
		||||
                                      shell, shell_config, logs):
 | 
			
		||||
    shell.get_history.return_value = ['fuck']
 | 
			
		||||
    shell_pid.return_value = 12
 | 
			
		||||
    _change_tracker(usage_tracker_io, 12)
 | 
			
		||||
    shell_config.read.return_value = ''
 | 
			
		||||
    main()
 | 
			
		||||
    shell_config.write.assert_any_call('eval $(thefuck --alias)')
 | 
			
		||||
    logs.configured_successfully.assert_called_once()
 | 
			
		||||
@@ -3,23 +3,20 @@
 | 
			
		||||
import os
 | 
			
		||||
from subprocess import PIPE
 | 
			
		||||
from mock import Mock
 | 
			
		||||
try:
 | 
			
		||||
    from pathlib import Path
 | 
			
		||||
except ImportError:
 | 
			
		||||
    from pathlib2 import Path
 | 
			
		||||
import pytest
 | 
			
		||||
from tests.utils import CorrectedCommand, Rule, Command
 | 
			
		||||
from thefuck import const
 | 
			
		||||
from thefuck.exceptions import EmptyCommand
 | 
			
		||||
from thefuck.system import Path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestCorrectedCommand(object):
 | 
			
		||||
 | 
			
		||||
    def test_equality(self):
 | 
			
		||||
        assert CorrectedCommand('ls', None, 100) == \
 | 
			
		||||
               CorrectedCommand('ls', None, 200)
 | 
			
		||||
        assert CorrectedCommand('ls', None, 100) != \
 | 
			
		||||
               CorrectedCommand('ls', lambda *_: _, 100)
 | 
			
		||||
        assert (CorrectedCommand('ls', None, 100) ==
 | 
			
		||||
                CorrectedCommand('ls', None, 200))
 | 
			
		||||
        assert (CorrectedCommand('ls', None, 100) !=
 | 
			
		||||
                CorrectedCommand('ls', lambda *_: _, 100))
 | 
			
		||||
 | 
			
		||||
    def test_hashable(self):
 | 
			
		||||
        assert {CorrectedCommand('ls', None, 100),
 | 
			
		||||
@@ -31,6 +28,20 @@ class TestCorrectedCommand(object):
 | 
			
		||||
        assert u'{}'.format(CorrectedCommand(u'echo café', None, 100)) == \
 | 
			
		||||
               u'CorrectedCommand(script=echo café, side_effect=None, priority=100)'
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize('script, printed, override_settings', [
 | 
			
		||||
        ('git branch', 'git branch', {'repeat': False, 'debug': False}),
 | 
			
		||||
        ('git brunch',
 | 
			
		||||
         "git brunch || fuck --repeat --force-command 'git brunch'",
 | 
			
		||||
         {'repeat': True, 'debug': False}),
 | 
			
		||||
        ('git brunch',
 | 
			
		||||
         "git brunch || fuck --repeat --debug --force-command 'git brunch'",
 | 
			
		||||
         {'repeat': True, 'debug': True})])
 | 
			
		||||
    def test_run(self, capsys, settings, script, printed, override_settings):
 | 
			
		||||
        settings.update(override_settings)
 | 
			
		||||
        CorrectedCommand(script, None, 1000).run(Command())
 | 
			
		||||
        out, _ = capsys.readouterr()
 | 
			
		||||
        assert out[:-1] == printed
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestRule(object):
 | 
			
		||||
    def test_from_path(self, mocker):
 | 
			
		||||
@@ -44,8 +55,8 @@ class TestRule(object):
 | 
			
		||||
                              priority=900,
 | 
			
		||||
                              requires_output=True))
 | 
			
		||||
        rule_path = os.path.join(os.sep, 'rules', 'bash.py')
 | 
			
		||||
        assert Rule.from_path(Path(rule_path)) \
 | 
			
		||||
               == Rule('bash', match, get_new_command, priority=900)
 | 
			
		||||
        assert (Rule.from_path(Path(rule_path))
 | 
			
		||||
                == Rule('bash', match, get_new_command, priority=900))
 | 
			
		||||
        load_source.assert_called_once_with('bash', rule_path)
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize('rules, exclude_rules, rule, is_enabled', [
 | 
			
		||||
@@ -82,15 +93,15 @@ class TestRule(object):
 | 
			
		||||
    def test_get_corrected_commands_with_rule_returns_list(self):
 | 
			
		||||
        rule = Rule(get_new_command=lambda x: [x.script + '!', x.script + '@'],
 | 
			
		||||
                    priority=100)
 | 
			
		||||
        assert list(rule.get_corrected_commands(Command(script='test'))) \
 | 
			
		||||
               == [CorrectedCommand(script='test!', priority=100),
 | 
			
		||||
                   CorrectedCommand(script='test@', priority=200)]
 | 
			
		||||
        assert (list(rule.get_corrected_commands(Command(script='test')))
 | 
			
		||||
                == [CorrectedCommand(script='test!', priority=100),
 | 
			
		||||
                    CorrectedCommand(script='test@', priority=200)])
 | 
			
		||||
 | 
			
		||||
    def test_get_corrected_commands_with_rule_returns_command(self):
 | 
			
		||||
        rule = Rule(get_new_command=lambda x: x.script + '!',
 | 
			
		||||
                    priority=100)
 | 
			
		||||
        assert list(rule.get_corrected_commands(Command(script='test'))) \
 | 
			
		||||
               == [CorrectedCommand(script='test!', priority=100)]
 | 
			
		||||
        assert (list(rule.get_corrected_commands(Command(script='test')))
 | 
			
		||||
                == [CorrectedCommand(script='test!', priority=100)])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestCommand(object):
 | 
			
		||||
@@ -104,11 +115,10 @@ class TestCommand(object):
 | 
			
		||||
 | 
			
		||||
    @pytest.fixture(autouse=True)
 | 
			
		||||
    def prepare(self, monkeypatch):
 | 
			
		||||
        monkeypatch.setattr('thefuck.types.os.environ', {})
 | 
			
		||||
        monkeypatch.setattr('thefuck.types.Command._wait_output',
 | 
			
		||||
                            staticmethod(lambda *_: True))
 | 
			
		||||
 | 
			
		||||
    def test_from_script_calls(self, Popen, settings):
 | 
			
		||||
    def test_from_script_calls(self, Popen, settings, os_environ):
 | 
			
		||||
        settings.env = {}
 | 
			
		||||
        assert Command.from_raw_script(
 | 
			
		||||
            ['apt-get', 'search', 'vim']) == Command(
 | 
			
		||||
@@ -118,7 +128,7 @@ class TestCommand(object):
 | 
			
		||||
                                      stdin=PIPE,
 | 
			
		||||
                                      stdout=PIPE,
 | 
			
		||||
                                      stderr=PIPE,
 | 
			
		||||
                                      env={})
 | 
			
		||||
                                      env=os_environ)
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize('script, result', [
 | 
			
		||||
        ([''], None),
 | 
			
		||||
 
 | 
			
		||||
@@ -30,11 +30,11 @@ def test_read_actions(patch_get_key):
 | 
			
		||||
        const.KEY_DOWN, 'j',
 | 
			
		||||
        # Ctrl+C:
 | 
			
		||||
        const.KEY_CTRL_C, 'q'])
 | 
			
		||||
    assert list(islice(ui.read_actions(), 8)) \
 | 
			
		||||
           == [const.ACTION_SELECT, const.ACTION_SELECT,
 | 
			
		||||
               const.ACTION_PREVIOUS, const.ACTION_PREVIOUS,
 | 
			
		||||
               const.ACTION_NEXT, const.ACTION_NEXT,
 | 
			
		||||
               const.ACTION_ABORT, const.ACTION_ABORT]
 | 
			
		||||
    assert (list(islice(ui.read_actions(), 8))
 | 
			
		||||
            == [const.ACTION_SELECT, const.ACTION_SELECT,
 | 
			
		||||
                const.ACTION_PREVIOUS, const.ACTION_PREVIOUS,
 | 
			
		||||
                const.ACTION_NEXT, const.ACTION_NEXT,
 | 
			
		||||
                const.ACTION_ABORT, const.ACTION_ABORT])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_command_selector():
 | 
			
		||||
@@ -74,8 +74,8 @@ class TestSelectCommand(object):
 | 
			
		||||
    def test_without_confirmation_with_side_effects(
 | 
			
		||||
            self, capsys, commands_with_side_effect, settings):
 | 
			
		||||
        settings.require_confirmation = False
 | 
			
		||||
        assert ui.select_command(iter(commands_with_side_effect)) \
 | 
			
		||||
               == commands_with_side_effect[0]
 | 
			
		||||
        assert (ui.select_command(iter(commands_with_side_effect))
 | 
			
		||||
                == commands_with_side_effect[0])
 | 
			
		||||
        assert capsys.readouterr() == ('', 'ls (+side effect)\n')
 | 
			
		||||
 | 
			
		||||
    def test_with_confirmation(self, capsys, patch_get_key, commands):
 | 
			
		||||
@@ -91,8 +91,8 @@ class TestSelectCommand(object):
 | 
			
		||||
    def test_with_confirmation_with_side_effct(self, capsys, patch_get_key,
 | 
			
		||||
                                               commands_with_side_effect):
 | 
			
		||||
        patch_get_key(['\n'])
 | 
			
		||||
        assert ui.select_command(iter(commands_with_side_effect)) \
 | 
			
		||||
               == commands_with_side_effect[0]
 | 
			
		||||
        assert (ui.select_command(iter(commands_with_side_effect))
 | 
			
		||||
                == commands_with_side_effect[0])
 | 
			
		||||
        assert capsys.readouterr() == ('', u'\x1b[1K\rls (+side effect) [enter/↑/↓/ctrl+c]\n')
 | 
			
		||||
 | 
			
		||||
    def test_with_confirmation_select_second(self, capsys, patch_get_key, commands):
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ from mock import Mock
 | 
			
		||||
import six
 | 
			
		||||
from thefuck.utils import default_settings, \
 | 
			
		||||
    memoize, get_closest, get_all_executables, replace_argument, \
 | 
			
		||||
    get_all_matched_commands, is_app, for_app, cache, compatibility_call, \
 | 
			
		||||
    get_all_matched_commands, is_app, for_app, cache, \
 | 
			
		||||
    get_valid_history_without_current
 | 
			
		||||
from tests.utils import Command
 | 
			
		||||
 | 
			
		||||
@@ -18,8 +18,7 @@ from tests.utils import Command
 | 
			
		||||
def test_default_settings(settings, override, old, new):
 | 
			
		||||
    settings.clear()
 | 
			
		||||
    settings.update(old)
 | 
			
		||||
    fn = lambda _: _
 | 
			
		||||
    default_settings(override)(fn)(None)
 | 
			
		||||
    default_settings(override)(lambda _: _)(None)
 | 
			
		||||
    assert settings == new
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -188,56 +187,6 @@ class TestCache(object):
 | 
			
		||||
        assert shelve == {key: {'etag': '0', 'value': 'test'}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestCompatibilityCall(object):
 | 
			
		||||
    def test_match(self):
 | 
			
		||||
        def match(command):
 | 
			
		||||
            assert command == Command()
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
        assert compatibility_call(match, Command())
 | 
			
		||||
 | 
			
		||||
    def test_old_match(self, settings):
 | 
			
		||||
        def match(command, _settings):
 | 
			
		||||
            assert command == Command()
 | 
			
		||||
            assert settings == _settings
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
        with pytest.warns(UserWarning):
 | 
			
		||||
            assert compatibility_call(match, Command())
 | 
			
		||||
 | 
			
		||||
    def test_get_new_command(self):
 | 
			
		||||
        def get_new_command(command):
 | 
			
		||||
            assert command == Command()
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
        assert compatibility_call(get_new_command, Command())
 | 
			
		||||
 | 
			
		||||
    def test_old_get_new_command(self, settings):
 | 
			
		||||
        def get_new_command(command, _settings):
 | 
			
		||||
            assert command == Command()
 | 
			
		||||
            assert settings == _settings
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
        with pytest.warns(UserWarning):
 | 
			
		||||
            assert compatibility_call(get_new_command, Command())
 | 
			
		||||
 | 
			
		||||
    def test_side_effect(self):
 | 
			
		||||
        def side_effect(command, new_command):
 | 
			
		||||
            assert command == Command() == new_command
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
        assert compatibility_call(side_effect, Command(), Command())
 | 
			
		||||
 | 
			
		||||
    def test_old_side_effect(self, settings):
 | 
			
		||||
        def side_effect(command, new_command, _settings):
 | 
			
		||||
            assert command == Command() == new_command
 | 
			
		||||
            assert settings == _settings
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
        with pytest.warns(UserWarning):
 | 
			
		||||
            assert compatibility_call(side_effect, Command(), Command())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestGetValidHistoryWithoutCurrent(object):
 | 
			
		||||
    @pytest.yield_fixture(autouse=True)
 | 
			
		||||
    def fail_on_warning(self):
 | 
			
		||||
@@ -257,8 +206,7 @@ class TestGetValidHistoryWithoutCurrent(object):
 | 
			
		||||
                            return_value='fuck')
 | 
			
		||||
 | 
			
		||||
    @pytest.fixture(autouse=True)
 | 
			
		||||
    def bins(self, mocker, monkeypatch):
 | 
			
		||||
        monkeypatch.setattr('thefuck.conf.os.environ', {'PATH': 'path'})
 | 
			
		||||
    def bins(self, mocker):
 | 
			
		||||
        callables = list()
 | 
			
		||||
        for name in ['diff', 'ls', 'café']:
 | 
			
		||||
            bin_mock = mocker.Mock(name=name)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										84
									
								
								thefuck/argument_parser.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								thefuck/argument_parser.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
import sys
 | 
			
		||||
from argparse import ArgumentParser, SUPPRESS
 | 
			
		||||
from .const import ARGUMENT_PLACEHOLDER
 | 
			
		||||
from .utils import get_alias
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Parser(object):
 | 
			
		||||
    """Argument parser that can handle arguments with our special
 | 
			
		||||
    placeholder.
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self._parser = ArgumentParser(prog='thefuck', add_help=False)
 | 
			
		||||
        self._add_arguments()
 | 
			
		||||
 | 
			
		||||
    def _add_arguments(self):
 | 
			
		||||
        """Adds arguments to parser."""
 | 
			
		||||
        self._parser.add_argument(
 | 
			
		||||
            '-v', '--version',
 | 
			
		||||
            action='store_true',
 | 
			
		||||
            help="show program's version number and exit")
 | 
			
		||||
        self._parser.add_argument(
 | 
			
		||||
            '-a', '--alias',
 | 
			
		||||
            nargs='?',
 | 
			
		||||
            const=get_alias(),
 | 
			
		||||
            help='[custom-alias-name] prints alias for current shell')
 | 
			
		||||
        self._parser.add_argument(
 | 
			
		||||
            '-h', '--help',
 | 
			
		||||
            action='store_true',
 | 
			
		||||
            help='show this help message and exit')
 | 
			
		||||
        self._add_conflicting_arguments()
 | 
			
		||||
        self._parser.add_argument(
 | 
			
		||||
            '-d', '--debug',
 | 
			
		||||
            action='store_true',
 | 
			
		||||
            help='enable debug output')
 | 
			
		||||
        self._parser.add_argument(
 | 
			
		||||
            '--force-command',
 | 
			
		||||
            action='store',
 | 
			
		||||
            help=SUPPRESS)
 | 
			
		||||
        self._parser.add_argument(
 | 
			
		||||
            'command',
 | 
			
		||||
            nargs='*',
 | 
			
		||||
            help='command that should be fixed')
 | 
			
		||||
 | 
			
		||||
    def _add_conflicting_arguments(self):
 | 
			
		||||
        """It's too dangerous to use `-y` and `-r` together."""
 | 
			
		||||
        group = self._parser.add_mutually_exclusive_group()
 | 
			
		||||
        group.add_argument(
 | 
			
		||||
            '-y', '--yes',
 | 
			
		||||
            action='store_true',
 | 
			
		||||
            help='execute fixed command without confirmation')
 | 
			
		||||
        group.add_argument(
 | 
			
		||||
            '-r', '--repeat',
 | 
			
		||||
            action='store_true',
 | 
			
		||||
            help='repeat on failure')
 | 
			
		||||
 | 
			
		||||
    def _prepare_arguments(self, argv):
 | 
			
		||||
        """Prepares arguments by:
 | 
			
		||||
 | 
			
		||||
        - removing placeholder and moving arguments after it to beginning,
 | 
			
		||||
          we need this to distinguish arguments from `command` with ours;
 | 
			
		||||
 | 
			
		||||
        - adding `--` before `command`, so our parse would ignore arguments
 | 
			
		||||
          of `command`.
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        if ARGUMENT_PLACEHOLDER in argv:
 | 
			
		||||
            index = argv.index(ARGUMENT_PLACEHOLDER)
 | 
			
		||||
            return argv[index + 1:] + ['--'] + argv[:index]
 | 
			
		||||
        elif argv and not argv[0].startswith('-') and argv[0] != '--':
 | 
			
		||||
            return ['--'] + argv
 | 
			
		||||
        else:
 | 
			
		||||
            return argv
 | 
			
		||||
 | 
			
		||||
    def parse(self, argv):
 | 
			
		||||
        arguments = self._prepare_arguments(argv[1:])
 | 
			
		||||
        return self._parser.parse_args(arguments)
 | 
			
		||||
 | 
			
		||||
    def print_usage(self):
 | 
			
		||||
        self._parser.print_usage(sys.stderr)
 | 
			
		||||
 | 
			
		||||
    def print_help(self):
 | 
			
		||||
        self._parser.print_help(sys.stderr)
 | 
			
		||||
@@ -1,12 +1,10 @@
 | 
			
		||||
from imp import load_source
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
try:
 | 
			
		||||
    from pathlib import Path
 | 
			
		||||
except ImportError:
 | 
			
		||||
    from pathlib2 import Path
 | 
			
		||||
from warnings import warn
 | 
			
		||||
from six import text_type
 | 
			
		||||
from . import const
 | 
			
		||||
from .system import Path
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Settings(dict):
 | 
			
		||||
@@ -16,7 +14,7 @@ class Settings(dict):
 | 
			
		||||
    def __setattr__(self, key, value):
 | 
			
		||||
        self[key] = value
 | 
			
		||||
 | 
			
		||||
    def init(self):
 | 
			
		||||
    def init(self, args=None):
 | 
			
		||||
        """Fills `settings` with values from `settings.py` and env."""
 | 
			
		||||
        from .logs import exception
 | 
			
		||||
 | 
			
		||||
@@ -33,6 +31,8 @@ class Settings(dict):
 | 
			
		||||
        except Exception:
 | 
			
		||||
            exception("Can't load settings from env", sys.exc_info())
 | 
			
		||||
 | 
			
		||||
        self.update(self._settings_from_args(args))
 | 
			
		||||
 | 
			
		||||
    def _init_settings_file(self):
 | 
			
		||||
        settings_path = self.user_dir.joinpath('settings.py')
 | 
			
		||||
        if not settings_path.is_file():
 | 
			
		||||
@@ -42,15 +42,18 @@ class Settings(dict):
 | 
			
		||||
                    settings_file.write(u'# {} = {}\n'.format(*setting))
 | 
			
		||||
 | 
			
		||||
    def _get_user_dir_path(self):
 | 
			
		||||
        # for backward compatibility, use `~/.thefuck` if it exists
 | 
			
		||||
        legacy_user_dir = Path(os.path.expanduser('~/.thefuck'))
 | 
			
		||||
        """Returns Path object representing the user config resource"""
 | 
			
		||||
        xdg_config_home = os.environ.get('XDG_CONFIG_HOME', '~/.config')
 | 
			
		||||
        user_dir = Path(xdg_config_home, 'thefuck').expanduser()
 | 
			
		||||
        legacy_user_dir = Path('~', '.thefuck').expanduser()
 | 
			
		||||
 | 
			
		||||
        # For backward compatibility use legacy '~/.thefuck' if it exists:
 | 
			
		||||
        if legacy_user_dir.is_dir():
 | 
			
		||||
            warn(u'Config path {} is deprecated. Please move to {}'.format(
 | 
			
		||||
                legacy_user_dir, user_dir))
 | 
			
		||||
            return legacy_user_dir
 | 
			
		||||
        else:
 | 
			
		||||
            default_xdg_config_dir = os.path.expanduser("~/.config")
 | 
			
		||||
            xdg_config_dir = os.getenv("XDG_CONFIG_HOME", default_xdg_config_dir)
 | 
			
		||||
            return Path(os.path.join(xdg_config_dir, 'thefuck'))
 | 
			
		||||
            return user_dir
 | 
			
		||||
 | 
			
		||||
    def _setup_user_dir(self):
 | 
			
		||||
        """Returns user config dir, create it when it doesn't exist."""
 | 
			
		||||
@@ -108,5 +111,19 @@ class Settings(dict):
 | 
			
		||||
                for env, attr in const.ENV_TO_ATTR.items()
 | 
			
		||||
                if env in os.environ}
 | 
			
		||||
 | 
			
		||||
    def _settings_from_args(self, args):
 | 
			
		||||
        """Loads settings from args."""
 | 
			
		||||
        if not args:
 | 
			
		||||
            return {}
 | 
			
		||||
 | 
			
		||||
        from_args = {}
 | 
			
		||||
        if args.yes:
 | 
			
		||||
            from_args['require_confirmation'] = not args.yes
 | 
			
		||||
        if args.debug:
 | 
			
		||||
            from_args['debug'] = args.debug
 | 
			
		||||
        if args.repeat:
 | 
			
		||||
            from_args['repeat'] = args.repeat
 | 
			
		||||
        return from_args
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
settings = Settings(const.DEFAULT_SETTINGS)
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,8 @@ DEFAULT_SETTINGS = {'rules': DEFAULT_RULES,
 | 
			
		||||
                    'alter_history': True,
 | 
			
		||||
                    'wait_slow_command': 15,
 | 
			
		||||
                    'slow_commands': ['lein', 'react-native', 'gradle',
 | 
			
		||||
                                      './gradlew'],
 | 
			
		||||
                                      './gradlew', 'vagrant'],
 | 
			
		||||
                    'repeat': False,
 | 
			
		||||
                    'env': {'LC_ALL': 'C', 'LANG': 'C', 'GIT_TRACE': '1'}}
 | 
			
		||||
 | 
			
		||||
ENV_TO_ATTR = {'THEFUCK_RULES': 'rules',
 | 
			
		||||
@@ -46,7 +47,8 @@ ENV_TO_ATTR = {'THEFUCK_RULES': 'rules',
 | 
			
		||||
               'THEFUCK_HISTORY_LIMIT': 'history_limit',
 | 
			
		||||
               'THEFUCK_ALTER_HISTORY': 'alter_history',
 | 
			
		||||
               'THEFUCK_WAIT_SLOW_COMMAND': 'wait_slow_command',
 | 
			
		||||
               'THEFUCK_SLOW_COMMANDS': 'slow_commands'}
 | 
			
		||||
               'THEFUCK_SLOW_COMMANDS': 'slow_commands',
 | 
			
		||||
               'THEFUCK_REPEAT': 'repeat'}
 | 
			
		||||
 | 
			
		||||
SETTINGS_HEADER = u"""# The Fuck settings file
 | 
			
		||||
#
 | 
			
		||||
@@ -59,3 +61,7 @@ SETTINGS_HEADER = u"""# The Fuck settings file
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
ARGUMENT_PLACEHOLDER = 'THEFUCK_ARGUMENT_PLACEHOLDER'
 | 
			
		||||
 | 
			
		||||
CONFIGURATION_TIMEOUT = 60
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,6 @@
 | 
			
		||||
try:
 | 
			
		||||
    from pathlib import Path
 | 
			
		||||
except ImportError:
 | 
			
		||||
    from pathlib2 import Path
 | 
			
		||||
from .conf import settings
 | 
			
		||||
from .types import Rule
 | 
			
		||||
from .system import Path
 | 
			
		||||
from . import logs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -80,16 +80,50 @@ def debug_time(msg):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def how_to_configure_alias(configuration_details):
 | 
			
		||||
    print("Seems like {bold}fuck{reset} alias isn't configured!".format(
 | 
			
		||||
    print(u"Seems like {bold}fuck{reset} alias isn't configured!".format(
 | 
			
		||||
        bold=color(colorama.Style.BRIGHT),
 | 
			
		||||
        reset=color(colorama.Style.RESET_ALL)))
 | 
			
		||||
 | 
			
		||||
    if configuration_details:
 | 
			
		||||
        content, path = configuration_details
 | 
			
		||||
        print(
 | 
			
		||||
            "Please put {bold}{content}{reset} in your "
 | 
			
		||||
            "{bold}{path}{reset}.".format(
 | 
			
		||||
            u"Please put {bold}{content}{reset} in your "
 | 
			
		||||
            u"{bold}{path}{reset} and apply "
 | 
			
		||||
            u"changes with {bold}{reload}{reset} or restart your shell.".format(
 | 
			
		||||
                bold=color(colorama.Style.BRIGHT),
 | 
			
		||||
                reset=color(colorama.Style.RESET_ALL),
 | 
			
		||||
                path=path,
 | 
			
		||||
                content=content))
 | 
			
		||||
    print('More details - https://github.com/nvbn/thefuck#manual-installation')
 | 
			
		||||
                **configuration_details._asdict()))
 | 
			
		||||
 | 
			
		||||
        if configuration_details.can_configure_automatically:
 | 
			
		||||
            print(
 | 
			
		||||
                u"Or run {bold}fuck{reset} second time for configuring"
 | 
			
		||||
                u" it automatically.".format(
 | 
			
		||||
                    bold=color(colorama.Style.BRIGHT),
 | 
			
		||||
                    reset=color(colorama.Style.RESET_ALL)))
 | 
			
		||||
 | 
			
		||||
    print(u'More details - https://github.com/nvbn/thefuck#manual-installation')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def already_configured(configuration_details):
 | 
			
		||||
    print(
 | 
			
		||||
        u"Seems like {bold}fuck{reset} alias already configured!\n"
 | 
			
		||||
        u"For applying changes run {bold}{reload}{reset}"
 | 
			
		||||
        u" or restart your shell.".format(
 | 
			
		||||
            bold=color(colorama.Style.BRIGHT),
 | 
			
		||||
            reset=color(colorama.Style.RESET_ALL),
 | 
			
		||||
            reload=configuration_details.reload))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def configured_successfully(configuration_details):
 | 
			
		||||
    print(
 | 
			
		||||
        u"{bold}fuck{reset} alias configured successfully!\n"
 | 
			
		||||
        u"For applying changes run {bold}{reload}{reset}"
 | 
			
		||||
        u" or restart your shell.".format(
 | 
			
		||||
            bold=color(colorama.Style.BRIGHT),
 | 
			
		||||
            reset=color(colorama.Style.RESET_ALL),
 | 
			
		||||
            reload=configuration_details.reload))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def version(thefuck_version, python_version):
 | 
			
		||||
    sys.stderr.write(
 | 
			
		||||
        u'The Fuck {} using Python {}\n'.format(thefuck_version,
 | 
			
		||||
                                                python_version))
 | 
			
		||||
 
 | 
			
		||||
@@ -3,27 +3,28 @@ from .system import init_output
 | 
			
		||||
 | 
			
		||||
init_output()
 | 
			
		||||
 | 
			
		||||
from argparse import ArgumentParser
 | 
			
		||||
from warnings import warn
 | 
			
		||||
from pprint import pformat
 | 
			
		||||
import sys
 | 
			
		||||
from . import logs, types
 | 
			
		||||
from .shells import shell
 | 
			
		||||
from .conf import settings
 | 
			
		||||
from .corrector import get_corrected_commands
 | 
			
		||||
from .exceptions import EmptyCommand
 | 
			
		||||
from .utils import get_installation_info, get_alias
 | 
			
		||||
from .ui import select_command
 | 
			
		||||
from pprint import pformat  # noqa: E402
 | 
			
		||||
import sys  # noqa: E402
 | 
			
		||||
from . import logs, types  # noqa: E402
 | 
			
		||||
from .shells import shell  # noqa: E402
 | 
			
		||||
from .conf import settings  # noqa: E402
 | 
			
		||||
from .corrector import get_corrected_commands  # noqa: E402
 | 
			
		||||
from .exceptions import EmptyCommand  # noqa: E402
 | 
			
		||||
from .ui import select_command  # noqa: E402
 | 
			
		||||
from .argument_parser import Parser  # noqa: E402
 | 
			
		||||
from .utils import get_installation_info  # noqa: E402
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def fix_command():
 | 
			
		||||
def fix_command(known_args):
 | 
			
		||||
    """Fixes previous command. Used when `thefuck` called without arguments."""
 | 
			
		||||
    settings.init()
 | 
			
		||||
    settings.init(known_args)
 | 
			
		||||
    with logs.debug_time('Total'):
 | 
			
		||||
        logs.debug(u'Run with settings: {}'.format(pformat(settings)))
 | 
			
		||||
        raw_command = ([known_args.force_command] if known_args.force_command
 | 
			
		||||
                       else known_args.command)
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            command = types.Command.from_raw_script(sys.argv[1:])
 | 
			
		||||
            command = types.Command.from_raw_script(raw_command)
 | 
			
		||||
        except EmptyCommand:
 | 
			
		||||
            logs.debug('Empty command, nothing to do')
 | 
			
		||||
            return
 | 
			
		||||
@@ -37,48 +38,18 @@ def fix_command():
 | 
			
		||||
            sys.exit(1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def print_alias(entry_point=True):
 | 
			
		||||
    """Prints alias for current shell."""
 | 
			
		||||
    if entry_point:
 | 
			
		||||
        warn('`thefuck-alias` is deprecated, use `thefuck --alias` instead.')
 | 
			
		||||
        position = 1
 | 
			
		||||
    else:
 | 
			
		||||
        position = 2
 | 
			
		||||
 | 
			
		||||
    alias = get_alias()
 | 
			
		||||
    if len(sys.argv) > position:
 | 
			
		||||
        alias = sys.argv[position]
 | 
			
		||||
    print(shell.app_alias(alias))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def how_to_configure_alias():
 | 
			
		||||
    """Shows useful information about how-to configure alias.
 | 
			
		||||
 | 
			
		||||
    It'll be only visible when user type fuck and when alias isn't configured.
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    settings.init()
 | 
			
		||||
    logs.how_to_configure_alias(shell.how_to_configure())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    parser = ArgumentParser(prog='thefuck')
 | 
			
		||||
    version = get_installation_info().version
 | 
			
		||||
    parser.add_argument(
 | 
			
		||||
            '-v', '--version',
 | 
			
		||||
            action='version',
 | 
			
		||||
            version='The Fuck {} using Python {}'.format(
 | 
			
		||||
                    version, sys.version.split()[0]))
 | 
			
		||||
    parser.add_argument('-a', '--alias',
 | 
			
		||||
                        action='store_true',
 | 
			
		||||
                        help='[custom-alias-name] prints alias for current shell')
 | 
			
		||||
    parser.add_argument('command',
 | 
			
		||||
                        nargs='*',
 | 
			
		||||
                        help='command that should be fixed')
 | 
			
		||||
    known_args = parser.parse_args(sys.argv[1:2])
 | 
			
		||||
    if known_args.alias:
 | 
			
		||||
        print_alias(False)
 | 
			
		||||
    parser = Parser()
 | 
			
		||||
    known_args = parser.parse(sys.argv)
 | 
			
		||||
 | 
			
		||||
    if known_args.help:
 | 
			
		||||
        parser.print_help()
 | 
			
		||||
    elif known_args.version:
 | 
			
		||||
        logs.version(get_installation_info().version,
 | 
			
		||||
                     sys.version.split()[0])
 | 
			
		||||
    elif known_args.command:
 | 
			
		||||
        fix_command()
 | 
			
		||||
        fix_command(known_args)
 | 
			
		||||
    elif known_args.alias:
 | 
			
		||||
        print(shell.app_alias(known_args.alias))
 | 
			
		||||
    else:
 | 
			
		||||
        parser.print_usage()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										111
									
								
								thefuck/not_configured.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								thefuck/not_configured.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
			
		||||
# Initialize output before importing any module, that can use colorama.
 | 
			
		||||
from .system import init_output
 | 
			
		||||
 | 
			
		||||
init_output()
 | 
			
		||||
 | 
			
		||||
import os  # noqa: E402
 | 
			
		||||
import json  # noqa: E402
 | 
			
		||||
import time  # noqa: E402
 | 
			
		||||
import six  # noqa: E402
 | 
			
		||||
from psutil import Process  # noqa: E402
 | 
			
		||||
from . import logs, const  # noqa: E402
 | 
			
		||||
from .shells import shell  # noqa: E402
 | 
			
		||||
from .conf import settings  # noqa: E402
 | 
			
		||||
from .system import Path  # noqa: E402
 | 
			
		||||
from .utils import get_cache_dir  # noqa: E402
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _get_shell_pid():
 | 
			
		||||
    """Returns parent process pid."""
 | 
			
		||||
    proc = Process(os.getpid())
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        return proc.parent().pid
 | 
			
		||||
    except TypeError:
 | 
			
		||||
        return proc.parent.pid
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _get_not_configured_usage_tracker_path():
 | 
			
		||||
    """Returns path of special file where we store latest shell pid."""
 | 
			
		||||
    return Path(get_cache_dir()).joinpath('thefuck.last_not_configured_run')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _record_first_run():
 | 
			
		||||
    """Records shell pid to tracker file."""
 | 
			
		||||
    info = {'pid': _get_shell_pid(),
 | 
			
		||||
            'time': time.time()}
 | 
			
		||||
 | 
			
		||||
    mode = 'wb' if six.PY2 else 'w'
 | 
			
		||||
    with _get_not_configured_usage_tracker_path().open(mode) as tracker:
 | 
			
		||||
        json.dump(info, tracker)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _get_previous_command():
 | 
			
		||||
    history = shell.get_history()
 | 
			
		||||
 | 
			
		||||
    if history:
 | 
			
		||||
        return history[-1]
 | 
			
		||||
    else:
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _is_second_run():
 | 
			
		||||
    """Returns `True` when we know that `fuck` called second time."""
 | 
			
		||||
    tracker_path = _get_not_configured_usage_tracker_path()
 | 
			
		||||
    if not tracker_path.exists():
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    current_pid = _get_shell_pid()
 | 
			
		||||
    with tracker_path.open('r') as tracker:
 | 
			
		||||
        try:
 | 
			
		||||
            info = json.load(tracker)
 | 
			
		||||
        except ValueError:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    if not (isinstance(info, dict) and info.get('pid') == current_pid):
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    return (_get_previous_command() == 'fuck' or
 | 
			
		||||
            time.time() - info.get('time', 0) < const.CONFIGURATION_TIMEOUT)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _is_already_configured(configuration_details):
 | 
			
		||||
    """Returns `True` when alias already in shell config."""
 | 
			
		||||
    path = Path(configuration_details.path).expanduser()
 | 
			
		||||
    with path.open('r') as shell_config:
 | 
			
		||||
        return configuration_details.content in shell_config.read()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _configure(configuration_details):
 | 
			
		||||
    """Adds alias to shell config."""
 | 
			
		||||
    path = Path(configuration_details.path).expanduser()
 | 
			
		||||
    with path.open('a') as shell_config:
 | 
			
		||||
        shell_config.write(u'\n')
 | 
			
		||||
        shell_config.write(configuration_details.content)
 | 
			
		||||
        shell_config.write(u'\n')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    """Shows useful information about how-to configure alias on a first run
 | 
			
		||||
    and configure automatically on a second.
 | 
			
		||||
 | 
			
		||||
    It'll be only visible when user type fuck and when alias isn't configured.
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    settings.init()
 | 
			
		||||
    configuration_details = shell.how_to_configure()
 | 
			
		||||
    if (
 | 
			
		||||
        configuration_details and
 | 
			
		||||
        configuration_details.can_configure_automatically
 | 
			
		||||
    ):
 | 
			
		||||
        if _is_already_configured(configuration_details):
 | 
			
		||||
            logs.already_configured(configuration_details)
 | 
			
		||||
            return
 | 
			
		||||
        elif _is_second_run():
 | 
			
		||||
            _configure(configuration_details)
 | 
			
		||||
            logs.configured_successfully(configuration_details)
 | 
			
		||||
            return
 | 
			
		||||
        else:
 | 
			
		||||
            _record_first_run()
 | 
			
		||||
 | 
			
		||||
    logs.how_to_configure_alias(configuration_details)
 | 
			
		||||
							
								
								
									
										10
									
								
								thefuck/rules/ag_literal.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								thefuck/rules/ag_literal.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
from thefuck.utils import for_app
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@for_app('ag')
 | 
			
		||||
def match(command):
 | 
			
		||||
    return command.stderr.endswith('run ag with -Q\n')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_new_command(command):
 | 
			
		||||
    return command.script.replace('ag', 'ag -Q', 1)
 | 
			
		||||
@@ -29,7 +29,7 @@ def get_package(executable):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def match(command):
 | 
			
		||||
    if 'not found' in command.stderr:
 | 
			
		||||
    if 'not found' in command.stderr or 'not installed' in command.stderr:
 | 
			
		||||
        executable = _get_executable(command)
 | 
			
		||||
        return not which(executable) and get_package(executable)
 | 
			
		||||
    else:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								thefuck/rules/aws_cli.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								thefuck/rules/aws_cli.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
from thefuck.utils import for_app, replace_argument
 | 
			
		||||
 | 
			
		||||
INVALID_CHOICE = "(?<=Invalid choice: ')(.*)(?=', maybe you meant:)"
 | 
			
		||||
OPTIONS = "^\s*\*\s(.*)"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@for_app('aws')
 | 
			
		||||
def match(command):
 | 
			
		||||
    return "usage:" in command.stderr and "maybe you meant:" in command.stderr
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_new_command(command):
 | 
			
		||||
    mistake = re.search(INVALID_CHOICE, command.stderr).group(0)
 | 
			
		||||
    options = re.findall(OPTIONS, command.stderr, flags=re.MULTILINE)
 | 
			
		||||
    return [replace_argument(command.script, mistake, o) for o in options]
 | 
			
		||||
							
								
								
									
										15
									
								
								thefuck/rules/brew_link.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								thefuck/rules/brew_link.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
from thefuck.utils import for_app
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@for_app('brew', at_least=2)
 | 
			
		||||
def match(command):
 | 
			
		||||
    return (command.script_parts[1] in ['ln', 'link']
 | 
			
		||||
            and "brew link --overwrite --dry-run" in command.stderr)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_new_command(command):
 | 
			
		||||
    command_parts = command.script_parts[:]
 | 
			
		||||
    command_parts[1] = 'link'
 | 
			
		||||
    command_parts.insert(2, '--overwrite')
 | 
			
		||||
    command_parts.insert(3, '--dry-run')
 | 
			
		||||
    return ' '.join(command_parts)
 | 
			
		||||
							
								
								
									
										14
									
								
								thefuck/rules/brew_uninstall.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								thefuck/rules/brew_uninstall.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
from thefuck.utils import for_app
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@for_app('brew', at_least=2)
 | 
			
		||||
def match(command):
 | 
			
		||||
    return (command.script_parts[1] in ['uninstall', 'rm', 'remove']
 | 
			
		||||
            and "brew uninstall --force" in command.stdout)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_new_command(command):
 | 
			
		||||
    command_parts = command.script_parts[:]
 | 
			
		||||
    command_parts[1] = 'uninstall'
 | 
			
		||||
    command_parts.insert(2, '--force')
 | 
			
		||||
    return ' '.join(command_parts)
 | 
			
		||||
@@ -54,8 +54,8 @@ def _brew_commands():
 | 
			
		||||
    brew_path_prefix = get_brew_path_prefix()
 | 
			
		||||
    if brew_path_prefix:
 | 
			
		||||
        try:
 | 
			
		||||
            return _get_brew_commands(brew_path_prefix) \
 | 
			
		||||
                   + _get_brew_tap_specific_commands(brew_path_prefix)
 | 
			
		||||
            return (_get_brew_commands(brew_path_prefix)
 | 
			
		||||
                    + _get_brew_tap_specific_commands(brew_path_prefix))
 | 
			
		||||
        except OSError:
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ def match(command):
 | 
			
		||||
 | 
			
		||||
def get_new_command(command):
 | 
			
		||||
    return u'{} -d {}'.format(
 | 
			
		||||
            command.script, shell.quote(_zip_file(command)[:-4]))
 | 
			
		||||
        command.script, shell.quote(_zip_file(command)[:-4]))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def side_effect(old_cmd, command):
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ def match(command):
 | 
			
		||||
def get_new_command(command):
 | 
			
		||||
    return ' '.join(command.script_parts[1:])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# it should be rare enough to actually have to type twice the same word, so
 | 
			
		||||
# this rule can have a higher priority to come before things like "cd cd foo"
 | 
			
		||||
priority = 900
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,8 @@ def _make_pattern(pattern):
 | 
			
		||||
                     .replace('{line}', '(?P<line>[0-9]+)') \
 | 
			
		||||
                     .replace('{col}', '(?P<col>[0-9]+)')
 | 
			
		||||
    return re.compile(pattern, re.MULTILINE)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
patterns = [_make_pattern(p).search for p in patterns]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user