mirror of
https://github.com/nvbn/thefuck.git
synced 2025-11-01 15:42:06 +00:00
Compare commits
107 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a9942061d | ||
|
|
a65f90813b | ||
|
|
a778ea6203 | ||
|
|
03a828d586 | ||
|
|
4a0d71c1c4 | ||
|
|
a6f63c0568 | ||
|
|
d1b9492085 | ||
|
|
993a661c60 | ||
|
|
bc9121cb13 | ||
|
|
7db140c456 | ||
|
|
e313ff73a9 | ||
|
|
8c62706db4 | ||
|
|
6baa7f650e | ||
|
|
4ae32cf4ee | ||
|
|
385746850e | ||
|
|
4f87141f0c | ||
|
|
dbedcc7aa6 | ||
|
|
e0b5d47fa5 | ||
|
|
ca44ee0640 | ||
|
|
892e8a8e65 | ||
|
|
a947259eef | ||
|
|
785cb83ff3 | ||
|
|
aec8fe3233 | ||
|
|
c21dbd2be3 | ||
|
|
6173913291 | ||
|
|
6f0d1e287d | ||
|
|
756044e087 | ||
|
|
ddd8788353 | ||
|
|
76c0e7bc70 | ||
|
|
4865bdd81f | ||
|
|
fa169c686c | ||
|
|
9cae0bffff | ||
|
|
b519d317f7 | ||
|
|
5b420204c9 | ||
|
|
07005b591a | ||
|
|
cb99e42e02 | ||
|
|
51f77964c6 | ||
|
|
30b1c44f91 | ||
|
|
af28f0334a | ||
|
|
5ee5439c1e | ||
|
|
cf006dac2c | ||
|
|
5b535077bf | ||
|
|
cf3acbfa2e | ||
|
|
4d714994a3 | ||
|
|
02f717a0e8 | ||
|
|
8f4f2f03a7 | ||
|
|
feb36ede5c | ||
|
|
16a440cb9d | ||
|
|
10b20574d1 | ||
|
|
91fceb401a | ||
|
|
4b79e23ba7 | ||
|
|
f915a6ed0c | ||
|
|
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 |
@@ -2,6 +2,9 @@ language: python
|
|||||||
sudo: false
|
sudo: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
python: "3.6"
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
python: "3.5"
|
python: "3.5"
|
||||||
@@ -29,7 +32,7 @@ addons:
|
|||||||
- python3-commandnotfound
|
- python3-commandnotfound
|
||||||
before_install:
|
before_install:
|
||||||
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew update ; fi
|
- 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 virtualenv venv -p $FORMULA; fi
|
||||||
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then source venv/bin/activate; fi
|
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then source venv/bin/activate; fi
|
||||||
- pip install -U pip
|
- pip install -U pip
|
||||||
@@ -41,7 +44,7 @@ install:
|
|||||||
script:
|
script:
|
||||||
- export COVERAGE_PYTHON_VERSION=python-${TRAVIS_PYTHON_VERSION:0:1}
|
- export COVERAGE_PYTHON_VERSION=python-${TRAVIS_PYTHON_VERSION:0:1}
|
||||||
- export RUN_TESTS="coverage run --source=thefuck,tests -m py.test -v --capture=sys tests"
|
- export RUN_TESTS="coverage run --source=thefuck,tests -m py.test -v --capture=sys tests"
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == 3.5 && $TRAVIS_OS_NAME != "osx" ]]; then $RUN_TESTS --enable-functional; fi
|
- if [[ $TRAVIS_PYTHON_VERSION == 3.6 && $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; fi
|
||||||
after_success:
|
after_success:
|
||||||
- coveralls
|
- coveralls
|
||||||
|
|||||||
21
README.md
21
README.md
@@ -103,7 +103,6 @@ brew install thefuck
|
|||||||
```
|
```
|
||||||
|
|
||||||
On Ubuntu you can install `The Fuck` with:
|
On Ubuntu you can install `The Fuck` with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install python3-dev python3-pip
|
sudo apt install python3-dev python3-pip
|
||||||
@@ -135,7 +134,7 @@ To make them available immediately, run `source ~/.bashrc` (or your shell config
|
|||||||
## Update
|
## Update
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo pip install thefuck --upgrade
|
sudo -H pip install thefuck --upgrade
|
||||||
```
|
```
|
||||||
|
|
||||||
**Aliases changed in 1.34.**
|
**Aliases changed in 1.34.**
|
||||||
@@ -145,6 +144,8 @@ sudo pip install thefuck --upgrade
|
|||||||
The Fuck tries to match a rule for the previous command, creates a new command
|
The Fuck tries to match a rule for the previous command, creates a new command
|
||||||
using the matched rule and runs it. Rules enabled by default are as follows:
|
using the matched rule and runs it. Rules enabled by default are as follows:
|
||||||
|
|
||||||
|
* `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` – runs `cargo build` instead of `cargo`;
|
||||||
* `cargo_no_command` – fixes wrongs commands like `cargo buid`;
|
* `cargo_no_command` – fixes wrongs commands like `cargo buid`;
|
||||||
* `cd_correction` – spellchecks and correct failed cd commands;
|
* `cd_correction` – spellchecks and correct failed cd commands;
|
||||||
@@ -164,22 +165,29 @@ using the matched rule and runs it. Rules enabled by default are as follows:
|
|||||||
* `fix_alt_space` – replaces Alt+Space with Space character;
|
* `fix_alt_space` – replaces Alt+Space with Space character;
|
||||||
* `fix_file` – opens a file with an error in your `$EDITOR`;
|
* `fix_file` – opens a file with an error in your `$EDITOR`;
|
||||||
* `git_add` – fixes *"pathspec 'foo' did not match any file(s) known to git."*;
|
* `git_add` – fixes *"pathspec 'foo' did not match any file(s) known to git."*;
|
||||||
|
* `git_bisect_usage` – fixes `git bisect strt`, `git bisect goood`, `git bisect rset`, etc. when bisecting;
|
||||||
* `git_branch_delete` – changes `git branch -d` to `git branch -D`;
|
* `git_branch_delete` – changes `git branch -d` to `git branch -D`;
|
||||||
* `git_branch_exists` – offers `git branch -d foo`, `git branch -D foo` or `git checkout foo` when creating a branch that already exists;
|
* `git_branch_exists` – offers `git branch -d foo`, `git branch -D foo` or `git checkout foo` when creating a branch that already exists;
|
||||||
* `git_branch_list` – catches `git branch list` in place of `git branch` and removes created branch;
|
* `git_branch_list` – catches `git branch list` in place of `git branch` and removes created branch;
|
||||||
* `git_checkout` – fixes branch name or creates new branch;
|
* `git_checkout` – fixes branch name or creates new branch;
|
||||||
|
* `git_diff_no_index` – adds `--no-index` to previous `git diff` on untracked files;
|
||||||
* `git_diff_staged` – adds `--staged` to previous `git diff` with unexpected output;
|
* `git_diff_staged` – adds `--staged` to previous `git diff` with unexpected output;
|
||||||
* `git_fix_stash` – fixes `git stash` commands (misspelled subcommand and missing `save`);
|
* `git_fix_stash` – fixes `git stash` commands (misspelled subcommand and missing `save`);
|
||||||
|
* `git_flag_after_filename` – fixes `fatal: bad flag '...' after filename`
|
||||||
* `git_help_aliased` – fixes `git help <alias>` commands replacing <alias> with the aliased command;
|
* `git_help_aliased` – fixes `git help <alias>` commands replacing <alias> with the aliased command;
|
||||||
* `git_not_command` – fixes wrong git commands like `git brnch`;
|
* `git_not_command` – fixes wrong git commands like `git brnch`;
|
||||||
* `git_pull` – sets upstream before executing previous `git pull`;
|
* `git_pull` – sets upstream before executing previous `git pull`;
|
||||||
* `git_pull_clone` – clones instead of pulling when the repo does not exist;
|
* `git_pull_clone` – clones instead of pulling when the repo does not exist;
|
||||||
|
* `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` – adds `--set-upstream origin $branch` to previous failed `git push`;
|
||||||
* `git_push_pull` – runs `git pull` when `push` was rejected;
|
* `git_push_pull` – runs `git pull` when `push` was rejected;
|
||||||
* `git_rebase_no_changes` – runs `git rebase --skip` instead of `git rebase --continue` when there are no changes;
|
* `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_recursive` – adds `-r` when you try to `rm` a directory;
|
||||||
|
* `git_rebase_merge_dir` – offers `git rebase (--continue | --abort | --skip)` or removing the `.git/rebase-merge` dir when a rebase is in progress;
|
||||||
* `git_remote_seturl_add` – runs `git remote add` when `git remote set_url` on nonexistant remote;
|
* `git_remote_seturl_add` – runs `git remote add` when `git remote set_url` on nonexistant remote;
|
||||||
* `git_stash` – stashes you local modifications before rebasing or switching branch;
|
* `git_stash` – stashes you local modifications before rebasing or switching branch;
|
||||||
|
* `git_stash_pop` – adds your local modifications before popping stash, then resets;
|
||||||
* `git_two_dashes` – adds a missing dash to commands like `git commit -amend` or `git rebase -continue`;
|
* `git_two_dashes` – adds a missing dash to commands like `git commit -amend` or `git rebase -continue`;
|
||||||
* `go_run` – appends `.go` extension when compiling/running Go programs;
|
* `go_run` – appends `.go` extension when compiling/running Go programs;
|
||||||
* `gradle_no_task` – fixes not found or ambiguous `gradle` task;
|
* `gradle_no_task` – fixes not found or ambiguous `gradle` task;
|
||||||
@@ -191,11 +199,13 @@ using the matched rule and runs it. Rules enabled by default are as follows:
|
|||||||
* `has_exists_script` – prepends `./` when script/binary exists;
|
* `has_exists_script` – prepends `./` when script/binary exists;
|
||||||
* `heroku_not_command` – fixes wrong `heroku` commands like `heroku log`;
|
* `heroku_not_command` – fixes wrong `heroku` commands like `heroku log`;
|
||||||
* `history` – tries to replace command with most similar command from history;
|
* `history` – tries to replace command with most similar command from history;
|
||||||
|
* `ifconfig_device_not_found` – fixes wrong device names like `wlan0` to `wlp2s0`;
|
||||||
* `java` – removes `.java` extension when running Java programs;
|
* `java` – removes `.java` extension when running Java programs;
|
||||||
* `javac` – appends missing `.java` when compiling Java files;
|
* `javac` – appends missing `.java` when compiling Java files;
|
||||||
* `lein_not_task` – fixes wrong `lein` tasks like `lein rpl`;
|
* `lein_not_task` – fixes wrong `lein` tasks like `lein rpl`;
|
||||||
* `ln_no_hard_link` – catches hard link creation on directories, suggest symbolic link;
|
* `ln_no_hard_link` – catches hard link creation on directories, suggest symbolic link;
|
||||||
* `ln_s_order` – fixes `ln -s` arguments order;
|
* `ln_s_order` – fixes `ln -s` arguments order;
|
||||||
|
* `ls_all` – adds `-A` to `ls` when output is empty;
|
||||||
* `ls_lah` – adds `-lah` to `ls`;
|
* `ls_lah` – adds `-lah` to `ls`;
|
||||||
* `man` – changes manual section;
|
* `man` – changes manual section;
|
||||||
* `man_no_space` – fixes man commands without spaces, for example `mandiff`;
|
* `man_no_space` – fixes man commands without spaces, for example `mandiff`;
|
||||||
@@ -215,6 +225,7 @@ using the matched rule and runs it. Rules enabled by default are as follows:
|
|||||||
* `python_execute` – appends missing `.py` when executing Python files;
|
* `python_execute` – appends missing `.py` when executing Python files;
|
||||||
* `quotation_marks` – fixes uneven usage of `'` and `"` when containing args';
|
* `quotation_marks` – fixes uneven usage of `'` and `"` when containing args';
|
||||||
* `react_native_command_unrecognized` – fixes unrecognized `react-native` commands;
|
* `react_native_command_unrecognized` – fixes unrecognized `react-native` commands;
|
||||||
|
* `remove_trailing_cedilla` – remove trailling cedillas `ç`, a common typo for european keyboard layouts;
|
||||||
* `rm_dir` – adds `-rf` when you trying to remove directory;
|
* `rm_dir` – adds `-rf` when you trying to remove directory;
|
||||||
* `sed_unterminated_s` – adds missing '/' to `sed`'s `s` commands;
|
* `sed_unterminated_s` – adds missing '/' to `sed`'s `s` commands;
|
||||||
* `sl_ls` – changes `sl` to `ls`;
|
* `sl_ls` – changes `sl` to `ls`;
|
||||||
@@ -238,6 +249,8 @@ Enabled by default only on specific platforms:
|
|||||||
* `apt_get_search` – changes trying to search using `apt-get` with searching using `apt-cache`;
|
* `apt_get_search` – changes trying to search using `apt-get` with searching using `apt-cache`;
|
||||||
* `apt_invalid_operation` – fixes invalid `apt` and `apt-get` calls, like `apt-get isntall vim`;
|
* `apt_invalid_operation` – fixes invalid `apt` and `apt-get` calls, like `apt-get isntall vim`;
|
||||||
* `brew_install` – fixes formula name for `brew install`;
|
* `brew_install` – fixes formula name for `brew install`;
|
||||||
|
* `brew_link` – adds `--overwrite --dry-run` if linking fails;
|
||||||
|
* `brew_uninstall` – adds `--force` to `brew uninstall` if multiple versions were installed;
|
||||||
* `brew_unknown_command` – fixes wrong brew commands, for example `brew docto/brew doctor`;
|
* `brew_unknown_command` – fixes wrong brew commands, for example `brew docto/brew doctor`;
|
||||||
* `brew_update_formula` – turns `brew update <formula>` into `brew upgrade <formula>`;
|
* `brew_update_formula` – turns `brew update <formula>` into `brew upgrade <formula>`;
|
||||||
* `brew_upgrade` – appends `--all` to `brew upgrade` as per Homebrew's new behaviour;
|
* `brew_upgrade` – appends `--all` to `brew upgrade` as per Homebrew's new behaviour;
|
||||||
@@ -266,7 +279,9 @@ side_effect(old_command: Command, fixed_command: str) -> None
|
|||||||
```
|
```
|
||||||
and optional `enabled_by_default`, `requires_output` and `priority` variables.
|
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`.
|
*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)).
|
`settings` is a special object filled with `~/.config/thefuck/settings.py` and values from env ([see more below](#settings)).
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ environment:
|
|||||||
- PYTHON: "C:/Python33"
|
- PYTHON: "C:/Python33"
|
||||||
- PYTHON: "C:/Python34"
|
- PYTHON: "C:/Python34"
|
||||||
- PYTHON: "C:/Python35"
|
- PYTHON: "C:/Python35"
|
||||||
|
- PYTHON: "C:/Python36"
|
||||||
|
|
||||||
init:
|
init:
|
||||||
- "ECHO %PYTHON%"
|
- "ECHO %PYTHON%"
|
||||||
|
|||||||
3
setup.py
3
setup.py
@@ -29,7 +29,7 @@ elif (3, 0) < version < (3, 3):
|
|||||||
' ({}.{} detected).'.format(*version))
|
' ({}.{} detected).'.format(*version))
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
VERSION = '3.11'
|
VERSION = '3.14'
|
||||||
|
|
||||||
install_requires = ['psutil', 'colorama', 'six', 'decorator']
|
install_requires = ['psutil', 'colorama', 'six', 'decorator']
|
||||||
extras_require = {':python_version<"3.4"': ['pathlib2'],
|
extras_require = {':python_version<"3.4"': ['pathlib2'],
|
||||||
@@ -51,5 +51,4 @@ setup(name='thefuck',
|
|||||||
extras_require=extras_require,
|
extras_require=extras_require,
|
||||||
entry_points={'console_scripts': [
|
entry_points={'console_scripts': [
|
||||||
'thefuck = thefuck.main:main',
|
'thefuck = thefuck.main:main',
|
||||||
'thefuck-alias = thefuck.main:print_alias',
|
|
||||||
'fuck = thefuck.main:how_to_configure_alias']})
|
'fuck = thefuck.main:how_to_configure_alias']})
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
try:
|
|
||||||
from pathlib import Path
|
|
||||||
except ImportError:
|
|
||||||
from pathlib2 import Path
|
|
||||||
import pytest
|
import pytest
|
||||||
from thefuck import shells
|
from thefuck import shells
|
||||||
from thefuck import conf, const
|
from thefuck import conf, const
|
||||||
|
from thefuck.system import Path
|
||||||
|
|
||||||
shells.shell = shells.Generic()
|
shells.shell = shells.Generic()
|
||||||
|
|
||||||
|
|||||||
@@ -3,18 +3,11 @@ from tests.functional.plots import with_confirmation, without_confirmation, \
|
|||||||
refuse_with_confirmation, history_changed, history_not_changed, \
|
refuse_with_confirmation, history_changed, history_not_changed, \
|
||||||
select_command_with_arrows, how_to_configure
|
select_command_with_arrows, how_to_configure
|
||||||
|
|
||||||
containers = ((u'thefuck/ubuntu-python3-bash',
|
containers = ((u'thefuck/python3-bash',
|
||||||
u'''FROM ubuntu:latest
|
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''',
|
|
||||||
u'bash'),
|
u'bash'),
|
||||||
(u'thefuck/ubuntu-python2-bash',
|
(u'thefuck/python2-bash',
|
||||||
u'''FROM ubuntu:latest
|
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''',
|
|
||||||
u'bash'))
|
u'bash'))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,19 +2,20 @@ import pytest
|
|||||||
from tests.functional.plots import with_confirmation, without_confirmation, \
|
from tests.functional.plots import with_confirmation, without_confirmation, \
|
||||||
refuse_with_confirmation, select_command_with_arrows
|
refuse_with_confirmation, select_command_with_arrows
|
||||||
|
|
||||||
containers = (('thefuck/ubuntu-python3-fish',
|
containers = (('thefuck/python3-fish',
|
||||||
u'''FROM ubuntu:latest
|
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 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''',
|
RUN apt-get install -yy fish''',
|
||||||
u'fish'),
|
u'fish'),
|
||||||
('thefuck/ubuntu-python2-fish',
|
('thefuck/python2-fish',
|
||||||
u'''FROM ubuntu:latest
|
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 update
|
||||||
RUN apt-get install -yy python python-pip python-dev git
|
|
||||||
RUN pip2 install -U pip setuptools
|
|
||||||
RUN apt-get install -yy fish''',
|
RUN apt-get install -yy fish''',
|
||||||
u'fish'))
|
u'fish'))
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,7 @@ import pytest
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
dockerfile = u'''
|
dockerfile = u'''
|
||||||
FROM ubuntu:latest
|
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 adduser --disabled-password --gecos '' test
|
RUN adduser --disabled-password --gecos '' test
|
||||||
ENV SEED "{seed}"
|
ENV SEED "{seed}"
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
@@ -42,7 +38,7 @@ def plot(proc, TIMEOUT):
|
|||||||
@pytest.mark.functional
|
@pytest.mark.functional
|
||||||
@pytest.mark.benchmark(min_rounds=10)
|
@pytest.mark.benchmark(min_rounds=10)
|
||||||
def test_performance(spawnu, TIMEOUT, benchmark):
|
def test_performance(spawnu, TIMEOUT, benchmark):
|
||||||
proc = spawnu(u'thefuck/ubuntu-python3-bash-performance',
|
proc = spawnu(u'thefuck/python3-bash-performance',
|
||||||
dockerfile, u'bash')
|
dockerfile, u'bash')
|
||||||
proc.sendline(u'pip install /src')
|
proc.sendline(u'pip install /src')
|
||||||
proc.sendline(u'su test')
|
proc.sendline(u'su test')
|
||||||
|
|||||||
@@ -2,19 +2,14 @@ import pytest
|
|||||||
from tests.functional.plots import with_confirmation, without_confirmation, \
|
from tests.functional.plots import with_confirmation, without_confirmation, \
|
||||||
refuse_with_confirmation, select_command_with_arrows
|
refuse_with_confirmation, select_command_with_arrows
|
||||||
|
|
||||||
containers = (('thefuck/ubuntu-python3-tcsh',
|
containers = (('thefuck/python3-tcsh',
|
||||||
u'''FROM ubuntu:latest
|
u'''FROM python:3
|
||||||
RUN apt-get update
|
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''',
|
RUN apt-get install -yy tcsh''',
|
||||||
u'tcsh'),
|
u'tcsh'),
|
||||||
('thefuck/ubuntu-python2-tcsh',
|
('thefuck/python2-tcsh',
|
||||||
u'''FROM ubuntu:latest
|
u'''FROM python:2
|
||||||
RUN apt-get update
|
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''',
|
RUN apt-get install -yy tcsh''',
|
||||||
u'tcsh'))
|
u'tcsh'))
|
||||||
|
|
||||||
|
|||||||
@@ -3,19 +3,14 @@ from tests.functional.plots import with_confirmation, without_confirmation, \
|
|||||||
refuse_with_confirmation, history_changed, history_not_changed, \
|
refuse_with_confirmation, history_changed, history_not_changed, \
|
||||||
select_command_with_arrows, how_to_configure
|
select_command_with_arrows, how_to_configure
|
||||||
|
|
||||||
containers = (('thefuck/ubuntu-python3-zsh',
|
containers = (('thefuck/python3-zsh',
|
||||||
u'''FROM ubuntu:latest
|
u'''FROM python:3
|
||||||
RUN apt-get update
|
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''',
|
RUN apt-get install -yy zsh''',
|
||||||
u'zsh'),
|
u'zsh'),
|
||||||
('thefuck/ubuntu-python2-zsh',
|
('thefuck/python2-zsh',
|
||||||
u'''FROM ubuntu:latest
|
u'''FROM python:2
|
||||||
RUN apt-get update
|
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''',
|
RUN apt-get install -yy zsh''',
|
||||||
u'zsh'))
|
u'zsh'))
|
||||||
|
|
||||||
|
|||||||
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
|
||||||
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
|
||||||
@@ -3,6 +3,12 @@ from thefuck.rules.git_add import match, get_new_command
|
|||||||
from tests.utils import 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
|
@pytest.fixture
|
||||||
def stderr(target):
|
def stderr(target):
|
||||||
return ("error: pathspec '{}' did not match any "
|
return ("error: pathspec '{}' did not match any "
|
||||||
@@ -16,10 +22,13 @@ def test_match(stderr, script, target):
|
|||||||
assert match(Command(script=script, stderr=stderr))
|
assert match(Command(script=script, stderr=stderr))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('script', [
|
@pytest.mark.parametrize('script, target, exists', [
|
||||||
'git submodule update known', 'git commit known'])
|
('git submodule update known', '', True),
|
||||||
def test_not_match(script):
|
('git commit known', '', True),
|
||||||
assert not match(Command(script=script, stderr=''))
|
('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', [
|
@pytest.mark.parametrize('script, target, new_command', [
|
||||||
|
|||||||
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
|
||||||
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):
|
def test_match(stderr):
|
||||||
|
assert match(Command('git push', stderr=stderr))
|
||||||
assert match(Command('git push master', stderr=stderr))
|
assert match(Command('git push master', stderr=stderr))
|
||||||
assert not match(Command('git push master'))
|
assert not match(Command('git push master'))
|
||||||
assert not match(Command('ls', stderr=stderr))
|
assert not match(Command('ls', stderr=stderr))
|
||||||
@@ -22,3 +23,11 @@ def test_match(stderr):
|
|||||||
def test_get_new_command(stderr):
|
def test_get_new_command(stderr):
|
||||||
assert get_new_command(Command('git push', stderr=stderr))\
|
assert get_new_command(Command('git push', stderr=stderr))\
|
||||||
== "git push --set-upstream origin master"
|
== "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"
|
||||||
|
|||||||
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
|
||||||
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
|
||||||
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 . && git stash pop && git reset ."
|
||||||
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
|
||||||
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', [
|
@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 2 read'), 'man 3 read'),
|
||||||
(Command('man 3 read'), 'man 2 read'),
|
(Command('man 3 read'), 'man 2 read'),
|
||||||
(Command('man -s2 read'), 'man -s3 read'),
|
(Command('man -s2 read'), 'man -s3 read'),
|
||||||
|
|||||||
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
|
||||||
@@ -56,3 +56,8 @@ class TestBash(object):
|
|||||||
def test_get_history(self, history_lines, shell):
|
def test_get_history(self, history_lines, shell):
|
||||||
history_lines(['ls', 'rm'])
|
history_lines(['ls', 'rm'])
|
||||||
assert list(shell.get_history()) == ['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
|
||||||
|
|||||||
@@ -76,11 +76,11 @@ class TestFish(object):
|
|||||||
|
|
||||||
def test_app_alias_alter_history(self, settings, shell):
|
def test_app_alias_alter_history(self, settings, shell):
|
||||||
settings.alter_history = True
|
settings.alter_history = True
|
||||||
assert 'history --delete' in shell.app_alias('FUCK')
|
assert 'builtin history delete' in shell.app_alias('FUCK')
|
||||||
assert 'history --merge' in shell.app_alias('FUCK')
|
assert 'builtin history merge' in shell.app_alias('FUCK')
|
||||||
settings.alter_history = False
|
settings.alter_history = False
|
||||||
assert 'history --delete' not in shell.app_alias('FUCK')
|
assert 'builtin history delete' not in shell.app_alias('FUCK')
|
||||||
assert 'history --merge' not in shell.app_alias('FUCK')
|
assert 'builtin history merge' not in shell.app_alias('FUCK')
|
||||||
|
|
||||||
def test_get_history(self, history_lines, shell):
|
def test_get_history(self, history_lines, shell):
|
||||||
history_lines(['- cmd: ls', ' when: 1432613911',
|
history_lines(['- cmd: ls', ' when: 1432613911',
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import six
|
import six
|
||||||
|
import os
|
||||||
from mock import Mock
|
from mock import Mock
|
||||||
from thefuck import const
|
from thefuck import const
|
||||||
|
|
||||||
@@ -101,3 +102,22 @@ class TestInitializeSettingsFile(object):
|
|||||||
for setting in const.DEFAULT_SETTINGS.items():
|
for setting in const.DEFAULT_SETTINGS.items():
|
||||||
assert '# {} = {}\n'.format(*setting) in settings_file_contents
|
assert '# {} = {}\n'.format(*setting) in settings_file_contents
|
||||||
settings_file.close()
|
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, 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:
|
||||||
|
environ['XDG_CONFIG_HOME'] = xdg_config_home
|
||||||
|
else:
|
||||||
|
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 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import pytest
|
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 import corrector, const
|
||||||
|
from thefuck.system import Path
|
||||||
from tests.utils import Rule, Command, CorrectedCommand
|
from tests.utils import Rule, Command, CorrectedCommand
|
||||||
from thefuck.corrector import get_corrected_commands, organize_commands
|
from thefuck.corrector import get_corrected_commands, organize_commands
|
||||||
|
|
||||||
@@ -16,7 +11,7 @@ class TestGetRules(object):
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def glob(self, mocker):
|
def glob(self, mocker):
|
||||||
results = {}
|
results = {}
|
||||||
mocker.patch(pathlib_name + '.Path.glob',
|
mocker.patch('thefuck.system.Path.glob',
|
||||||
new_callable=lambda: lambda *_: results.pop('value', []))
|
new_callable=lambda: lambda *_: results.pop('value', []))
|
||||||
return lambda value: results.update({'value': value})
|
return lambda value: results.update({'value': value})
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,11 @@
|
|||||||
import os
|
import os
|
||||||
from subprocess import PIPE
|
from subprocess import PIPE
|
||||||
from mock import Mock
|
from mock import Mock
|
||||||
try:
|
|
||||||
from pathlib import Path
|
|
||||||
except ImportError:
|
|
||||||
from pathlib2 import Path
|
|
||||||
import pytest
|
import pytest
|
||||||
from tests.utils import CorrectedCommand, Rule, Command
|
from tests.utils import CorrectedCommand, Rule, Command
|
||||||
from thefuck import const
|
from thefuck import const
|
||||||
from thefuck.exceptions import EmptyCommand
|
from thefuck.exceptions import EmptyCommand
|
||||||
|
from thefuck.system import Path
|
||||||
|
|
||||||
|
|
||||||
class TestCorrectedCommand(object):
|
class TestCorrectedCommand(object):
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from mock import Mock
|
|||||||
import six
|
import six
|
||||||
from thefuck.utils import default_settings, \
|
from thefuck.utils import default_settings, \
|
||||||
memoize, get_closest, get_all_executables, replace_argument, \
|
memoize, get_closest, get_all_executables, replace_argument, \
|
||||||
get_all_matched_commands, is_app, for_app, cache, compatibility_call, \
|
get_all_matched_commands, is_app, for_app, cache, \
|
||||||
get_valid_history_without_current
|
get_valid_history_without_current
|
||||||
from tests.utils import Command
|
from tests.utils import Command
|
||||||
|
|
||||||
@@ -188,56 +188,6 @@ class TestCache(object):
|
|||||||
assert shelve == {key: {'etag': '0', 'value': 'test'}}
|
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):
|
class TestGetValidHistoryWithoutCurrent(object):
|
||||||
@pytest.yield_fixture(autouse=True)
|
@pytest.yield_fixture(autouse=True)
|
||||||
def fail_on_warning(self):
|
def fail_on_warning(self):
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
from imp import load_source
|
from imp import load_source
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
try:
|
from warnings import warn
|
||||||
from pathlib import Path
|
|
||||||
except ImportError:
|
|
||||||
from pathlib2 import Path
|
|
||||||
from six import text_type
|
from six import text_type
|
||||||
from . import const
|
from . import const
|
||||||
|
from .system import Path
|
||||||
|
|
||||||
|
|
||||||
class Settings(dict):
|
class Settings(dict):
|
||||||
@@ -42,15 +40,18 @@ class Settings(dict):
|
|||||||
settings_file.write(u'# {} = {}\n'.format(*setting))
|
settings_file.write(u'# {} = {}\n'.format(*setting))
|
||||||
|
|
||||||
def _get_user_dir_path(self):
|
def _get_user_dir_path(self):
|
||||||
# for backward compatibility, use `~/.thefuck` if it exists
|
"""Returns Path object representing the user config resource"""
|
||||||
legacy_user_dir = Path(os.path.expanduser('~/.thefuck'))
|
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():
|
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
|
return legacy_user_dir
|
||||||
else:
|
else:
|
||||||
default_xdg_config_dir = os.path.expanduser("~/.config")
|
return user_dir
|
||||||
xdg_config_dir = os.getenv("XDG_CONFIG_HOME", default_xdg_config_dir)
|
|
||||||
return Path(os.path.join(xdg_config_dir, 'thefuck'))
|
|
||||||
|
|
||||||
def _setup_user_dir(self):
|
def _setup_user_dir(self):
|
||||||
"""Returns user config dir, create it when it doesn't exist."""
|
"""Returns user config dir, create it when it doesn't exist."""
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
try:
|
|
||||||
from pathlib import Path
|
|
||||||
except ImportError:
|
|
||||||
from pathlib2 import Path
|
|
||||||
from .conf import settings
|
from .conf import settings
|
||||||
from .types import Rule
|
from .types import Rule
|
||||||
|
from .system import Path
|
||||||
from . import logs
|
from . import logs
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ from .system import init_output
|
|||||||
init_output()
|
init_output()
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from warnings import warn
|
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
import sys
|
import sys
|
||||||
from . import logs, types
|
from . import logs, types
|
||||||
@@ -37,17 +36,13 @@ def fix_command():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def print_alias(entry_point=True):
|
def print_alias():
|
||||||
"""Prints alias for current shell."""
|
"""Prints alias for current shell."""
|
||||||
if entry_point:
|
try:
|
||||||
warn('`thefuck-alias` is deprecated, use `thefuck --alias` instead.')
|
alias = sys.argv[2]
|
||||||
position = 1
|
except IndexError:
|
||||||
else:
|
alias = get_alias()
|
||||||
position = 2
|
|
||||||
|
|
||||||
alias = get_alias()
|
|
||||||
if len(sys.argv) > position:
|
|
||||||
alias = sys.argv[position]
|
|
||||||
print(shell.app_alias(alias))
|
print(shell.app_alias(alias))
|
||||||
|
|
||||||
|
|
||||||
@@ -76,8 +71,9 @@ def main():
|
|||||||
nargs='*',
|
nargs='*',
|
||||||
help='command that should be fixed')
|
help='command that should be fixed')
|
||||||
known_args = parser.parse_args(sys.argv[1:2])
|
known_args = parser.parse_args(sys.argv[1:2])
|
||||||
|
|
||||||
if known_args.alias:
|
if known_args.alias:
|
||||||
print_alias(False)
|
print_alias()
|
||||||
elif known_args.command:
|
elif known_args.command:
|
||||||
fix_command()
|
fix_command()
|
||||||
else:
|
else:
|
||||||
|
|||||||
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)
|
||||||
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)
|
||||||
@@ -1,18 +1,27 @@
|
|||||||
import re
|
import re
|
||||||
from thefuck.shells import shell
|
from thefuck.shells import shell
|
||||||
from thefuck.specific.git import git_support
|
from thefuck.specific.git import git_support
|
||||||
|
from thefuck.system import Path
|
||||||
|
from thefuck.utils import memoize
|
||||||
|
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
def _get_missing_file(command):
|
||||||
|
pathspec = re.findall(
|
||||||
|
r"error: pathspec '([^']*)' "
|
||||||
|
r'did not match any file\(s\) known to git.', command.stderr)[0]
|
||||||
|
if Path(pathspec).exists():
|
||||||
|
return pathspec
|
||||||
|
|
||||||
|
|
||||||
@git_support
|
@git_support
|
||||||
def match(command):
|
def match(command):
|
||||||
return 'did not match any file(s) known to git.' in command.stderr
|
return ('did not match any file(s) known to git.' in command.stderr
|
||||||
|
and _get_missing_file(command))
|
||||||
|
|
||||||
|
|
||||||
@git_support
|
@git_support
|
||||||
def get_new_command(command):
|
def get_new_command(command):
|
||||||
missing_file = re.findall(
|
missing_file = _get_missing_file(command)
|
||||||
r"error: pathspec '([^']*)' "
|
|
||||||
r'did not match any file\(s\) known to git.', command.stderr)[0]
|
|
||||||
|
|
||||||
formatme = shell.and_('git add -- {}', '{}')
|
formatme = shell.and_('git add -- {}', '{}')
|
||||||
return formatme.format(missing_file, command.script)
|
return formatme.format(missing_file, command.script)
|
||||||
|
|||||||
16
thefuck/rules/git_bisect_usage.py
Normal file
16
thefuck/rules/git_bisect_usage.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import re
|
||||||
|
from thefuck.utils import replace_command
|
||||||
|
from thefuck.specific.git import git_support
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def match(command):
|
||||||
|
return ('bisect' in command.script_parts and
|
||||||
|
'usage: git bisect' in command.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def get_new_command(command):
|
||||||
|
broken = re.findall(r'git bisect ([^ $]*).*', command.script)[0]
|
||||||
|
usage = re.findall(r'usage: git bisect \[([^\]]+)\]', command.stderr)[0]
|
||||||
|
return replace_command(command, broken, usage.split('|'))
|
||||||
17
thefuck/rules/git_diff_no_index.py
Normal file
17
thefuck/rules/git_diff_no_index.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from thefuck.utils import replace_argument
|
||||||
|
from thefuck.specific.git import git_support
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def match(command):
|
||||||
|
files = [arg for arg in command.script_parts[2:]
|
||||||
|
if not arg.startswith('-')]
|
||||||
|
return ('diff' in command.script
|
||||||
|
and '--no-index' not in command.script
|
||||||
|
and not command.stdout
|
||||||
|
and len(files) == 2)
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def get_new_command(command):
|
||||||
|
return replace_argument(command.script, 'diff', 'diff --no-index')
|
||||||
30
thefuck/rules/git_flag_after_filename.py
Normal file
30
thefuck/rules/git_flag_after_filename.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import re
|
||||||
|
from thefuck.specific.git import git_support
|
||||||
|
|
||||||
|
error_pattern = "fatal: bad flag '(.*?)' used after filename"
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def match(command):
|
||||||
|
return re.search(error_pattern, command.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def get_new_command(command):
|
||||||
|
command_parts = command.script_parts[:]
|
||||||
|
|
||||||
|
# find the bad flag
|
||||||
|
bad_flag = re.search(error_pattern, command.stderr).group(1)
|
||||||
|
bad_flag_index = command_parts.index(bad_flag)
|
||||||
|
|
||||||
|
# find the filename
|
||||||
|
for index in reversed(range(bad_flag_index)):
|
||||||
|
if command_parts[index][0] != '-':
|
||||||
|
filename_index = index
|
||||||
|
break
|
||||||
|
|
||||||
|
# swap them
|
||||||
|
command_parts[bad_flag_index], command_parts[filename_index] = \
|
||||||
|
command_parts[filename_index], command_parts[bad_flag_index] # noqa: E122
|
||||||
|
|
||||||
|
return u' '.join(command_parts)
|
||||||
14
thefuck/rules/git_pull_uncommitted_changes.py
Normal file
14
thefuck/rules/git_pull_uncommitted_changes.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
from thefuck.shells import shell
|
||||||
|
from thefuck.specific.git import git_support
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def match(command):
|
||||||
|
return ('pull' in command.script
|
||||||
|
and ('You have unstaged changes' in command.stderr
|
||||||
|
or 'contains uncommitted changes' in command.stderr))
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def get_new_command(command):
|
||||||
|
return shell.and_('git stash', 'git pull', 'git stash pop')
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from thefuck.utils import replace_argument
|
||||||
from thefuck.specific.git import git_support
|
from thefuck.specific.git import git_support
|
||||||
|
|
||||||
|
|
||||||
@@ -7,6 +8,29 @@ def match(command):
|
|||||||
and 'set-upstream' in command.stderr)
|
and 'set-upstream' in command.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_upstream_option_index(command_parts):
|
||||||
|
if '--set-upstream' in command_parts:
|
||||||
|
return command_parts.index('--set-upstream')
|
||||||
|
elif '-u' in command_parts:
|
||||||
|
return command_parts.index('-u')
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
@git_support
|
@git_support
|
||||||
def get_new_command(command):
|
def get_new_command(command):
|
||||||
return command.stderr.split('\n')[-3].strip()
|
# If --set-upstream or -u are passed, remove it and its argument. This is
|
||||||
|
# because the remaining arguments are concatenated onto the command suggested
|
||||||
|
# by git, which includes --set-upstream and its argument
|
||||||
|
command_parts = command.script_parts[:]
|
||||||
|
upstream_option_index = _get_upstream_option_index(command_parts)
|
||||||
|
|
||||||
|
if upstream_option_index is not None:
|
||||||
|
command_parts.pop(upstream_option_index)
|
||||||
|
|
||||||
|
# In case of `git push -u` we don't have next argument:
|
||||||
|
if len(command_parts) > upstream_option_index:
|
||||||
|
command_parts.pop(upstream_option_index)
|
||||||
|
|
||||||
|
push_upstream = command.stderr.split('\n')[-3].strip().partition('git ')[2]
|
||||||
|
return replace_argument(" ".join(command_parts), 'push', push_upstream)
|
||||||
|
|||||||
17
thefuck/rules/git_rebase_merge_dir.py
Normal file
17
thefuck/rules/git_rebase_merge_dir.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from difflib import get_close_matches
|
||||||
|
from thefuck.specific.git import git_support
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def match(command):
|
||||||
|
return (' rebase' in command.script and
|
||||||
|
'It seems that there is already a rebase-merge directory' in command.stderr and
|
||||||
|
'I wonder if you are in the middle of another rebase' in command.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def get_new_command(command):
|
||||||
|
command_list = ['git rebase --continue', 'git rebase --abort', 'git rebase --skip']
|
||||||
|
rm_cmd = command.stderr.split('\n')[-4]
|
||||||
|
command_list.append(rm_cmd.strip())
|
||||||
|
return get_close_matches(command.script, command_list, 4, 0)
|
||||||
19
thefuck/rules/git_rm_local_modifications.py
Normal file
19
thefuck/rules/git_rm_local_modifications.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from thefuck.specific.git import git_support
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def match(command):
|
||||||
|
return (' rm ' in command.script and
|
||||||
|
'error: the following file has local modifications' in command.stderr and
|
||||||
|
'use --cached to keep the file, or -f to force removal' in command.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def get_new_command(command):
|
||||||
|
command_parts = command.script_parts[:]
|
||||||
|
index = command_parts.index('rm') + 1
|
||||||
|
command_parts.insert(index, '--cached')
|
||||||
|
command_list = [u' '.join(command_parts)]
|
||||||
|
command_parts[index] = '-f'
|
||||||
|
command_list.append(u' '.join(command_parts))
|
||||||
|
return command_list
|
||||||
@@ -10,6 +10,7 @@ def match(command):
|
|||||||
|
|
||||||
@git_support
|
@git_support
|
||||||
def get_new_command(command):
|
def get_new_command(command):
|
||||||
index = command.script_parts.index('rm') + 1
|
command_parts = command.script_parts[:]
|
||||||
command.script_parts.insert(index, '-r')
|
index = command_parts.index('rm') + 1
|
||||||
return u' '.join(command.script_parts)
|
command_parts.insert(index, '-r')
|
||||||
|
return u' '.join(command_parts)
|
||||||
|
|||||||
18
thefuck/rules/git_stash_pop.py
Normal file
18
thefuck/rules/git_stash_pop.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from thefuck.shells import shell
|
||||||
|
from thefuck.specific.git import git_support
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def match(command):
|
||||||
|
return ('stash' in command.script
|
||||||
|
and 'pop' in command.script
|
||||||
|
and 'Your local changes to the following files would be overwritten by merge' in command.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
@git_support
|
||||||
|
def get_new_command(command):
|
||||||
|
return shell.and_('git add .', 'git stash pop', 'git reset .')
|
||||||
|
|
||||||
|
|
||||||
|
# make it come before the other applicable rules
|
||||||
|
priority = 900
|
||||||
25
thefuck/rules/ifconfig_device_not_found.py
Normal file
25
thefuck/rules/ifconfig_device_not_found.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import subprocess
|
||||||
|
from thefuck.utils import for_app, replace_command, eager
|
||||||
|
import sys
|
||||||
|
|
||||||
|
@for_app('ifconfig')
|
||||||
|
def match(command):
|
||||||
|
return 'error fetching interface information: Device not found' \
|
||||||
|
in command.stderr
|
||||||
|
|
||||||
|
|
||||||
|
@eager
|
||||||
|
def _get_possible_interfaces():
|
||||||
|
proc = subprocess.Popen(['ifconfig', '-a'], stdout=subprocess.PIPE)
|
||||||
|
for line in proc.stdout.readlines():
|
||||||
|
line = line.decode()
|
||||||
|
if line and line != '\n' and not line.startswith(' '):
|
||||||
|
yield line.split(' ')[0]
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command):
|
||||||
|
interface = command.stderr.split(' ')[0][:-1]
|
||||||
|
possible_interfaces = _get_possible_interfaces()
|
||||||
|
return replace_command(command, interface, possible_interfaces)
|
||||||
|
|
||||||
|
|
||||||
10
thefuck/rules/ls_all.py
Normal file
10
thefuck/rules/ls_all.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from thefuck.utils import for_app
|
||||||
|
|
||||||
|
|
||||||
|
@for_app('ls')
|
||||||
|
def match(command):
|
||||||
|
return command.stdout.strip() == ''
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command):
|
||||||
|
return ' '.join(['ls', '-A'] + command.script_parts[1:])
|
||||||
@@ -12,10 +12,22 @@ def get_new_command(command):
|
|||||||
if '2' in command.script:
|
if '2' in command.script:
|
||||||
return command.script.replace("2", "3")
|
return command.script.replace("2", "3")
|
||||||
|
|
||||||
|
last_arg = command.script_parts[-1]
|
||||||
|
help_command = last_arg + ' --help'
|
||||||
|
|
||||||
|
# If there are no man pages for last_arg, suggest `last_arg --help` instead.
|
||||||
|
# Otherwise, suggest `--help` after suggesting other man page sections.
|
||||||
|
if command.stderr.strip() == 'No manual entry for ' + last_arg:
|
||||||
|
return [help_command]
|
||||||
|
|
||||||
split_cmd2 = command.script_parts
|
split_cmd2 = command.script_parts
|
||||||
split_cmd3 = split_cmd2[:]
|
split_cmd3 = split_cmd2[:]
|
||||||
|
|
||||||
split_cmd2.insert(1, ' 2 ')
|
split_cmd2.insert(1, ' 2 ')
|
||||||
split_cmd3.insert(1, ' 3 ')
|
split_cmd3.insert(1, ' 3 ')
|
||||||
|
|
||||||
return ["".join(split_cmd3), "".join(split_cmd2)]
|
return [
|
||||||
|
"".join(split_cmd3),
|
||||||
|
"".join(split_cmd2),
|
||||||
|
help_command,
|
||||||
|
]
|
||||||
|
|||||||
@@ -6,9 +6,8 @@ from thefuck.specific.sudo import sudo_support
|
|||||||
|
|
||||||
@sudo_support
|
@sudo_support
|
||||||
def match(command):
|
def match(command):
|
||||||
toks = command.script_parts
|
return (command.script_parts
|
||||||
return (toks
|
and command.script_parts[0].endswith('.py')
|
||||||
and toks[0].endswith('.py')
|
|
||||||
and ('Permission denied' in command.stderr or
|
and ('Permission denied' in command.stderr or
|
||||||
'command not found' in command.stderr))
|
'command not found' in command.stderr))
|
||||||
|
|
||||||
|
|||||||
11
thefuck/rules/remove_trailing_cedilla.py
Normal file
11
thefuck/rules/remove_trailing_cedilla.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
CEDILLA = u"ç"
|
||||||
|
|
||||||
|
|
||||||
|
def match(command):
|
||||||
|
return command.script.endswith(CEDILLA)
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command):
|
||||||
|
return command.script[:-1]
|
||||||
@@ -19,7 +19,8 @@ patterns = ['permission denied',
|
|||||||
'you don\'t have access to the history db.',
|
'you don\'t have access to the history db.',
|
||||||
'authentication is required',
|
'authentication is required',
|
||||||
'edspermissionerror',
|
'edspermissionerror',
|
||||||
'you don\'t have write permissions']
|
'you don\'t have write permissions',
|
||||||
|
'use `sudo`']
|
||||||
|
|
||||||
|
|
||||||
def match(command):
|
def match(command):
|
||||||
|
|||||||
@@ -17,6 +17,6 @@ def match(command):
|
|||||||
|
|
||||||
@sudo_support
|
@sudo_support
|
||||||
def get_new_command(command):
|
def get_new_command(command):
|
||||||
cmd = command.script_parts
|
cmd = command.script_parts[:]
|
||||||
cmd[-1], cmd[-2] = cmd[-2], cmd[-1]
|
cmd[-1], cmd[-2] = cmd[-2], cmd[-1]
|
||||||
return ' '.join(cmd)
|
return ' '.join(cmd)
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
try:
|
|
||||||
from pathlib import Path
|
|
||||||
except ImportError:
|
|
||||||
from pathlib2 import Path
|
|
||||||
|
|
||||||
from thefuck.utils import for_app, replace_command, eager, memoize
|
from thefuck.utils import for_app, replace_command, eager, memoize
|
||||||
|
from thefuck.system import Path
|
||||||
|
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ shells = {'bash': Bash,
|
|||||||
def _get_shell():
|
def _get_shell():
|
||||||
proc = Process(os.getpid())
|
proc = Process(os.getpid())
|
||||||
|
|
||||||
while proc is not None:
|
while proc is not None and proc.pid > 0:
|
||||||
try:
|
try:
|
||||||
name = proc.name()
|
name = proc.name()
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class Bash(Generic):
|
|||||||
" eval $TF_CMD".format(fuck)
|
" eval $TF_CMD".format(fuck)
|
||||||
|
|
||||||
if settings.alter_history:
|
if settings.alter_history:
|
||||||
return alias + " && history -s $TF_CMD'"
|
return alias + "; history -s $TF_CMD'"
|
||||||
else:
|
else:
|
||||||
return alias + "'"
|
return alias + "'"
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ class Fish(Generic):
|
|||||||
|
|
||||||
def app_alias(self, fuck):
|
def app_alias(self, fuck):
|
||||||
if settings.alter_history:
|
if settings.alter_history:
|
||||||
alter_history = (' history --delete $fucked_up_command\n'
|
alter_history = (' builtin history delete --exact'
|
||||||
' history --merge ^ /dev/null\n')
|
' --case-sensitive -- $fucked_up_command\n'
|
||||||
|
' builtin history merge ^ /dev/null\n')
|
||||||
else:
|
else:
|
||||||
alter_history = ''
|
alter_history = ''
|
||||||
# It is VERY important to have the variables declared WITHIN the alias
|
# It is VERY important to have the variables declared WITHIN the alias
|
||||||
|
|||||||
@@ -65,9 +65,19 @@ class Generic(object):
|
|||||||
|
|
||||||
def split_command(self, command):
|
def split_command(self, command):
|
||||||
"""Split the command using shell-like syntax."""
|
"""Split the command using shell-like syntax."""
|
||||||
|
encoded = self.encode_utf8(command)
|
||||||
|
splitted = shlex.split(encoded)
|
||||||
|
return self.decode_utf8(splitted)
|
||||||
|
|
||||||
|
def encode_utf8(self, command):
|
||||||
if six.PY2:
|
if six.PY2:
|
||||||
return [s.decode('utf8') for s in shlex.split(command.encode('utf8'))]
|
return command.encode('utf8')
|
||||||
return shlex.split(command)
|
return command
|
||||||
|
|
||||||
|
def decode_utf8(self, command_parts):
|
||||||
|
if six.PY2:
|
||||||
|
return [s.decode('utf8') for s in command_parts]
|
||||||
|
return command_parts
|
||||||
|
|
||||||
def quote(self, s):
|
def quote(self, s):
|
||||||
"""Return a shell-escaped version of the string s."""
|
"""Return a shell-escaped version of the string s."""
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class Zsh(Generic):
|
|||||||
" eval $TF_CMD".format(alias_name)
|
" eval $TF_CMD".format(alias_name)
|
||||||
|
|
||||||
if settings.alter_history:
|
if settings.alter_history:
|
||||||
return alias + " && print -s $TF_CMD'"
|
return alias + " ; test -n \"$TF_CMD\" && print -s $TF_CMD'"
|
||||||
else:
|
else:
|
||||||
return alias + "'"
|
return alias + "'"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import tty
|
import tty
|
||||||
import termios
|
import termios
|
||||||
@@ -33,3 +34,15 @@ def get_key():
|
|||||||
return const.KEY_DOWN
|
return const.KEY_DOWN
|
||||||
|
|
||||||
return ch
|
return ch
|
||||||
|
|
||||||
|
try:
|
||||||
|
from pathlib import Path
|
||||||
|
except ImportError:
|
||||||
|
from pathlib2 import Path
|
||||||
|
|
||||||
|
|
||||||
|
def _expanduser(self):
|
||||||
|
return self.__class__(os.path.expanduser(str(self)))
|
||||||
|
|
||||||
|
if not hasattr(Path, 'expanduser'):
|
||||||
|
Path.expanduser = _expanduser
|
||||||
|
|||||||
@@ -25,3 +25,15 @@ def get_key():
|
|||||||
|
|
||||||
encoding = sys.stdout.encoding or os.environ.get('PYTHONIOENCODING', 'utf-8')
|
encoding = sys.stdout.encoding or os.environ.get('PYTHONIOENCODING', 'utf-8')
|
||||||
return ch.decode(encoding)
|
return ch.decode(encoding)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from pathlib import Path
|
||||||
|
except ImportError:
|
||||||
|
from pathlib2 import Path
|
||||||
|
|
||||||
|
|
||||||
|
def _expanduser(self):
|
||||||
|
return self.__class__(os.path.expanduser(str(self)))
|
||||||
|
|
||||||
|
# pathlib's expanduser fails on windows, see http://bugs.python.org/issue19776
|
||||||
|
Path.expanduser = _expanduser
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ from .shells import shell
|
|||||||
from .conf import settings
|
from .conf import settings
|
||||||
from .const import DEFAULT_PRIORITY, ALL_ENABLED
|
from .const import DEFAULT_PRIORITY, ALL_ENABLED
|
||||||
from .exceptions import EmptyCommand
|
from .exceptions import EmptyCommand
|
||||||
from .utils import compatibility_call
|
|
||||||
|
|
||||||
|
|
||||||
class Command(object):
|
class Command(object):
|
||||||
@@ -35,7 +34,8 @@ class Command(object):
|
|||||||
except Exception:
|
except Exception:
|
||||||
logs.debug(u"Can't split command script {} because:\n {}".format(
|
logs.debug(u"Can't split command script {} because:\n {}".format(
|
||||||
self, sys.exc_info()))
|
self, sys.exc_info()))
|
||||||
self._script_parts = None
|
self._script_parts = []
|
||||||
|
|
||||||
return self._script_parts
|
return self._script_parts
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
@@ -225,7 +225,7 @@ class Rule(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
with logs.debug_time(u'Trying rule: {};'.format(self.name)):
|
with logs.debug_time(u'Trying rule: {};'.format(self.name)):
|
||||||
if compatibility_call(self.match, command):
|
if self.match(command):
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
logs.rule_failed(self, sys.exc_info())
|
logs.rule_failed(self, sys.exc_info())
|
||||||
@@ -237,7 +237,7 @@ class Rule(object):
|
|||||||
:rtype: Iterable[CorrectedCommand]
|
:rtype: Iterable[CorrectedCommand]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
new_commands = compatibility_call(self.get_new_command, command)
|
new_commands = self.get_new_command(command)
|
||||||
if not isinstance(new_commands, list):
|
if not isinstance(new_commands, list):
|
||||||
new_commands = (new_commands,)
|
new_commands = (new_commands,)
|
||||||
for n, new_command in enumerate(new_commands):
|
for n, new_command in enumerate(new_commands):
|
||||||
@@ -283,7 +283,7 @@ class CorrectedCommand(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
if self.side_effect:
|
if self.side_effect:
|
||||||
compatibility_call(self.side_effect, old_cmd, self.script)
|
self.side_effect(old_cmd, self.script)
|
||||||
if settings.alter_history:
|
if settings.alter_history:
|
||||||
shell.put_to_history(self.script)
|
shell.put_to_history(self.script)
|
||||||
# This depends on correct setting of PYTHONIOENCODING by the alias:
|
# This depends on correct setting of PYTHONIOENCODING by the alias:
|
||||||
|
|||||||
@@ -4,17 +4,13 @@ import pkg_resources
|
|||||||
import re
|
import re
|
||||||
import shelve
|
import shelve
|
||||||
import six
|
import six
|
||||||
from .conf import settings
|
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
from decorator import decorator
|
from decorator import decorator
|
||||||
from difflib import get_close_matches
|
from difflib import get_close_matches
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from inspect import getargspec
|
|
||||||
try:
|
|
||||||
from pathlib import Path
|
|
||||||
except ImportError:
|
|
||||||
from pathlib2 import Path
|
|
||||||
from warnings import warn
|
from warnings import warn
|
||||||
|
from .conf import settings
|
||||||
|
from .system import Path
|
||||||
|
|
||||||
DEVNULL = open(os.devnull, 'w')
|
DEVNULL = open(os.devnull, 'w')
|
||||||
|
|
||||||
@@ -163,7 +159,7 @@ def is_app(command, *app_names, **kwargs):
|
|||||||
if kwargs:
|
if kwargs:
|
||||||
raise TypeError("got an unexpected keyword argument '{}'".format(kwargs.keys()))
|
raise TypeError("got an unexpected keyword argument '{}'".format(kwargs.keys()))
|
||||||
|
|
||||||
if command.script_parts is not None and len(command.script_parts) > at_least:
|
if len(command.script_parts) > at_least:
|
||||||
return command.script_parts[0] in app_names
|
return command.script_parts[0] in app_names
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@@ -245,27 +241,6 @@ def cache(*depends_on):
|
|||||||
cache.disabled = False
|
cache.disabled = False
|
||||||
|
|
||||||
|
|
||||||
def compatibility_call(fn, *args):
|
|
||||||
"""Special call for compatibility with user-defined old-style rules
|
|
||||||
with `settings` param.
|
|
||||||
|
|
||||||
"""
|
|
||||||
fn_args_count = len(getargspec(fn).args)
|
|
||||||
if fn.__name__ in ('match', 'get_new_command') and fn_args_count == 2:
|
|
||||||
warn("Two arguments `{}` from rule `{}` is deprecated, please "
|
|
||||||
"remove `settings` argument and use "
|
|
||||||
"`from thefuck.conf import settings` instead."
|
|
||||||
.format(fn.__name__, fn.__module__))
|
|
||||||
args += (settings,)
|
|
||||||
if fn.__name__ == 'side_effect' and fn_args_count == 3:
|
|
||||||
warn("Three arguments `side_effect` from rule `{}` is deprecated, "
|
|
||||||
"please remove `settings` argument and use `from thefuck.conf "
|
|
||||||
"import settings` instead."
|
|
||||||
.format(fn.__name__, fn.__module__))
|
|
||||||
args += (settings,)
|
|
||||||
return fn(*args)
|
|
||||||
|
|
||||||
|
|
||||||
def get_installation_info():
|
def get_installation_info():
|
||||||
return pkg_resources.require('thefuck')[0]
|
return pkg_resources.require('thefuck')[0]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user