1
0
mirror of https://github.com/nvbn/thefuck.git synced 2025-10-31 23:22:10 +00:00

Compare commits

...

351 Commits
3.18 ... master

Author SHA1 Message Date
Alan Gabbianelli
c7e7e1d884 Fix typos in README.md 2024-01-25 20:52:35 +01:00
Pablo Santiago Blum de Aguiar
62e0767c50 #N/A: Fix a couple of issues after new flake8 release 2023-07-30 22:22:37 +02:00
Gerardo Grignoli
3cd187a3bb #1329: Add support for Windows CMD and easier setup for Powershell
* feat: Added nicer support for Windows CMD & Powershell

* Fix  typo

* Fix CMD console color after thefuck Ctrl-C

* Update setup.py

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>

* Update setup.py

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>

* Addressed PR comments

* fix spacing and newline issues

---------

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2023-07-10 15:09:27 +02:00
Pablo Santiago Blum de Aguiar
0420442e77 #1248: Use imp only when importlib.util not available
The imp module is deprecated and will be removed in Python 12.
2023-07-10 14:43:45 +02:00
Pablo Santiago Blum de Aguiar
617aaa1fd0 #1248: Skip a failing test when running on Windows 2023-07-10 14:40:45 +02:00
Pablo Santiago Blum de Aguiar
cf0921be4a #1248: Check for multiple patterns in functional tests 2023-07-10 14:39:58 +02:00
Pablo Santiago Blum de Aguiar
ef1ea4b4dd #1248: Check container status before test functions 2023-07-10 14:36:42 +02:00
Pablo Santiago Blum de Aguiar
2cadcca904 #1248: Reuse Docker images in functional tests 2023-07-10 14:34:46 +02:00
Pablo Santiago Blum de Aguiar
d81929f294 #1248: Move deprecated Python versions to separate workflow job 2023-07-10 14:22:23 +02:00
Pablo Santiago Blum de Aguiar
b03e0913d3 #1248: Run workflows on push and pull_request 2023-07-10 14:20:40 +02:00
Hugo van Kemenade
b79e104df8 Add support for Python 3.11 2023-07-09 13:03:32 +02:00
Hugo van Kemenade
3f71959b1b Add python_requires to help pip 2023-07-09 13:03:32 +02:00
Hugo van Kemenade
51b82c5377 Update min Python 3 version required in README 2023-07-09 13:03:32 +02:00
Hugo van Kemenade
5f562a185c Drop the dot https://twitter.com/pytestdotorg/status/753767547866972160 2023-07-09 13:03:27 +02:00
Hugo van Kemenade
1a242c7daa Test on Python 3.10 final 2023-07-09 13:01:48 +02:00
josepdaniel
ceeaeab94b Add terraform 'no command' rule (#1317)
* Add terraform 'no command' rule

* Feedback from PR

Co-authored-by: Joseph Daniel <jdn@logpoint.com>
2022-09-25 21:37:47 +02:00
Pablo Aguiar
77627a3140 #N/A: Define branches in workflow (#1328) 2022-09-07 21:33:40 +02:00
Pablo Santiago Blum de Aguiar
03a032295d #N/A: Change workflow triggers 2022-08-31 22:36:44 +02:00
Dan
56c16b737f Added Arch based installation (#1319)
Co-authored-by: Dan <dan@arch.localdomain>
2022-08-31 20:42:41 +02:00
Miguel Guthridge
f9768cf929 #1302: Add new git_clone_missing rule
* Add git clone missing rule

* Clean up tests and improve matching

* Make rules behave correctly?

* Improve tests and redo matcher

* Remove unnecessary tests

* Improvements as per code review

* Remove dead tests

* Improve match function for git clone missing

* Improve tests

* Fix more tests

* Fix failing test

* Add Macos's /bin/sh command output to match

* Add output for lines uncovered by tests

Co-authored-by: Pablo Santiago Blum de Aguiar <scorphus@gmail.com>
2022-07-03 13:22:36 +02:00
Peter
ed40463105 #1299: Update output for brew_install and cleanup (#1316)
* fix: Update output for brew_install test: fixed

* chore: fixing flake8 styles

* feat: show more suggestions

* test: new functions added and multi suggestions

* refactor: rename to _get_suggestions
2022-07-02 15:06:00 +02:00
Peter
f1b7d879bd #1290: Update output for brew_update_formula
* fix: brew_update_formula change output string

* fix: regex removed, test: backtick added

* Update tests/rules/test_brew_update_formula.py

* Update thefuck/rules/brew_update_formula.py

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2022-06-28 18:28:38 +02:00
Nikos Kakonas
5198b34f24 #1282: Keep quotes in the script on no_command rule
Co-authored-by: Pablo Santiago Blum de Aguiar <scorphus@gmail.com>
2022-06-13 23:29:15 +02:00
Pablo Santiago Blum de Aguiar
1a1b5200a9 #N/A: Lock pyte<=0.8.0 for Python 2 2022-06-08 23:39:19 +02:00
0xphk
06cb50b1e3 #1308: Add updatedb (mlocate) pattern to sudo rule
* added updatedb(mlocate) to sudo rules

* Add test

Co-authored-by: phk <phk@terminal21.de>
Co-authored-by: Pablo Santiago Blum de Aguiar <scorphus@gmail.com>
2022-06-05 22:58:31 +02:00
Oļegs Čapligins
16eb823066 #1261: Add two more patterns to sudo rule (#1307)
* macos shutdown sudo fix

* Update tests/rules/test_sudo.py

* Update thefuck/rules/sudo.py

* Update tests/rules/test_sudo.py

* Update thefuck/rules/sudo.py

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2022-05-29 21:40:31 +02:00
Tagada
d8ddf5a2be #1279: Add pikaur AUR manager to Arch Linux's commands
* Add pikaur AUR manager to Arch Linux's commands

* Update README.md

* Update test_pacman_not_found.py

* Update pacman_not_found.py

* Update README.md

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2022-03-27 22:06:40 +02:00
Marek Šuppa
cf1beb6b89 fix: Add missing comma
* Add missing comma in a test
2022-01-30 22:34:38 +01:00
Anupam Patil
925e562d96 Updated license date to 2022 2022-01-20 22:01:21 +01:00
Pablo Santiago Blum de Aguiar
841e3f9e13 Bump to 3.32 2022-01-02 22:45:09 +01:00
Joris Hartog
0f4a523dc4 Encapsulate force_command in _get_raw_command
Using the `force_command` argument will run into issues as the
`_get_raw_command` method simply returns the value of `force_command`
(which is a string) while it should actually return a list.

Fix #1240
2021-12-20 00:05:47 +01:00
Benjamin Rood
c719712b62 Use --user with pip, not sudo pip
`sudo` with `pip` is [considered unsafe](https://stackoverflow.com/a/22517157/2469559).

Instead, run such commands with the `--user` argument to get the same result _safely._
2021-09-05 16:58:35 +02:00
Pablo Santiago Blum de Aguiar
51e4e87280 #1227: Make git_support support output-independent rules
Fix #1227
2021-08-17 15:41:54 +02:00
Pablo Santiago Blum de Aguiar
7b7c150bb7 #697: Encode expanded script on Python 2
Fix #697
2021-08-17 15:40:56 +02:00
Yotam Salmon
2a166a7dec #977: Add wrong_hyphen_before_subcommand rule
Co-authored-by: user <avi.salmon@intel.com>
Co-authored-by: Pablo Santiago Blum de Aguiar <scorphus@gmail.com>
2021-08-07 23:26:36 +02:00
Lars Alexander Blumberg
8fa10b1049 #868: Fix outdated link to homebrew for Linux (#1226) 2021-08-07 13:12:12 +02:00
Pablo Santiago Blum de Aguiar
7f3442747e #579: Ignore commands of len 1 in missing_space_before_subcommand 2021-08-01 22:24:29 +02:00
Pablo Santiago Blum de Aguiar
8bebce331e #933: Correctly redefine the function with a cache 2021-08-01 22:07:19 +02:00
Pablo Santiago Blum de Aguiar
dbc435c040 #618: Fix git_push_without_commits rule
The rule was in a non-working state. And the tests needed some bit of
simplification. Certain degree of repetition is oftentimes a good thing.
2021-07-29 22:11:34 +02:00
Pablo Santiago Blum de Aguiar
30c90bccaa #1184: Configure devcontainer shell with recommended way
https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration
2021-07-29 22:09:21 +02:00
Pablo Santiago Blum de Aguiar
8e8c80c227 #1188: Remove only leading whitespace chars from script
Fix #1188
2021-07-29 21:43:24 +02:00
Pablo Santiago Blum de Aguiar
c2df71caed #994: Replace decoding errors with the replacement marker
Fix #994

Reference: https://docs.python.org/3/library/codecs.html#error-handlers
2021-07-29 21:37:19 +02:00
Pablo Santiago Blum de Aguiar
eb05b28c5b #N/A: Replace only exact words when expanding a Git alias 2021-07-29 21:36:15 +02:00
Divy Jain
a2a6cbdc70 #894: Combine commands with shell.and_ in docker_login rule 2021-07-29 13:49:42 +02:00
Pablo Santiago Blum de Aguiar
58ddd4338a #1215: Initiate settings before printing the alias 2021-07-21 13:09:19 +02:00
Dave Storey
58f61d8090 #1184: Add devcontainer for easy Python development
* adding devcontainer and new rule for main-master

* update devcontainer work

* cleaning up devcontainer.json

* fixed line ending

* move to VARIANT 3

* Update .devcontainer/devcontainer.json

* Update .devcontainer/devcontainer.json

* Update .devcontainer/devcontainer.json

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2021-07-19 22:47:19 +02:00
Pablo Santiago Blum de Aguiar
0668822abb #1215: Remove redirection to stderr with the ^ character
Redirection to standard error with the `^` character is disabled by
default since Fish Shell version 3.3[1].

Fix #1214

[1]: https://github.com/fish-shell/fish-shell/blob/master/CHANGELOG.rst#deprecations-and-removed-features-1
2021-07-18 15:10:48 +02:00
Pablo Santiago Blum de Aguiar
711feb4df5 #1184: Improve + fix git_main_master rule 2021-07-09 16:13:25 +02:00
Dave Storey
70a42b54ab #1184: Add new rule for main / master Git branches 2021-04-06 14:50:43 +01:00
Pablo Santiago Blum de Aguiar
11b70526f7 #1131: Improve git_commit_add rule
Add more capabilities to the rule, remove its priority and fix tests
2021-07-08 21:43:35 +02:00
Sergei Haller
55922e4dbe #1131: Add rule for Git commit with no added files 2020-09-08 11:47:05 +02:00
Pablo Santiago Blum de Aguiar
799f4127ca #942: Improve git_branch_0flag rule - with a new name 2021-07-13 15:36:11 +02:00
Ryan Delaney
fe1942866b #1133: Match commands with path prefixes in @for_app decorations
* Resolve paths before checking app identity

Commands entered with a path do not match is_app. I encountered this
when working with a test for the rm_dir rule. This rule did not use the
@for_app decorator, but when I migrated it, the test for "./bin/hdfs.."
failed because 'hdfs' was recognized as a command, while "./bin/hdfs"
was not.

This commit addresses the false negative by resolving path names in the
command, via os.path.basename.

* Remove paths from for_app invocations in rules

I presume that the `./` in `./gradlew` was used here because thefuck
would not find an app match on just `gradlew`, and thus no fucks would
be given on the most common and idiomatic way of invoking gradlew.

After 8faf9b1, thefuck does not distinguish between commands with
paths and those without. Therefore, the tests for this rule are now
broken because thefuck strips paths from the _user_'s command, but not
from the for_app decoration.

This commit addresses that problem by changing the for_app decoration to
this rule.
2021-07-07 23:05:55 +02:00
M. H. Kwon
13fda64d6e #1109: Fix a typo on a comment
on -> one
2021-07-06 16:58:44 +02:00
Abraham Chan
6111523034 #1210: Add rule 'rails_migrations_pending'
* Add rule 'rails_migrations_pending'

* Update thefuck/rules/rails_migrations_pending.py

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>

* Add initial command to corrected command

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2021-07-06 12:52:54 +02:00
ProfessorTom
24576b30b2 #942: Add new git_branch_0v_to_dash_v rule
* fix fuckup `branch 0v` by...

...deleting branch `0v` and running `git branch -v` as the user intended

* use quotes consistently

* provide new  solution implementation based on feedback on PR

* rename files to more accurately reflect their more generic contents

* update import statement to match new file name

* update command name in README.md

* separate out matching tests so the pattern is clear for those who add matches in the future
2021-07-01 23:07:38 +02:00
T.J. Kolberg
373f445e9b #1150: Update the name of macOS on README
* Update README.md

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2021-07-01 11:47:12 +02:00
Divy Jain
54253027e3 #1123: Update composer_not_command rule (#1135)
Fix #1123
2021-06-30 23:10:06 +02:00
theslimshaney
9201ce79cf #1039: Remove all leading $ not just one 2021-06-30 22:46:20 +02:00
Romain Heller
7f97818663 #455: [README] Add uninstall instructions (#1171)
* ~[Doc] Add Uninstall instructions

As we need the package and to modify the shell config, users could have a pain in the ass when it comes to retire *The Fuck* from the system.

* Update README.md

* Update README.md

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2021-06-30 14:20:48 +02:00
Abraham Chan
2f4adcf3cb #N/A: Fix yield_fixture deprecation (#1211) 2021-06-29 21:26:13 +02:00
Elisha Hollander
06e14afd17 #N/A: Fix grammar and spelling errors (#1193)
* Fix grammar and spelling errors

* Update README.md

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2021-06-29 21:25:01 +02:00
Utkarsh Agarwal
3651b0fa0c #1164: Optimize GIFs with ImgBot
*Total -- 1,239.63kb -> 1,088.54kb (12.19%)

/example_instant_mode.gif -- 535.22kb -> 457.41kb (14.54%)
/example.gif -- 704.41kb -> 631.13kb (10.4%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>

Co-authored-by: ImgBotApp <ImgBotHelp@gmail.com>
2021-06-23 12:19:47 +02:00
Felix Yan
d723bb71b7 Avoid using pkg_resources
pkg_resources is expensive to load, and it's an external module provided
by the setuptools project.

Let's use importlib.metadata from Python 3.8+'s stdlib when available, which
is much faster. This also erases setuptools from thefuck's runtime
dependency.

Simple benchmark data for `thefuck --version`:

Before: 0.602s
After: 0.169s
2021-06-21 17:06:02 +02:00
Hamid Nazari
b2e1886de8 Fix git_hook_bypass priority (#1207) 2021-06-21 16:32:35 +02:00
Vladimir Iakovlev
0949d2e770 Bump to 3.31 2021-06-09 21:50:44 +02:00
Vladimir Iakovlev
e343c577cd NA: Fix possible changes in files outside of working directory (#1206) 2021-06-08 22:04:51 +02:00
Stuart Leeks
6da0bc557f Add excluded_search_path_prefixes setting (#1165)
Improves performance in WSL

Fix #1036

* Add excluded_search_path_prefixes setting

Allows filtering the paths used to search for commands
Can be useful to filter out /mnt/ in WSL for performance

* Add test for excluded_search_path_prefixes

* Apply suggestions from code review

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2021-04-21 19:43:21 +02:00
Pablo Santiago Blum de Aguiar
1a595f1ba2 #N/A: Force decorator<5 for Python <= 2.7
For some reason, the index used by GH Actions is not considering the
requesting Python version to decide which package version to deliver.
This is unnecessary for the official index and will be removed once we
drop support to Python 2.
2021-04-18 15:48:39 +02:00
godofhyperdeath
875d3f11cb #N/A: Update license year to 2020-2021 (#1088)
Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2021-04-17 00:24:30 +02:00
Sid Shardanand
4c7479b3ad #N/A: Add cd_cs rule (#1167)
* adding in files for the cd-cs feature

* Updated thefuck/rules/cd_cs.py comments to be more verbose

Thanks Scorphus!

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>

* Updating the rules file to exclude the \xe2 character

This character(–) has lead to the commit failing some of the tests. 
I am removing it from the code and we should see the tests pass now.

* Setting the encoding in thefuck/rules/cd_cs.py

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>

Co-authored-by: SID SHARDANAND <sshardan@deakin.edu.au>
Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2021-03-22 20:55:45 +01:00
Divy Jain
5b612add74 #1154: Fix badges in README (#1175) 2021-03-13 14:24:53 +01:00
Pablo Santiago Blum de Aguiar
b9dd54c768 #1174: Fix anchor references 2021-03-13 12:50:09 +01:00
Bhavishya Pandit
7af9f41d93 #N/A: Add a Contents section to README (#1174)
* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2021-03-13 00:58:10 +01:00
Pablo Santiago Blum de Aguiar
c2cc95db88 #1117: Mock Popen in go_unknown_command test
Instead of ignoring it whenever `go` is unavailable
2021-02-22 22:54:45 +01:00
Georgios Kontosis
0e34c2343e #/N/A: Extend pyenv rule to include goenv, nodenv and rbenv (#1100)
Co-authored-by: Pablo Santiago Blum de Aguiar <scorphus@gmail.com>
Co-authored-by: Divy Jain <dkj@somaiya.edu>
2021-02-11 12:48:20 +01:00
Connor Martin
fd90e69ceb #N/A: Add conda rule (#1138)
* add conda rules

* revert

* add conda

* add to readme and flake

* consistency with quotes and use for_app

* Update thefuck/rules/conda_mistype.py

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2021-02-08 13:04:59 +01:00
Divy Jain
0c58317932 #N/A: Migrate CI pipeline to Github Actions (#1154)
Co-authored-by: Pablo Santiago Blum de Aguiar <scorphus@gmail.com>
2021-01-21 14:34:01 +01:00
Divy Jain
62dddd5821 #1149: Add python_module_error rule (#1151) 2021-01-19 22:37:05 +01:00
Divy Jain
40dd65963d #1141: Fix crash on empty history (#1145) 2020-11-18 10:43:11 +01:00
Kartik Soneji
836f6eeac5 Skip test instead of failing if go executable is not found. (#1117) 2020-11-03 18:30:03 +01:00
Kartik Soneji
b4c75eebe6 Fix pytest warnings (#1116)
* Add custom pytest mark.

* Fix typo usefixture -> usefixtures.
2020-11-03 18:29:28 +01:00
Pablo Aguiar
22efa8f70e #1113: Do not load excluded rules (#1125) 2020-11-03 18:27:09 +01:00
Pablo Aguiar
9d3bcad229 #1113: Ignore a rule that fails to load (#1124) 2020-11-03 18:26:13 +01:00
Divya Jain
c196e2901c #509: Fixed correction on windows machine running other shells (#1091)
* Replaced print with sys.stdout.write

* Fixed tests

* Normalized line endings
2020-07-16 23:56:58 +02:00
Aditi Gupta
ca46956e20 #1066 - Fix rule for brew cask (#1111)
* #1066: Add cask to list of fallback commands

* #1066: Fix homebrew paths
2020-07-16 23:34:41 +02:00
Nyanotech
639e9bda7a Add rule to remove a doubled-up "git clone" in a git clone command. (#1106)
Some git hosts will copy the entire clone command, while others just
copy the url, so typing "git clone ", then pasting a git url that
already has a "git clone " on the front is a somewhat common issue.
2020-07-16 23:34:22 +02:00
Divya Jain
39753a004e #1096: Rule: Bypass failed git hook (#1097)
* naive implementation

* better implementation

* remove redundant enabled_by_default

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>

* add README entry

* add tests

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2020-07-16 23:32:29 +02:00
Divya Jain
365db1ee41 #N/A: Refactor for better readability (#1094)
* #N/A: Refactor for better readability

* Change typename for test tuple

* Rename variable
2020-06-14 16:20:40 +02:00
Divya Jain
81b39defe4 #N/A: Fix formatting (#1092)
* Fixed corrector.py format string

* Fixed types.py format string

* Fixed tests/rules/test_fix_file.py formatting

* Removed trailing whitespace

* Fixed UnicodeEncodeError in python 2.7
2020-06-11 00:21:45 +02:00
Connor Martin
f82176802e add git-lfs support (#1056)
* add mistyping support for git lfs

* add the rule

* fix flake8

* flake8

* add to readme

* use fixtures and regex

* get rid of additional matched strings
2020-06-11 00:20:37 +02:00
Pablo Aguiar
6975d30818 #960: Improve pacman_invalid_option rule (#1072)
The rule now matches all possible lower case options and only those, not
failing for those that cannot be fixed.
2020-04-06 21:46:40 +02:00
DragonGhost7
3c542a5b8c Added pacman invalid option rule (#960)
* Added pacman invalid option rule

* Added test

* flake8 fixes

* Test changes

* Test fix

* Typo - again

* Travis test fix

* More Travis

* Even more travis

* I hope im right here

* Update README.md

Co-Authored-By: Pablo Aguiar <scorphus@gmail.com>

* Update thefuck/rules/pacman_invalid_option.py

Co-Authored-By: Pablo Aguiar <scorphus@gmail.com>

Co-authored-by: Pablo Aguiar <scorphus@gmail.com>
2020-03-28 23:15:20 +01:00
Vladimir Iakovlev
d3a05426de Bump to 3.30 2020-03-19 18:21:12 +01:00
Caplinja
88db57b4b1 #N/A: Add a new rule to create directory on cp or mv 2020-03-01 13:04:53 -06:00
Caplinja
444908ce1c #1047: Fix pip_unknown_command by using a less restrictive regex
Fix #1047
2020-03-01 10:40:49 -06:00
David Hart
2ced7a7f33 Allow multiple returns from git_checkout (#1022)
* Allow multiple returns from git_checkout

* Remove multiple returns
2020-01-13 23:28:20 +01:00
David Hart
b28ece0f34 Apt-get help is now much more like apt (#1031)
* Apt-get help is now much more like apt

* Fix tests

* Really fix the tests
2020-01-05 23:53:09 +01:00
Vladimir Iakovlev
eb60900330 #N/A: Unlink python 2 on travis-ci osx build (#1032) 2020-01-05 23:51:19 +01:00
donniebreve
ed8aaa7f26 fixed grammar on how to configure message (#1029) 2019-12-23 17:57:42 +01:00
Tim Gates
77992029b6 Fix simple typo: controle -> control (#1017) 2019-12-16 22:10:45 +01:00
Eli Schiff
25c858c13e removed useless redefined of path variable (#1023) 2019-12-16 21:56:12 +01:00
Vladimir Iakovlev
60073bea78 N/A: Remove deprecated python 3.4 support + fix tests in 2.7 (#1025)
* N/A: Remove deprecated python 3.4 support

More details - https://www.python.org/downloads/release/python-3410/

* N/A: Remove Python 3.4 from appveyor config

* N/A: Fix UnicodeDecodeError with Python 2.7 and newer versions of py.test
2019-12-16 21:55:19 +01:00
Philip Arola
d10fc80fa5 Add choco_install rule (#998)
* Add choco_install rule

Adds a rule to append '.install' to a chocolatey install command that
failed because of a non-existent package.

TODO: add support for other suffixes (.portable), find more parameter
cases

* Apply suggestions from code review

Circling back to retest

Co-Authored-By: Pablo Aguiar <scorphus@gmail.com>

* Fixed errors from suggested changes

* Added more test cases, refactored parsing

* Reformat keyword detection if statement

* Fixed flake errors

* Added tests for match
2019-11-07 01:10:00 +01:00
boonwj
fdea32b47d Fix typos in README.md (#997)
* Fix typos in README.md

* Fix another typo

- lifecycle to life cycle
2019-11-02 19:07:32 +01:00
Simon Chan
9381cfefa5 fix: incorrect powershell alias instruction (#1004)
* fix: incorrect powershell alias instruction

* fix: use dot operator to reload powershell profile
2019-11-02 19:06:17 +01:00
boonwj
793510ad48 Add rule to remove leading shell prompt literal $ (#996)
* Add rule to remove shell prompt literals $

Rule added to handle cases where the $ symbol is used in the command,
this usually happens when the command is copy pasted from a
documentation that includes the shell prompt symbol in the code blocks.

* Change files using black and flake8 style check

* Refactor tests and rule

- Refactor test for cleaner test tables
- Removed unnecessary requires_output=True option
2019-11-02 19:04:47 +01:00
Pablo Aguiar
d85099b8da #N/A: Inform the correct path to DEFAULT_RULES (#993) 2019-11-02 19:03:58 +01:00
Pablo Aguiar
ecee70f774 #N/A: Use Xenial on TravisCI (#989)
This simplifies and reduces the size of `.travis.yml`.
2019-11-02 19:03:35 +01:00
Shawn McGraw
70b414aca2 Issue#965 - added venv instructions to CONTRIBUTING.md (#976)
* Issue#965 - added venv instructions to CONTRIBUTING.md

* Added link to official docs for venv [issue965]
2019-10-23 00:30:55 +02:00
Pablo Aguiar
80cfd6991d #N/A: Add new git_branch_delete_checked_out rule (#985) 2019-10-23 00:30:17 +02:00
ik1ne
0ccb34bde8 Support for yum invalid commands. (#968)
* - Add skeleton code for yum_invalid_operation.py
- Add test for rule/yum_invalid_operation

* Add: mocker for subprocess.Popen.

* Fix: invalid yum_operations.

* Fix: Added missing fixtures.

* Add: yum_invalid_operation implementation.

* Add: enabled_by_default variable for rules/yum_invalid_operation.

* Update Readme.
2019-10-19 15:05:22 +02:00
ik1ne
581a292797 Add support for switch_lang for Korean. (#981)
* switch korean letters to english

* revised according to recent changes

* Fix typo in tests/test_switch_lang.py

* Add a test case for coverage

* Change: Moved decomposing logic which changes command.script to get_new_command instead of match.

* Fix: changed unicode characters to unicode string for python2 compatibility.

* Fix: Modified to change request.

@ik1ne @yangkyeongmo
2019-10-19 15:03:21 +02:00
Eugene Duboviy
7a9d87f502 Add Python 3.8 version support (#983)
* Update .travis.yml

* Update tox.ini
2019-10-19 15:00:52 +02:00
Eli Schiff
4f165bf6df removed extra whitespace (#967) 2019-10-08 23:47:04 +02:00
Fabian van Dijk
6789701e23 Add fuck --hard as alternative to fuck --yeah (#963)
* Add fuck --hard as alternative to fuck --yeah

* Fix missing comma in thefuck/argument_parser.py

Co-Authored-By: lomckee <cstutoringluke@gmail.com>

* Update README on fuck --hard
2019-10-08 23:44:22 +02:00
RetekBacsi
64dd018c1a Slow command timeout didn’t work (#961)
* Slow command timeout didn’t work

+ Fixed debug message to include is_slow
* Using only the first word of shlex.split when checking if command is slow.

* Fixed index error when command is empty
2019-10-08 23:43:19 +02:00
thatneat
3bbd0e9463 Correct "apt uninstall" -> "apt remove" (#950)
* Correct "apt uninstall" -> "apt remove"

* remove unused import
2019-09-17 20:02:45 +02:00
Shaoyuan CHEN
c53676e42f change sudo.py pattern to lowercase (#947) 2019-09-02 19:17:48 +02:00
ik1ne
84c16fb69a Change: rules_git_checkout handling branch names with slashes & Remote HEAD. (#944)
* Add: Test for branch names with slashes & Remote HEAD.

* - Add: Handling for removing remote HEAD.
- Change: Improved handling for branches with slash in their names.
2019-09-02 19:16:40 +02:00
ik1ne
1683f45e94 Update docker commands. (#940)
* Add: Tests for newer version docker support.

* Add: Support for newer versions of docker (Modified rules.docker_not_command).

* Fix: Updated disabling memoize.

* Change: removed empty list check.

* Fix: _parse_commands now uses line.strip() internally and ends_with arg now doesn't end with newline.

* Change: Replaced disable_memoize in favor of no_memoize fixture.

* Fix: removed unused import.
2019-08-21 20:35:55 +02:00
ik1ne
d88454a638 Add: rules/go_unknown_command for misspelled go commands. (#933)
* - Add: rules/go_unknown_command for misspelled go commands.
- Add: tests/test_go_unknown_command which tests match and mismatch case of rules/go_unknown_command.
- Change: Added description of go_unknown_command to README.md.

* Add: test_get_new_command for testing rules.go_unknown_command.test_get_new_command method.

* Change: go_unknown_command.match now uses for_app decorator.

* Add: get_golang_commands which dynamically gets golang possible commands.

* Fix: cache proper function instead of its result.
2019-08-21 20:34:34 +02:00
Samuel Marks
8ef9634492 [.editorconfig] Init (#938) 2019-08-19 21:47:15 +02:00
ik1ne
335ae40675 Fix: rules.git_checkout not working with git 2.22.0 (#934)
* Change: remove period from git checkout error output.

* Change: remove period from git checkout get_new_command.
2019-08-19 21:45:55 +02:00
tobixx
3bbe391391 Only consider raw command in output (#931)
* Only consider raw command in output match

... else it will not work for localized messages.

Example German output:
```
Führen Sie »apt list --upgradable« aus, um sie anzuzeigen.
```

* added german output test

* make the linter happy
2019-08-19 21:39:14 +02:00
Connor Martin
01a5ba99d0 Docker remove container before remove image (#928)
* add docker container removal

* remove container before deleting image

* update readme

* clean up and add assert not test

* test not docker command

* use shell.and_ correctly
2019-07-10 20:34:20 +02:00
Mathieu Cantin
4c3a559124 Added rules to run terraform init before terraform plan or apply (#924)
* Run terraform init to initialize terraform modules

* Fix indent

* Add unit tests for terraform_init.py
2019-06-26 20:02:01 +02:00
Pablo Aguiar
e047c1eb40 #921: Try printing alias before trying to fix a command (#923)
Fixes #921
2019-06-26 20:01:38 +02:00
Tycho Grouwstra
48e1e4217f support nixos command-not-found, closes #912 (#922) 2019-06-26 20:01:02 +02:00
Vladimir Iakovlev
59dc6cbf90 #N/A: Fix the release script 2019-05-27 18:32:48 +02:00
Vladimir Iakovlev
59e1f7b122 Bump to 3.29 2019-05-27 18:29:04 +02:00
Pablo Aguiar
ff2944086d #N/A: Improve how version is fetched for all shells (#920) 2019-05-27 18:24:55 +02:00
Pablo Aguiar
ba949f7fd9 #N/A: Add pyenv_no_such_command rule (#919) 2019-05-27 18:23:45 +02:00
Pablo Aguiar
5efcf1019f #N/A: Improve support to Windows in no_command rule (#918)
Windows “not found” message is quite different from POSIX systems.
2019-05-27 18:23:06 +02:00
Ryan Delaney
70a13406f0 Fix a couple small shellcheck errors (#915)
* Fix shellcheck SC2046

Further reading: https://github.com/koalaman/shellcheck/wiki/Sc2046

* Fix shellcheck 2068

Further reading: https://github.com/koalaman/shellcheck/wiki/Sc2068

* Fix syntax error from bad quoting

I also used a docstring here because the escaping makes it harder for
humans to parse
2019-05-22 20:22:09 +02:00
Jesus Cuesta
201c01fc74 Adding yay AUR manager to Arch Linux's commands since yaourt is unmaintained and has some security issues. (#907) 2019-05-21 20:49:04 +02:00
Pablo Aguiar
78ef9eec88 #902: Use os.pathsep to split PATH env var (#917)
Fix #902
2019-05-21 20:47:47 +02:00
Pablo Aguiar
40ab4eb62d #899: Support -y/--yeah command line args in Fish Shell (#900) 2019-04-24 18:17:52 +02:00
Nick "darkfiberiru" Wolff
55cb3546df Pkg should be recommend on freebsd to install (#905) 2019-04-24 18:17:01 +02:00
Inga Feick
82902fb50d Add rule for pip_install permission fix (#895)
* Add rule for pip_install permission fix

* Fix whitespace

* Switch quotation to single

* remove 2nd else

* E261 indent comment
2019-04-24 18:15:38 +02:00
Inga Feick
828ae537da Docker login (#894)
* Add docker_login rule

* Add docker_login rule

* Whitespace fix

* Fix typo in test case

* Fix typo in test case

* Add test cases
2019-04-04 00:01:14 +02:00
Aiden Song
1208faaabb #N/A: Add rule for git commit that reverts previous commit (#886) 2019-02-25 23:24:16 +01:00
Pablo Santiago Blum de Aguiar
2d81166213 #N/A: Return an ordered list from set of overridden aliases
This way it's ensured that whatever is used as cache key is always
ordered. Sets are unordered collections.
2019-01-17 00:29:22 +01:00
Vladimir Iakovlev
8093f7cab8 Squashed commit of the following:
commit b853385ea9b9409a29a30c7af4d47c9a500cd287
Author: Vladimir Iakovlev <nvbn.rm@gmail.com>
Date:   Tue Jan 15 00:54:01 2019 +0100

    #864: Make the solution for Greek a bit more extensible

commit 073ebceb594ad24972f7765b1f608de44c1cebf2
Merge: b946b7d 141462a
Author: Vladimir Iakovlev <nvbn.rm@gmail.com>
Date:   Tue Jan 15 00:46:09 2019 +0100

    Merge branch 'master' of git://github.com/RealOgre/thefuck into RealOgre-master

commit 141462a6fb
Author: RealOrge <45096491+RealOrge@users.noreply.github.com>
Date:   Thu Dec 13 16:47:43 2018 +0200

    Update switch_lang.py

commit 1f792853f2
Author: RealOrge <45096491+RealOrge@users.noreply.github.com>
Date:   Thu Dec 13 16:39:04 2018 +0200

    Update switch_lang.py

commit e7dede53a1
Author: RealOrge <45096491+RealOrge@users.noreply.github.com>
Date:   Thu Dec 13 15:24:10 2018 +0200

    Update switch_lang.py

commit 4a0a973e62
Author: RealOrge <45096491+RealOrge@users.noreply.github.com>
Date:   Thu Dec 13 15:04:44 2018 +0200

    Update switch_lang.py

commit 80d6b8da4c
Author: RealOrge <45096491+RealOrge@users.noreply.github.com>
Date:   Thu Dec 13 14:25:15 2018 +0200

    Update switch_lang.py

commit 66b13c53b3
Author: RealOrge <45096491+RealOrge@users.noreply.github.com>
Date:   Thu Dec 13 11:44:48 2018 +0200

    Update switch_lang.py
2019-01-15 00:54:48 +01:00
yangkyeongmo
b946b7d319 Comment correction on ui.py (#874) 2019-01-15 00:36:05 +01:00
Vladimir Iakovlev
9354a977dd #N/A: Fix tests with pytest 4 2019-01-15 00:35:28 +01:00
Mickaël Schoentgen
1eb4ccbcc9 Fix 2 DeprecationWarning: invlid escape sequence (#872)
Signed-off-by: Mickaël Schoentgen <contact@tiger-222.fr>
2019-01-06 15:44:09 +01:00
Pablo Santiago Blum de Aguiar
ce5feaebf7 #869: Use fish --version instead of an interactive shell for info()
This prevents initialisation and consequentially a recursive loop.

Fix #869
Ref oh-my-fish/plugin-thefuck#11
2019-01-04 20:54:03 +01:00
Fábio Santos
ac343fb1bd #868: Point out you can use linuxbrew in README
* Point out you can use linuxbrew

* Change text and add link to linuxbrew

* Change brew related URLs to HTTPS
2019-01-04 20:35:27 +01:00
Chris De Pasquale
7bc619385b Fixed incorrect ordering of for_app and sudo_support causing apt_invalid_operation and dnf_no_such_command rules to fail (#861) 2018-12-11 01:01:17 +01:00
Vladimir Iakovlev
d86dd5f179 #N/A: Clear dist/ before uploading releases 2018-11-29 23:57:07 +01:00
Vladimir Iakovlev
8c1591fbe3 Bump to 3.28 2018-11-29 23:43:39 +01:00
kozar
dfd31872a9 #855 - Support Ukrainian layout; Fix matching of similar layouts (#856)
*  #855 - Support Ukrainian layout; Fix matching of similar layouts

* Fix splitting of command line
2018-11-21 19:56:49 +01:00
Vladimir Iakovlev
1eaead4f70 #N/A: Remove performance tests as they are meaningless with the current implementation 2018-11-21 19:44:07 +01:00
Vladimir Iakovlev
5b3350b2dd #N/A: Fix tests with py.test 4 2018-11-21 19:43:01 +01:00
Vladimir Iakovlev
81b05b9f88 #N/A: Fix osx travis-ci build 2018-11-21 19:31:59 +01:00
Simon Eisenmann
b5436a2c47 Remove zsh instant mode log with -f (#854)
In some setups, rm might default to interactive promt. This change adds
the -f parameter to force remove the instant mode log on exit to avoid
an interactive prompt.

```
 ~ 
rm: remove regular file
'/tmp/user/1000/thefuck-script-log-bbb81260140c4b3fa18bf2097f15bd77'?
```
2018-11-02 20:00:56 +01:00
Přemek Vyhnal
b08aec02f5 update install guide for Linux Mint (#852)
on Mint I had to install python3-setuptools package too
2018-10-30 21:49:42 +01:00
Pablo Aguiar
e6be00a63b Comply to new flake8 3.6 (#853)
* #N/A: Ignore W504 line break after binary operator

W504 is now part of flake8 current version 3.6

* #N/A: Fix invalid escape sequences

* #N/A: Remove conflicting path before installing gcc with brew
2018-10-30 20:56:55 +01:00
Vladimir Iakovlev
d226b8f258 #835: Make cache failure non-fatal 2018-10-18 00:35:18 +02:00
Vladimir Iakovlev
f06ebbf2ae #N/A: Use twine for uploading new releases 2018-10-16 21:08:08 +02:00
Nallagatla Manikanta
3e522ba787 Add the pwsh support for thefuck (#844) 2018-10-09 23:20:48 +02:00
Pablo Aguiar
25142f81f8 Some improvements (#846)
* #833: do not require sudo on TravisCI

* #N/A: Add Python dev releases to TravisCI pipeline

Inspired by Brett Cannon's advise [1].

    1: https://snarky.ca/how-to-use-your-project-travis-to-help-test-python-itself/

* #837: try and kill proc and its children

* #N/A: show shell information on `thefuck --version`

* #N/A: omit default arguments to get_close_matches

* #842: add settings var to control number of close matches

* #N/A: remove `n` from the list of `get_closest`'s args
2018-10-08 22:32:30 +02:00
Rafał Zawadzki
5fd4f74701 Added back-ticks for the consistency (#845) 2018-10-08 22:20:17 +02:00
Waldir Pimenta
a0286b402a ISSUE_TEMPLATE.md: sync format of fill-in fields (#841)
Some of the "FILL THIS IN" were wrapped with html comment markup, but most of them weren't. This change makes them all use the same format.
2018-10-02 20:46:58 +02:00
Mateusz Mikuła
bb41f5c4e5 Add snapcraft.yaml (#836) 2018-10-02 20:46:13 +02:00
James Turnbull
926e9ef963 Added a rule to match az binary sub-command misses (#834) 2018-08-16 00:22:24 +02:00
Eugene Duboviy
9d46291944 Add Python 3.7 version support (#833) 2018-08-14 00:22:53 +02:00
Pablo Aguiar
cc6d90963e #367: Support BSD style output in touch rule (#830)
On a Mac, also on NetBSD or OpenBSD, `touch` errs differently:

```
$ uname; touch a/b/c
Darwin
touch: a/b/c: No such file or directory
```

That gets matched by the rule but not fixed by it. Thus the regex
pattern is now a bit more tolerant.
2018-07-29 18:18:42 +02:00
Vladimir Iakovlev
4e755e4799 #827: Make cat_dir rule safer 2018-07-11 23:57:41 +02:00
Scott Colby
1dfd6373ee Stop parsing language-variable cat output to make cat_dir more reliable. (#827)
* Stop parsing language-variable cat output to make cat_dir more reliable.

* Add missing semicolon in readme
2018-07-11 23:47:06 +02:00
Scott Colby
fe0785bc42 Create cat_dir rule for replacing cat with ls (#823)
* Create `cat_dir` rule for replacing `cat` with `ls` when you try to run `cat` on a directory.

* Changed to string methods in response to feedback.

Added a test to make sure lines like 'cat cat' don't become 'ls ls'.

Added trailing '\n's to test cases.
2018-07-10 00:51:42 +02:00
Glen Yu
142ef6e66c added --yeah as an alterative arg to -y and --yes; updated README.md (#822) 2018-07-10 00:50:11 +02:00
Mas0s
59745942b5 added notice to README.md (#821)
zsh's autocorrect function interferes with thefuck, that is now mentioned in README
2018-07-10 00:49:20 +02:00
Chris Mendis
692ee53a33 Avoid masking shell return values in Zsh.app_alias (#820)
I discovered that a common shell script issue (https://github.com/koalaman/shellcheck/wiki/SC2155) is present in the script returned by `Zsh.app_alias()`, amongst other `app_alias` methods in thefuck.

In the case of the zsh `app_alias()` script, this common issue is causing the script to error on some versions of Mac OS X. This is  reported in #718.

Unmasking the value of `TF_SHELL_ALIASES` fixes the errors in Mac OS X, but I also unmasked `TF_HISTORY` for consistency.
2018-07-10 00:48:56 +02:00
Matthieu Guilbert
534782414f git_push: Handle command containing force argument (#818) 2018-07-10 00:48:08 +02:00
Matt Kotsenas
a6bb41e802 Fix Win32 get_key (#819)
PR #711 moved the arrow and cancel key codes to `const.py`. However, the
move also changed the codes from byte arrays to strings, which broke the
use of `msvcrt.getch()` for Windows.

The fix is to use `msvcrt.getwch()` so the key is a Unicode character,
matching the Unix implementation.
2018-07-10 00:46:57 +02:00
Vladimir Iakovlev
86efc6a252 Bump to 3.27 2018-05-22 19:26:55 +02:00
Iulian Onofrei
89207d6d7c Add brew_reinstall rule (#816)
Replaces install with reinstall when a package is already installed.
2018-05-22 19:25:05 +02:00
afwilkin
f6e50bef82 fixed powershell coloring (#805) 2018-05-22 19:03:52 +02:00
Vladimir Iakovlev
81042514c8 Squashed commit of the following:
commit 6919161e77a39b9bd59ca54eac44b956cd3ae1dc
Author: Vladimir Iakovlev <nvbn.rm@gmail.com>
Date:   Tue May 22 19:01:33 2018 +0200

    #810: Fix code style

commit ebbb31a3227ce32ba5288e96c0c16a3d334c45d6
Merge: 2df1a5a a2799ad
Author: Vladimir Iakovlev <nvbn.rm@gmail.com>
Date:   Tue May 22 18:59:56 2018 +0200

    Merge branch 'feature/long-form-help' of https://github.com/jakewarren/thefuck into jakewarren-feature/long-form-help

commit a2799ad098
Author: Jake Warren <jakewarren@users.noreply.github.com>
Date:   Mon May 7 14:12:57 2018 -0500

    Add new `long_form_help` rule
2018-05-22 19:01:51 +02:00
Vladimir Iakovlev
2df1a5a45b #N/A: Fix formatting 2018-05-14 22:44:10 +02:00
Vladimir Iakovlev
72e88d6ba3 #N/A: Add basic shell logger support 2018-05-14 22:16:33 +02:00
Pablo Aguiar
8db3cf6048 Support aliases with equal sign (#808)
* #N/A: Remove `pip` from requirements.txt

* #807: Expect aliases declared with equal sign too

This fixes #807
2018-05-13 15:29:33 +02:00
Iulian Onofrei
68949a5922 Fix spelling (#814) 2018-05-13 15:28:39 +02:00
Pablo Aguiar
216d82b464 #N/A: Remove pip from requirements.txt (#813) 2018-05-13 15:28:00 +02:00
Evan Pratten
97f2d743b3 Update README.md 2018-05-11 11:36:24 +02:00
Vladimir Iakovlev
d5cc7ec43b Bump to 3.26 2018-04-25 18:19:14 +02:00
Adam B
33a87502cd Update README.md for clarity and concision (#794)
Reworded several sentences and paragraphs for clarity and concision. All original information was maintained.
2018-04-01 16:25:09 -04:00
Vladimir Iakovlev
82a12dda81 #N/A: Test only with python3 in ci on osx
Default python version in homebrew is changed to 3.6, more details - https://brew.sh/2018/01/19/homebrew-1.5.0/
2018-03-19 23:26:35 +01:00
Vladimir Iakovlev
4c9099a79b #N/A: Fix mmap log cleanup 2018-03-19 22:41:38 +01:00
Vladimir Iakovlev
1508ecfeae #N/A: Use mmap for sharing output in instant mode 2018-03-14 00:12:40 +01:00
Vladimir Iakovlev
284d49da8d #786: Fix tests 2018-02-23 21:15:05 +01:00
Vladimir Iakovlev
fb39d0bbd3 #786: Fix apt_get rule on ubuntu 18.04 2018-02-23 21:08:41 +01:00
Vladimir Iakovlev
ed24e4ca61 Squashed commit of the following:
commit 8573f94c2f3ba17ec5d7dd123338c14a550e57e6
Author: Vladimir Iakovlev <nvbn.rm@gmail.com>
Date:   Fri Feb 23 20:45:01 2018 +0100

    #785: Remove functional test

commit 5484576d6e3ef4a53d69860ef953bb48037e8a72
Merge: a36a8b4 f59aa93
Author: Vladimir Iakovlev <nvbn.rm@gmail.com>
Date:   Fri Feb 23 20:44:20 2018 +0100

    Merge branch 'master' of https://github.com/alexbarcelo/thefuck into alexbarcelo-master

commit f59aa931c3
Author: Alex Barcelo <alex.barcelo@gmail.com>
Date:   Fri Feb 16 23:43:43 2018 +0100

    rewritten match + fish output check for cd_* rules

commit 150ecee00f
Author: Alex Barcelo <alex.barcelo@gmail.com>
Date:   Fri Feb 16 23:43:19 2018 +0100

    Adding unittest for cd_correction (with extra fish test case, also for cd_mkdir)

commit e73dd3f6d1
Author: Alex Barcelo <alex.barcelo@gmail.com>
Date:   Fri Feb 16 22:48:22 2018 +0100

    adding functional test for cd_correction rule

commit d1dbbb57d9
Author: Alex Barcelo <alex@betarho.net>
Date:   Fri Feb 16 12:21:33 2018 +0100

    Include root (start with /) case
2018-02-23 20:45:36 +01:00
Vladimir Iakovlev
a36a8b4de1 Merge branch 'master' of github.com:nvbn/thefuck 2018-02-23 20:44:08 +01:00
Vladimir Iakovlev
2678adf981 #788: Use uniq last tracker path for different users 2018-02-23 20:42:00 +01:00
JunYoung Gwak
dd9554539f Added a rule to delete sudo for pacaur. (#787) 2018-02-22 22:14:02 +01:00
Omer Katz
b65e3a9aad Added hebrew the list of keyboard layouts (#778)
* Added hebrew the list of keyboard layouts.

Fixes #776.

* Added tests for hebrew layout.

* Fix test.

* Make lint happy.
2018-01-29 08:46:18 +01:00
Joseph Frazier
027b41da59 Add git_merge_unrelated rule for git merge --allow-unrelated-histories (#773)
From https://git-scm.com/docs/merge-options#merge-options---allow-unrelated-histories

> By default, `git merge` command refuses to merge histories that do not
share a common ancestor. This option can be used to override this safety
when merging histories of two projects that started their lives
independently.
2018-01-16 20:03:56 -05:00
Guangyuan (Charlie) Yang
aa45585601 Add installation instructions on FreeBSD (#770)
misc/thefuck has recently been committed to the FreeBSD ports tree (https://svnweb.freebsd.org/ports?view=revision&revision=458123).
2018-01-10 21:31:38 +01:00
David Hart
c205683a8d git_push: Handle branch names containing 'set-upstream' (#759)
This should fix https://github.com/nvbn/thefuck/issues/723 (IndexError when using bitbucket)
2018-01-06 17:44:03 -05:00
David Hart
7c858fadb3 #762: handle single quotes in git_branch_exists
* handle single quotes in git_branch_exists

* Fix line length

* Fix missing quotes from test
2018-01-05 19:25:08 -02:00
David Hart
797ca1c564 Offer git commit --amend after previous git commit (#764) 2018-01-05 16:24:43 -05:00
David Hart
7b10a86267 Add rule for ADB unknown commands (#765) 2018-01-05 16:20:03 -05:00
David Hart
b62bb90a0d git_push: Escape single quote in branch names (#760)
Parameterize test output fixture.

Check for 'push' in command.script_parts than anywhere in command.script.
2018-01-04 11:40:01 -05:00
Joseph Frazier
a696461cd3 Add apt_upgrade rule (#761)
* apt_list_upgradable: Prepend sudo to suggestion if used in command

* Add apt_upgrade rule

This suggests `apt upgrade` after `apt list --upgradable` if there are
packages to upgrade. It pairs well with the `apt_list_upgradable` rule,
which suggests `apt list --upgradable` after `apt update` if there are
packages to upgrade.

* Add apt_upgrade rule to README
2018-01-03 19:01:09 +01:00
Joseph Frazier
7e6d1dbc7c Move Developing instructions from README to CONTRIBUTING (#757)
* Move Developing instructions from README to CONTRIBUTING

This makes them easier to find, especially for users opening issues or
pull requests. See here for more details:
https://help.github.com/articles/setting-guidelines-for-repository-contributors/

* fixup! Move Developing instructions from README to CONTRIBUTING
2018-01-03 19:00:20 +01:00
Joseph Frazier
4fb85b0a92 Add GitHub Issue template (#749)
This prompts the user to include relevant information when reporting
issues. I adapted it from the corresponding section of CONTRIBUTING.md

See here for details: https://github.com/blog/2111-issue-and-pull-request-templates
2018-01-03 18:59:38 +01:00
David Hart
83e1710712 Fix fish shell aliasing (#753)
* Handle user defined fish aliases

* Add more aliases to test

* Revert unecessary Popen mock changes

* Add test for fish aliasing

Fixes #727
2018-01-02 23:14:02 -05:00
Pablo Santiago Blum de Aguiar
045c8ae76c #738: Assert TF_SHELL is defined in bash and zsh aliases 2018-01-02 17:18:34 -02:00
Pablo Santiago Blum de Aguiar
bcb749722b #738: Set SHELL env var for fish and tcsh 2018-01-02 17:18:34 -02:00
David Hart
f700b23f57 Add git merge rule (#755)
This fixes https://github.com/nvbn/thefuck/issues/629
2018-01-02 11:47:48 -05:00
Joseph Frazier
897572d278 README: Use pip3 in upgrade command (#756)
Fixes https://github.com/nvbn/thefuck/issues/615
2018-01-02 10:14:11 -05:00
Joseph Frazier
0640509895 Drop Python 3.3 Support (#747)
* Drop Python 3.3 Support

It's reached end-of-life, and our dependencies have started to drop it.
See https://github.com/nvbn/thefuck/pull/744#issuecomment-353244371

* Revert "Use pytest<3.3 to fix Python 3.3 tests (#746)"

This reverts commit f966ecd4f5.
2018-01-01 20:18:05 -05:00
David Hart
57fb6e079a git_push: Make option handling more robust (#751)
See https://github.com/nvbn/thefuck/issues/740#issuecomment-354466567
2018-01-01 19:45:46 -05:00
David Hart
83cf97dc26 Suggest git checkout -b (#754)
This fixes https://github.com/nvbn/thefuck/issues/632

This uses `script_parts` instead of `script.startswith`
to let it work even if there's extra spaces in the command, e.g.

    git  checkout unknown
2018-01-01 18:30:33 -05:00
Miguel Piedrafita
9e788196e6 Update license year to 2015-2018 (#752) 2018-01-01 12:53:34 -05:00
Joseph Frazier
4ea02a3153 git_push: Don't add duplicate remote/branch name (#745)
This fixes https://github.com/nvbn/thefuck/issues/740
2017-12-27 07:54:52 -05:00
Joseph Frazier
f966ecd4f5 Use pytest<3.3 to fix Python 3.3 tests (#746)
See https://github.com/nvbn/thefuck/pull/744 for context.

I'm personally okay with dropping Python 3.3 support,
but I'd like to at least get the tests working while we decide on that.
2017-12-20 20:43:01 -05:00
Vladimir Iakovlev
629056077f #783: Don't rely on $SHELL for detecting shell 2017-11-27 21:08:46 +01:00
Vladimir Iakovlev
4780027d63 Bump to 3.25 2017-11-23 20:51:04 +01:00
Vladimir Iakovlev
4847078f37 #737: Add support of third-party rules 2017-11-23 20:21:44 +01:00
Joseph Frazier
d582159670 Add apt_list_upgradable rule (#732)
This helps you run `apt list --upgradable` after `apt update`,
as it suggests.
2017-11-16 20:19:44 +01:00
Jarrod Moore
97123dbf73 Fix zsh alias (#733) 2017-11-16 20:19:16 +01:00
Joseph Frazier
10ac1a3b38 #728: Add heroku_multiple_apps rule (#729)
Closes https://github.com/nvbn/thefuck/issues/728
2017-11-09 18:42:23 -05:00
Joseph Frazier
8fb5ddefb6 git_flag_after_filename: Handle new error message
See 2a5aa826ee
2017-11-01 09:42:52 -04:00
Joseph Frazier
f1fab0dbb2 git_flag_after_filename: Call match() instead of copying its body 2017-11-01 09:42:52 -04:00
Vladimir Iakovlev
68df7154e5 #N/A: FIx new flake8 warnings 2017-10-25 19:31:03 +02:00
Vladimir Iakovlev
08082e606b #715: Fix work on Windows 2017-10-25 19:16:28 +02:00
Vladimir Iakovlev
b2789ad899 Bump to 3.24 2017-10-16 20:11:01 +02:00
Vladimir Iakovlev
72f0df2f90 #711: Handle ctrl+n and ctrl+p 2017-10-16 19:19:29 +02:00
Vladimir Iakovlev
50d14be43a Merge branch 'scorphus-pull-request-702' 2017-10-16 19:09:53 +02:00
Vladimir Iakovlev
054fd0b166 #702: Make match in php_s rule more strict 2017-10-16 19:09:44 +02:00
Pablo Santiago Blum de Aguiar
75d2c43997 #702: fix minor issues with php_s rule
Unfortunately, I didn't catch these issues while reviewing #702.

After looking more closely at `php` options, `-S` requires additional
arguments (<address>:<port>) and `-s` may produce output if used that
way. So, matching ` -s ` seems to be better.

Also, `@for_app('php')` already asserts the presence of `php ` in the
command script. Matching `php -s` prevents the rule from fixing commands
like `php -t public -s 0.0.0.0:8080`.
2017-10-15 17:18:21 -02:00
Stef Pletinck
64d6835e15 #652: Add new git_push_different_branch_names rule
Fix #652

* Basic fix for #652
* Finishing work
* Added readme line
* Added test
* My test was stupid...
* Removed redundant lines
* That space...
2017-10-15 13:30:29 -02:00
Vladimir Iakovlev
2233e3679c Merge branch 'matthewfallshaw-patch-1' 2017-10-15 16:39:49 +02:00
Vladimir Iakovlev
bab5de236f #710: Fix tests 2017-10-15 16:39:40 +02:00
Vladimir Iakovlev
8a4f37edb3 Merge branch 'patch-1' of https://github.com/matthewfallshaw/thefuck into matthewfallshaw-patch-1 2017-10-15 16:32:57 +02:00
Vladimir Iakovlev
a566e040f7 #N/A: Fix deprecation warnings 2017-10-15 16:16:43 +02:00
Vladimir Iakovlev
10a4e910e9 #N/A: Fix deprecation warnings 2017-10-15 16:13:36 +02:00
Vladimir Iakovlev
985b2d9ec9 #N/A: Add brew_cask_dependency rule 2017-10-15 16:11:08 +02:00
Vladimir Iakovlev
a906a751c8 #N/A: Add prove_recursively rule 2017-10-15 15:51:09 +02:00
Matthew Fallshaw
d11ca52ec9 Bugfix: brew_update_formula.py
Sample command output is:

    Error: This command updates brew itself, and does not take formula names.
    Use 'brew upgrade thefuck' instead.

This will never match the previous `"Use 'brew upgrade <formula>'" in command.output` test.
2017-10-12 13:43:28 -07:00
Stef Pletinck
e658f35bd9 quick fix for #655 (#702)
* quick fix for #655

* Enabled by default and fix

* Test

* Added readme line

* This is unnecessary
2017-10-10 19:24:38 +02:00
Vladimir Iakovlev
21a916d953 #708: Fix handling of shelve errors 2017-10-10 19:19:54 +02:00
Vladimir Iakovlev
d228091beb #707: Don't use @cache on methods 2017-10-10 19:15:36 +02:00
Vladimir Iakovlev
5d14d65837 #707: Use pickle for cache keys 2017-10-10 19:14:42 +02:00
Vladimir Iakovlev
1f8f3dd967 #707: Update tests 2017-10-10 08:31:45 +02:00
Vladimir Iakovlev
d9fd5e8a6b #707: Reimplement cache 2017-10-10 08:30:26 +02:00
Vladimir Iakovlev
7a04a1f4c5 Merge branch 'master' of github.com:nvbn/thefuck 2017-10-09 19:06:53 +02:00
Vladimir Iakovlev
c2de69bbfd #682: Fix zsh PS1 width in experimental instant mode 2017-10-09 19:03:18 +02:00
Vladimir Iakovlev
b1730ed8e1 Merge pull request #706 from scorphus/pull-request-701
Fix minor issues with git_remote_delete
2017-10-09 18:47:13 +02:00
Pablo Santiago Blum de Aguiar
af1a88b271 #701: Do not require git in the script
@git_support already does that
2017-10-08 21:15:28 -03:00
Pablo Santiago Blum de Aguiar
dfd0be2002 #701: Replace the first single occurrence of delete 2017-10-08 18:55:44 -03:00
Vladimir Iakovlev
3253b0e789 #682: Fix functional tests for experimental instant mode 2017-10-08 17:16:15 +02:00
Vladimir Iakovlev
1ab0e80f8f #682: Fix PS1 on macos with zsh 2017-10-08 16:39:13 +02:00
Vladimir Iakovlev
78a9d52df0 #N/A: Remove enabled_by_default = True from rules 2017-10-08 16:27:23 +02:00
Vladimir Iakovlev
6362c37eec Merge pull request #701 from Epse/#670-git_remote_delete
fixed #670
2017-10-08 16:25:59 +02:00
Vladimir Iakovlev
f333dfe657 Merge pull request #698 from Epse/dnf-module
Basic DNF support
2017-10-08 16:19:51 +02:00
Vladimir Iakovlev
ad294bc4d4 Merge pull request #704 from z3ntu/issue/658
#658: Change configuration code for fish shell
2017-10-08 16:18:58 +02:00
Vladimir Iakovlev
d2c70bd8b8 #682: Use our own shell logger, fix experimental instant mode on macos 2017-10-08 16:17:41 +02:00
Stef Pletinck
f24110de56 added readme line 2017-10-07 14:01:26 +02:00
Stef Pletinck
b6ecaf4d86 Enabled by default 2017-10-07 13:59:51 +02:00
Stef Pletinck
f372f3d56c Added test 2017-10-07 13:59:32 +02:00
Stef Pletinck
be48f02784 Tests! Also fixed some bytes-string issues 2017-10-07 12:59:21 +02:00
Stef Pletinck
449cb9a006 Added README line 2017-10-06 17:13:29 +02:00
Vladimir Iakovlev
edac010a7b Merge pull request #705 from scorphus/fix-appveyor-build
#N/A: Use curl to download get-pip.py on AppVeyor
2017-10-06 07:55:55 +02:00
Pablo Santiago Blum de Aguiar
c2c98d5f69 #N/A: Use curl to download get-pip.py on AppVeyor
`curl` seems to be smarter than `net.webclient` when dealing with SSL.
2017-10-06 01:16:15 -03:00
Luca Weiss
4f3ab71934 #658: Change configuration code for fish shell 2017-10-05 20:57:08 +02:00
Stef Pletinck
89bc2e9759 fixed #670 2017-10-05 18:44:04 +02:00
Stef Pletinck
f465fb3ed8 Slightly more comments 2017-10-05 16:50:44 +02:00
Stef Pletinck
d6b2c512f7 DNF module only enabled when DNF available and dynamically loads corrections 2017-10-05 16:40:17 +02:00
Stef Pletinck
16de31b9d6 basic dnf module 2017-10-05 10:36:51 +02:00
Vladimir Iakovlev
18992f246a #695: Try to use link with name 2017-09-27 18:21:07 +02:00
Vladimir Iakovlev
cec919374e #695: Fix link to manual-installation 2017-09-27 18:15:44 +02:00
Vladimir Iakovlev
bc7eaff5d1 #695: Fix link to manual-installation 2017-09-27 18:14:29 +02:00
Vladimir Iakovlev
8fb5ba3931 Merge pull request #696 from MattKotsenas/bugfix/params
Support parameters in PowerShell
2017-09-27 19:09:46 +03:00
Vladimir Iakovlev
e94f420cb1 Merge pull request #693 from sQu1rr/master
fixes #692 : multiline PS1 breaking instant mode
2017-09-27 19:09:20 +03:00
Matt Kotsenas
e6496ce8bb Support parameters in PowerShell
Update the PowerShell alias so it passes thefuck parameters (e.g. `-y` or `-r`).
2017-09-26 15:57:13 -07:00
sQu1rr
d34b3ada71 fixes #692 : multiline PS1 breaking instant mode 2017-09-17 16:16:48 +01:00
Vladimir Iakovlev
20779731d3 #N/A: Store not configured usage tracker in tempdir 2017-09-12 08:09:00 +02:00
Vladimir Iakovlev
ec5b69ca63 Merge branch 'reitermarkus-patch-1' 2017-09-10 07:56:45 +02:00
Vladimir Iakovlev
8fbd7c13e4 Merge branch 'patch-1' of https://github.com/reitermarkus/thefuck into reitermarkus-patch-1
# Conflicts:
#	tests/rules/test_brew_upgrade.py
2017-09-10 07:56:33 +02:00
Vladimir Iakovlev
22aa9b701d #682: Measure time spent on log reading 2017-09-09 06:07:08 +02:00
Vladimir Iakovlev
4875d75a64 #682: Ensure that script exists 2017-09-03 10:10:50 +02:00
Vladimir Iakovlev
1cae91b649 #N/A: Get shell from env if possible 2017-09-03 06:51:44 +02:00
Vladimir Iakovlev
50dd4b8f54 #682: Use system temporary directory 2017-09-02 17:35:08 +02:00
Vladimir Iakovlev
84f6d2631e #682: Fix appearance of PS1 in bash 2017-09-02 11:06:40 +02:00
Vladimir Iakovlev
e33960b193 #685: Mention only Python 3 in requirements 2017-09-02 11:02:49 +02:00
Vladimir Iakovlev
ff442a2eb0 #682: Remove script log on exit 2017-09-02 10:44:16 +02:00
Vladimir Iakovlev
17b7bf8ec2 #682: Parse only the last MB of log 2017-09-02 10:39:22 +02:00
Vladimir Iakovlev
bf0867967b #N/A: Cache docker, gem, grunt and yarn output in rules 2017-09-02 10:22:00 +02:00
Vladimir Iakovlev
f20e344663 #N/A: Update apt_invalid_operation rule 2017-09-02 10:11:02 +02:00
Vladimir Iakovlev
badd5a2aff Merge pull request #689 from nvbn/682-instant-fuck-mode
Unify work with output in instant and classic modes
2017-09-02 11:02:34 +03:00
Vladimir Iakovlev
f83e41137b Merge branch 'master' into 682-instant-fuck-mode 2017-09-02 09:31:24 +02:00
Vladimir Iakovlev
f9a4b69362 #N/A: Reorganize entrypoints 2017-09-02 09:30:03 +02:00
Vladimir Iakovlev
e9f48312e4 Merge branch 'master' into 682-instant-fuck-mode 2017-09-01 10:11:58 +02:00
Vladimir Iakovlev
9ba36c9d2a #74: #103: #221: Go back in history if alias is misspelled 2017-09-01 10:11:42 +02:00
Vladimir Iakovlev
2e0b423f2c #682: Add functional tests for instant mode 2017-09-01 07:10:16 +02:00
Vladimir Iakovlev
452ac21603 #682: Update readme 2017-08-31 17:59:38 +02:00
Vladimir Iakovlev
4625d8503d #682: Unify work with output in classic and instant mode 2017-08-31 17:58:56 +02:00
Vladimir Iakovlev
96843fc6cd #N/A: Support relative paths in cache decorator 2017-08-30 15:05:44 +02:00
Vladimir Iakovlev
503c903822 #N/A: Update react_native_command_unrecognized rule 2017-08-30 08:09:13 +02:00
Vladimir Iakovlev
1f1b7da6f4 #682: Warn if PS1 changed after thefuck initialization 2017-08-30 07:44:58 +02:00
Vladimir Iakovlev
db12211e05 Bump to 3.23 2017-08-29 09:39:32 +02:00
Vladimir Iakovlev
7a0db1899c #685: Warn about Python 2 only on Python 2 2017-08-29 09:39:24 +02:00
Vladimir Iakovlev
e5255c3278 Bump to 3.22 2017-08-29 05:02:16 +02:00
Vladimir Iakovlev
d44b11fbd8 #682: Fix gif link 2017-08-28 03:39:17 +02:00
Vladimir Iakovlev
3472026d5e #685: Warn about Python 2 support 2017-08-28 03:38:14 +02:00
Vladimir Iakovlev
bf3c16816d Merge pull request #684 from nvbn/682-instant-fuck-mode
682 instant fuck mode
2017-08-28 04:35:51 +03:00
Vladimir Iakovlev
6fac0622e5 #682: Warn on instant mode with Python 2 2017-08-28 03:21:15 +02:00
Vladimir Iakovlev
1b694fae7b #682: Fix gif link 2017-08-26 14:41:05 +02:00
Vladimir Iakovlev
2ebfb92760 #682: Add gif with instant mode 2017-08-26 14:39:36 +02:00
Vladimir Iakovlev
9cb04ac631 #682: Make warnings more visible 2017-08-26 14:30:19 +02:00
Vladimir Iakovlev
5504b905f3 #682: Fix git_push rule in instant mode 2017-08-26 13:39:38 +02:00
Vladimir Iakovlev
e707728fd5 #682: Update readme 2017-08-26 13:31:09 +02:00
Vladimir Iakovlev
3d98aad5df Merge branch 'master' into 682-instant-fuck-mode 2017-08-26 13:25:59 +02:00
Vladimir Iakovlev
b72ad2907f #682: Allow THEFUCK_INSTANT_MODE=False 2017-08-26 13:21:24 +02:00
Vladimir Iakovlev
7a57355e7e #682: Disable instant mode on Python 2 2017-08-26 13:16:10 +02:00
Vladimir Iakovlev
1132015e60 #682: Rename output to output_readers 2017-08-26 12:45:49 +02:00
Vladimir Iakovlev
0ecc86eda6 #682: Fix aliases in instant mode 2017-08-26 06:29:38 +02:00
Vladimir Iakovlev
c4848d1816 #682: Fix tests in python 2 2017-08-26 06:20:52 +02:00
Vladimir Iakovlev
31becc9456 #682: Fix tests and flake8 2017-08-26 06:16:51 +02:00
Vladimir Iakovlev
cd3a3cd823 #682: Implement instant mode aliases for bash and zsh 2017-08-26 05:46:07 +02:00
Vladimir Iakovlev
f9b30ae2d3 #683: Mention -y and -r in the readme 2017-08-26 04:57:16 +02:00
Vladimir Iakovlev
832ef96188 #681: Lower priority of missing_space_before_subcommand rule 2017-08-25 11:47:17 +02:00
Vladimir Iakovlev
20e678a38a #682: Implement experimental instant mode 2017-08-25 11:44:07 +02:00
Vladimir Iakovlev
f76d2061d1 Merge pull request #680 from simonwhitaker/patch-1
Fix docs for Command type
2017-08-23 09:37:13 +03:00
Simon Whitaker
16ec6a7d2a Fix docs for Command type 2017-08-23 07:14:56 +01:00
Vladimir Iakovlev
6c4333944f Bump to 3.21 2017-08-21 12:26:19 +02:00
Vladimir Iakovlev
31f5185642 Merge pull request #679 from nvbn/678-speedup-thefuck-alias
678 speedup thefuck
2017-08-21 13:25:33 +03:00
Vladimir Iakovlev
d71dbc5de4 #678: Speedup fuck by hardcoding entry points 2017-08-21 11:55:34 +02:00
Vladimir Iakovlev
fabef80056 #678: Import pkg_resources only when it needed 2017-08-21 11:50:04 +02:00
Vladimir Iakovlev
b4c4fdf706 #678: Use fastentrypoints 2017-08-21 11:32:23 +02:00
Vladimir Iakovlev
d267488520 Bump to 3.20 2017-08-16 11:28:59 +02:00
Vladimir Iakovlev
e31124335f #658: Ensure that history isn't empty in autoconfiguration 2017-08-16 11:26:43 +02:00
Vladimir Iakovlev
71a5182b9a Merge pull request #676 from nvbn/662-fix-autoconfig
#662: Autoconfigure when `fuck` was called < 60 seconds ago from the same shell
2017-08-08 17:36:10 +02:00
Vladimir Iakovlev
6a096155dc #662: Autoconfigure when fuck was called < 60 seconds ago from the same shell 2017-08-08 16:13:37 +02:00
Vladimir Iakovlev
5742d2d910 #N/A: Use real PATH in tests 2017-08-03 12:30:04 +02:00
Vladimir Iakovlev
754bb3e21f #N/A: Reset environment variables in tests 2017-08-03 12:18:05 +02:00
Vladimir Iakovlev
2bbba9a0c8 Bump to 3.19 2017-08-03 11:34:01 +02:00
Vladimir Iakovlev
b978c3793e Merge pull request #669 from tomoshi0809/master
#630 Catching the escaped space in filenames
2017-07-22 20:11:03 +02:00
KEI
8a83b30e73 Corrected the part for splitting a command 2017-07-19 00:09:21 +09:00
Markus Reiter
50db76c019 Update README.md 2017-07-06 00:21:31 +02:00
Markus Reiter
a1da33493e Delete test_brew_upgrade.py 2017-07-06 00:20:46 +02:00
Markus Reiter
916dfae6dd Remove brew upgrade --all rule. 2017-07-06 00:10:27 +02:00
Vladimir Iakovlev
fd20a3f832 Merge pull request #657 from josephfrazier/git_not_command-wording
Update stderr wording of git_not_command
2017-06-19 23:12:46 +02:00
Joseph Frazier
b6ed499103 Make git_not_command stderr detection backward-compatible 2017-06-06 13:56:13 -04:00
Joseph Frazier
76600cf40a Update stderr wording of git_not_command
This changed in git v2.13.1, see
6c48686263 (diff-081cf476dd9ac3b05c183570de47cb23)
2017-06-05 17:29:42 -04:00
Vladimir Iakovlev
e62666181a #650: #651: #646: Recommend to install thefuck globally 2017-05-29 10:11:15 +02:00
408 changed files with 7190 additions and 2323 deletions

10
.devcontainer/Dockerfile Normal file
View File

@@ -0,0 +1,10 @@
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.163.1/containers/python-3/.devcontainer/base.Dockerfile
# [Choice] Python version: 3, 3.9, 3.8, 3.7, 3.6
ARG VARIANT="3"
FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT}
# [Optional] If your pip requirements rarely change, uncomment this section to add them to the image.
COPY requirements.txt /tmp/pip-tmp/
RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \
&& rm -rf /tmp/pip-tmp

View File

@@ -0,0 +1,39 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.163.1/containers/python-3
{
"name": "Python 3",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
// Set *default* container specific settings.json values on container create.
"settings": {
"terminal.integrated.profiles.linux": {
"bash (login)": {
"path": "bash",
"args": ["-l"]
}
},
"python.pythonPath": "/usr/local/bin/python",
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8",
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
"python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
"python.linting.banditPath": "/usr/local/py-utils/bin/bandit",
"python.linting.flake8Path": "/usr/local/py-utils/bin/flake8",
"python.linting.mypyPath": "/usr/local/py-utils/bin/mypy",
"python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle",
"python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle",
"python.linting.pylintPath": "/usr/local/py-utils/bin/pylint"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-python.python"
],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "pip3 install -r requirements.txt && python3 setup.py develop"
}

11
.editorconfig Normal file
View File

@@ -0,0 +1,11 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
[*.py]
max_line_length = 119

34
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,34 @@
<!-- If you have any issue with The Fuck, sorry about that, but we will do what we
can to fix that. Actually, maybe we already have, so first thing to do is to
update The Fuck and see if the bug is still there. -->
<!-- If it is (sorry again), check if the problem has not already been reported and
if not, just open an issue on [GitHub](https://github.com/nvbn/thefuck) with
the following basic information: -->
The output of `thefuck --version` (something like `The Fuck 3.1 using Python
3.5.0 and Bash 4.4.12(1)-release`):
FILL THIS IN
Your system (Debian 7, ArchLinux, Windows, etc.):
FILL THIS IN
How to reproduce the bug:
FILL THIS IN
The output of The Fuck with `THEFUCK_DEBUG=true` exported (typically execute `export THEFUCK_DEBUG=true` in your shell before The Fuck):
FILL THIS IN
If the bug only appears with a specific application, the output of that application and its version:
FILL THIS IN
Anything else you think is relevant:
FILL THIS IN
<!-- It's only with enough information that we can do something to fix the problem. -->

68
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,68 @@
name: Tests
on: [push, pull_request]
env:
PYTHON_LATEST: "3.11"
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12-dev"]
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Cache dependencies
id: cache-deps
uses: actions/cache@v2
with:
path: |
${{ env.pythonLocation }}/bin/*
${{ env.pythonLocation }}/lib/*
${{ env.pythonLocation }}/scripts/*
key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('setup.py', 'requirements.txt') }}
- name: Install The Fuck with all dependencies
if: steps.cache-deps.outputs.cache-hit != 'true'
run: |
pip install -Ur requirements.txt coveralls
python setup.py develop
- name: Lint
if: matrix.os == 'ubuntu-latest' && matrix.python-version == env.PYTHON_LATEST
run: flake8
- name: Run tests
if: matrix.os != 'ubuntu-latest' || matrix.python-version != env.PYTHON_LATEST
run: coverage run --source=thefuck,tests -m pytest -v --capture=sys tests
- name: Run tests (including functional)
if: matrix.os == 'ubuntu-latest' && matrix.python-version == env.PYTHON_LATEST
run: |
docker build -t thefuck/python3 -f tests/Dockerfile --build-arg PYTHON_VERSION=3 .
docker build -t thefuck/python2 -f tests/Dockerfile --build-arg PYTHON_VERSION=2 .
coverage run --source=thefuck,tests -m pytest -v --capture=sys tests --enable-functional
- name: Post coverage results
if: matrix.os == 'ubuntu-latest' && matrix.python-version == env.PYTHON_LATEST
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: coveralls --service=github
test-deprecated:
strategy:
matrix:
python-version: ["2.7", "3.6"]
runs-on: ubuntu-latest
container: python:${{ matrix.python-version }}
steps:
- uses: actions/checkout@v2
- name: Install The Fuck with all dependencies
run: |
pip install -Ur requirements.txt coveralls
python setup.py develop
- name: Lint
run: flake8
- name: Run tests
run: coverage run --source=thefuck,tests -m pytest -v --capture=sys tests

View File

@@ -1,51 +0,0 @@
language: python
sudo: false
matrix:
include:
- os: linux
dist: trusty
python: "3.6"
- os: linux
dist: trusty
python: "3.5"
- os: linux
dist: trusty
python: "3.4"
- os: linux
dist: trusty
python: "3.3"
- os: linux
dist: trusty
python: "2.7"
- os: osx
env: FORMULA="python"
language: generic
- os: osx
env: FORMULA="python3"
language: generic
services:
- docker
addons:
apt:
packages:
- python-commandnotfound
- python3-commandnotfound
before_install:
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew update ; 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
- pip install -U coveralls
install:
- pip install -Ur requirements.txt
- 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.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:
- if [[ $TRAVIS_PYTHON_VERSION == 3.6 && $TRAVIS_OS_NAME != "osx" ]]; then coveralls; fi

View File

@@ -23,3 +23,70 @@ It's only with enough information that we can do something to fix the problem.
We gladly accept pull request on the [official
repository](https://github.com/nvbn/thefuck) for new rules, new features, bug
fixes, etc.
# Developing
In order to develop locally, there are two options:
- Develop using a local installation of Python 3 and setting up a virtual environment
- Develop using an automated VSCode Dev Container.
## Develop using local Python installation
[Create and activate a Python 3 virtual environment.](https://docs.python.org/3/tutorial/venv.html)
Install `The Fuck` for development:
```bash
pip install -r requirements.txt
python setup.py develop
```
Run code style checks:
```bash
flake8
```
Run unit tests:
```bash
pytest
```
Run unit and functional tests (requires docker):
```bash
pytest --enable-functional
```
For sending package to pypi:
```bash
sudo apt-get install pandoc
./release.py
```
## Develop using Dev Container
To make local development easier a [VSCode Devcontainer](https://code.visualstudio.com/docs/remote/remote-overview) is included with this repository. This will allows you to spin up a Docker container with all the necessary prerequisites for this project pre-installed ready to go, no local Python install/setup required.
### Prerequisites
To use the container you require:
- [Docker](https://www.docker.com/products/docker-desktop)
- [VSCode](https://code.visualstudio.com/)
- [VSCode Remote Development Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack)
- [Windows Users Only]: [Installation of WSL2 and configuration of Docker to use it](https://docs.docker.com/docker-for-windows/wsl/)
Full notes about [installation are here](https://code.visualstudio.com/docs/remote/containers#_installation)
### Running the container
Assuming you have the prerequisites:
1. Open VSCode
1. Open command palette (CMD+SHIFT+P (mac) or CTRL+SHIFT+P (windows))
1. Select `Remote-Containers: Reopen in Container`.
1. Container will be built, install all pip requirements and your VSCode will mount into it automagically.
1. Your VSCode and container now essentially become a throw away environment.

View File

@@ -1,7 +1,7 @@
The MIT License (MIT)
=====================
Copyright (c) 2015 Vladimir Iakovlev
Copyright (c) 2015-2022 Vladimir Iakovlev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1 +1,2 @@
include LICENSE.md
include fastentrypoints.py

336
README.md
View File

@@ -1,12 +1,15 @@
# The Fuck [![Version][version-badge]][version-link] [![Build Status][travis-badge]][travis-link] [![Windows Build Status][appveyor-badge]][appveyor-link] [![Coverage][coverage-badge]][coverage-link] [![MIT License][license-badge]](LICENSE.md)
# The Fuck [![Version][version-badge]][version-link] [![Build Status][workflow-badge]][workflow-link] [![Coverage][coverage-badge]][coverage-link] [![MIT License][license-badge]](LICENSE.md)
Magnificent app which corrects your previous console command,
inspired by a [@liamosaur](https://twitter.com/liamosaur/)
[tweet](https://twitter.com/liamosaur/status/506975850596536320).
*The Fuck* is a magnificent app, inspired by a [@liamosaur](https://twitter.com/liamosaur/)
[tweet](https://twitter.com/liamosaur/status/506975850596536320),
that corrects errors in previous console commands.
Is *The Fuck* too slow? [Try the experimental instant mode!](#experimental-instant-mode)
[![gif with examples][examples-link]][examples-link]
Few more examples:
More examples:
```bash
➜ apt-get install vim
@@ -73,8 +76,8 @@ REPL-y 0.3.1
...
```
If you are not scared to blindly run the changed command, there is a `require_confirmation`
[settings](#settings) option:
If you're not afraid of blindly running corrected commands, the
`require_confirmation` [settings](#settings) option can be disabled:
```bash
➜ apt-get install vim
@@ -88,36 +91,68 @@ Reading package lists... Done
...
```
## Contents
1. [Requirements](#requirements)
2. [Installations](#installation)
3. [Updating](#updating)
4. [How it works](#how-it-works)
5. [Creating your own rules](#creating-your-own-rules)
6. [Settings](#settings)
7. [Third party packages with rules](#third-party-packages-with-rules)
8. [Experimental instant mode](#experimental-instant-mode)
9. [Developing](#developing)
10. [License](#license-mit)
## Requirements
- python (2.7+ or 3.3+)
- python (3.5+)
- pip
- python-dev
##### [Back to Contents](#contents)
## Installation
On OS X you can install `The Fuck` with [Homebrew][homebrew]:
On macOS or Linux, you can install *The Fuck* via [Homebrew][homebrew]:
```bash
brew install thefuck
```
On Ubuntu you can install `The Fuck` with:
On Ubuntu / Mint, install *The Fuck* with the following commands:
```bash
sudo apt update
sudo apt install python3-dev python3-pip
pip3 install --user thefuck
sudo apt install python3-dev python3-pip python3-setuptools
pip3 install thefuck --user
```
On other systems you can install `The Fuck` with `pip`:
On FreeBSD, install *The Fuck* with the following commands:
```bash
pkg install thefuck
```
On ChromeOS, install *The Fuck* using [chromebrew](https://github.com/skycocker/chromebrew) with the following command:
```bash
crew install thefuck
```
On Arch based systems, install *The Fuck* with the following command:
```
sudo pacman -S thefuck
```
On other systems, install *The Fuck* by using `pip`:
```bash
pip install --user thefuck
pip install thefuck
```
[Or using an OS package manager (OS X, Ubuntu, Arch).](https://github.com/nvbn/thefuck/wiki/Installation)
[Alternatively, you may use an OS package manager (OS X, Ubuntu, Arch).](https://github.com/nvbn/thefuck/wiki/Installation)
You should place this command in your `.bash_profile`, `.bashrc`, `.zshrc` or other startup script:
<a href='#manual-installation' name='manual-installation'>#</a>
It is recommended that you place this command in your `.bash_profile`,
`.bashrc`, `.zshrc` or other startup script:
```bash
eval $(thefuck --alias)
@@ -127,46 +162,70 @@ eval $(thefuck --alias FUCK)
[Or in your shell config (Bash, Zsh, Fish, Powershell, tcsh).](https://github.com/nvbn/thefuck/wiki/Shell-aliases)
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`).
Changes are only available in a new shell session. To make changes immediately
available, 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:
To run fixed commands without confirmation, use the `--yeah` option (or just `-y` for short, or `--hard` if you're especially frustrated):
```bash
alias fuck-it='export THEFUCK_REQUIRE_CONFIRMATION=False; fuck; export THEFUCK_REQUIRE_CONFIRMATION=True'
fuck --yeah
```
## Update
To fix commands recursively until succeeding, use the `-r` option:
```bash
pip install --user thefuck --upgrade
fuck -r
```
**Aliases changed in 1.34.**
##### [Back to Contents](#contents)
## Updating
```bash
pip3 install thefuck --upgrade
```
**Note: Alias functionality was changed in v1.34 of *The Fuck***
## Uninstall
To remove *The Fuck*, reverse the installation process:
- erase or comment *thefuck* alias line from your Bash, Zsh, Fish, Powershell, tcsh, ... shell config
- use your package manager (brew, pip3, pkg, crew, pip) to uninstall the binaries
## How it works
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:
*The Fuck* attempts to match the previous command with a rule. If a match is
found, a new command is created using the matched rule and executed. The
following rules are enabled by default:
* `adb_unknown_command` &ndash; fixes misspelled commands like `adb logcta`;
* `ag_literal` &ndash; adds `-Q` to `ag` when suggested;
* `aws_cli` &ndash; fixes misspelled commands like `aws dynamdb scan`;
* `az_cli` &ndash; fixes misspelled commands like `az providers`;
* `cargo` &ndash; runs `cargo build` instead of `cargo`;
* `cargo_no_command` &ndash; fixes wrongs commands like `cargo buid`;
* `cd_correction` &ndash; spellchecks and correct failed cd commands;
* `cargo_no_command` &ndash; fixes wrong commands like `cargo buid`;
* `cat_dir` &ndash; replaces `cat` with `ls` when you try to `cat` a directory;
* `cd_correction` &ndash; spellchecks and corrects failed cd commands;
* `cd_cs` &ndash; changes `cs` to `cd`;
* `cd_mkdir` &ndash; creates directories before cd'ing into them;
* `cd_parent` &ndash; changes `cd..` to `cd ..`;
* `chmod_x` &ndash; add execution bit;
* `chmod_x` &ndash; adds execution bit;
* `choco_install` &ndash; appends common suffixes for chocolatey packages;
* `composer_not_command` &ndash; fixes composer command name;
* `conda_mistype` &ndash; fixes conda commands;
* `cp_create_destination` &ndash; creates a new directory when you attempt to `cp` or `mv` to a non-existent one
* `cp_omitting_directory` &ndash; adds `-a` when you `cp` directory;
* `cpp11` &ndash; adds missing `-std=c++11` to `g++` or `clang++`;
* `dirty_untar` &ndash; fixes `tar x` command that untarred in the current directory;
* `dirty_unzip` &ndash; fixes `unzip` command that unzipped in the current directory;
* `django_south_ghost` &ndash; adds `--delete-ghost-migrations` to failed because ghosts django south migration;
* `django_south_merge` &ndash; adds `--merge` to inconsistent django south migration;
* `docker_login` &ndash; executes a `docker login` and repeats the previous command;
* `docker_not_command` &ndash; fixes wrong docker commands like `docker tags`;
* `docker_image_being_used_by_container` &dash; removes the container that is using the image before removing the image;
* `dry` &ndash; fixes repetitions like `git git push`;
* `fab_command_not_found` &ndash; fix misspelled fabric commands;
* `fab_command_not_found` &ndash; fixes misspelled fabric commands;
* `fix_alt_space` &ndash; replaces Alt+Space with Space character;
* `fix_file` &ndash; opens a file with an error in your `$EDITOR`;
* `gem_unknown_command` &ndash; fixes wrong `gem` commands;
@@ -174,46 +233,63 @@ using the matched rule and runs it. Rules enabled by default are as follows:
* `git_add_force` &ndash; adds `--force` to `git add <pathspec>...` when paths are .gitignore'd;
* `git_bisect_usage` &ndash; fixes `git bisect strt`, `git bisect goood`, `git bisect rset`, etc. when bisecting;
* `git_branch_delete` &ndash; changes `git branch -d` to `git branch -D`;
* `git_branch_delete_checked_out` &ndash; changes `git branch -d` to `git checkout master && git branch -D` when trying to delete a checked out branch;
* `git_branch_exists` &ndash; offers `git branch -d foo`, `git branch -D foo` or `git checkout foo` when creating a branch that already exists;
* `git_branch_list` &ndash; catches `git branch list` in place of `git branch` and removes created branch;
* `git_branch_0flag` &ndash; fixes commands such as `git branch 0v` and `git branch 0r` removing the created branch;
* `git_checkout` &ndash; fixes branch name or creates new branch;
* `git_clone_git_clone` &ndash; replaces `git clone git clone ...` with `git clone ...`
* `git_clone_missing` &ndash; adds `git clone` to URLs that appear to link to a git repository.
* `git_commit_add` &ndash; offers `git commit -a ...` or `git commit -p ...` after previous commit if it failed because nothing was staged;
* `git_commit_amend` &ndash; offers `git commit --amend` after previous commit;
* `git_commit_reset` &ndash; offers `git reset HEAD~` after previous commit;
* `git_diff_no_index` &ndash; adds `--no-index` to previous `git diff` on untracked files;
* `git_diff_staged` &ndash; adds `--staged` to previous `git diff` with unexpected output;
* `git_fix_stash` &ndash; fixes `git stash` commands (misspelled subcommand and missing `save`);
* `git_flag_after_filename` &ndash; fixes `fatal: bad flag '...' after filename`
* `git_help_aliased` &ndash; fixes `git help <alias>` commands replacing <alias> with the aliased command;
* `git_hook_bypass` &ndash; adds `--no-verify` flag previous to `git am`, `git commit`, or `git push` command;
* `git_lfs_mistype` &ndash; fixes mistyped `git lfs <command>` commands;
* `git_main_master` &ndash; fixes incorrect branch name between `main` and `master`
* `git_merge` &ndash; adds remote to branch names;
* `git_merge_unrelated` &ndash; adds `--allow-unrelated-histories` when required
* `git_not_command` &ndash; fixes wrong git commands like `git brnch`;
* `git_pull` &ndash; sets upstream before executing previous `git pull`;
* `git_pull_clone` &ndash; clones instead of pulling when the repo does not exist;
* `git_pull_uncommitted_changes` &ndash; stashes changes before pulling and pops them afterwards;
* `git_push` &ndash; adds `--set-upstream origin $branch` to previous failed `git push`;
* `git_push_different_branch_names` &ndash; fixes pushes when local branch name does not match remote branch name;
* `git_push_pull` &ndash; runs `git pull` when `push` was rejected;
* `git_push_without_commits` &ndash; Creates an initial commit if you forget and only `git add .`, when setting up a new project;
* `git_push_without_commits` &ndash; creates an initial commit if you forget and only `git add .`, when setting up a new project;
* `git_rebase_no_changes` &ndash; runs `git rebase --skip` instead of `git rebase --continue` when there are no changes;
* `git_rm_local_modifications` &ndash; adds `-f` or `--cached` when you try to `rm` a locally modified file;
* `git_remote_delete` &ndash; replaces `git remote delete remote_name` with `git remote remove remote_name`;
* `git_rm_local_modifications` &ndash; adds `-f` or `--cached` when you try to `rm` a locally modified file;
* `git_rm_recursive` &ndash; adds `-r` when you try to `rm` a directory;
* `git_rm_staged` &ndash; adds `-f` or `--cached` when you try to `rm` a file with staged changes
* `git_rebase_merge_dir` &ndash; offers `git rebase (--continue | --abort | --skip)` or removing the `.git/rebase-merge` dir when a rebase is in progress;
* `git_remote_seturl_add` &ndash; runs `git remote add` when `git remote set_url` on nonexistant remote;
* `git_remote_seturl_add` &ndash; runs `git remote add` when `git remote set_url` on nonexistent remote;
* `git_stash` &ndash; stashes your local modifications before rebasing or switching branch;
* `git_stash_pop` &ndash; adds your local modifications before popping stash, then resets;
* `git_tag_force` &ndash; adds `--force` to `git tag <tagname>` when the tag already exists;
* `git_two_dashes` &ndash; adds a missing dash to commands like `git commit -amend` or `git rebase -continue`;
* `go_run` &ndash; appends `.go` extension when compiling/running Go programs;
* `go_unknown_command` &ndash; fixes wrong `go` commands, for example `go bulid`;
* `gradle_no_task` &ndash; fixes not found or ambiguous `gradle` task;
* `gradle_wrapper` &ndash; replaces `gradle` with `./gradlew`;
* `grep_arguments_order` &ndash; fixes grep arguments order for situations like `grep -lir . test`;
* `grep_recursive` &ndash; adds `-r` when you trying to `grep` directory;
* `grep_arguments_order` &ndash; fixes `grep` arguments order for situations like `grep -lir . test`;
* `grep_recursive` &ndash; adds `-r` when you try to `grep` directory;
* `grunt_task_not_found` &ndash; fixes misspelled `grunt` commands;
* `gulp_not_task` &ndash; fixes misspelled `gulp` tasks;
* `has_exists_script` &ndash; prepends `./` when script/binary exists;
* `heroku_multiple_apps` &ndash; adds `--app <app>` to `heroku` commands like `heroku pg`;
* `heroku_not_command` &ndash; fixes wrong `heroku` commands like `heroku log`;
* `history` &ndash; tries to replace command with most similar command from history;
* `history` &ndash; tries to replace command with the most similar command from history;
* `hostscli` &ndash; tries to fix `hostscli` usage;
* `ifconfig_device_not_found` &ndash; fixes wrong device names like `wlan0` to `wlp2s0`;
* `java` &ndash; removes `.java` extension when running Java programs;
* `javac` &ndash; appends missing `.java` when compiling Java files;
* `lein_not_task` &ndash; fixes wrong `lein` tasks like `lein rpl`;
* `long_form_help` &ndash; changes `-h` to `--help` when the short form version is not supported
* `ln_no_hard_link` &ndash; catches hard link creation on directories, suggest symbolic link;
* `ln_s_order` &ndash; fixes `ln -s` arguments order;
* `ls_all` &ndash; adds `-A` to `ls` when output is empty;
@@ -222,95 +298,121 @@ using the matched rule and runs it. Rules enabled by default are as follows:
* `man_no_space` &ndash; fixes man commands without spaces, for example `mandiff`;
* `mercurial` &ndash; fixes wrong `hg` commands;
* `missing_space_before_subcommand` &ndash; fixes command with missing space like `npminstall`;
* `mkdir_p` &ndash; adds `-p` when you trying to create directory without parent;
* `mkdir_p` &ndash; adds `-p` when you try to create a directory without a parent;
* `mvn_no_command` &ndash; adds `clean package` to `mvn`;
* `mvn_unknown_lifecycle_phase` &ndash; fixes misspelled lifecycle phases with `mvn`;
* `mvn_unknown_lifecycle_phase` &ndash; fixes misspelled life cycle phases with `mvn`;
* `npm_missing_script` &ndash; fixes `npm` custom script name in `npm run-script <script>`;
* `npm_run_script` &ndash; adds missing `run-script` for custom `npm` scripts;
* `npm_wrong_command` &ndash; fixes wrong npm commands like `npm urgrade`;
* `no_command` &ndash; fixes wrong console commands, for example `vom/vim`;
* `no_such_file` &ndash; creates missing directories with `mv` and `cp` commands;
* `open` &ndash; either prepends `http://` to address passed to `open` or create a new file or directory and passes it to `open`;
* `omnienv_no_such_command` &ndash; fixes wrong commands for `goenv`, `nodenv`, `pyenv` and `rbenv` (eg.: `pyenv isntall` or `goenv list`);
* `open` &ndash; either prepends `http://` to address passed to `open` or creates a new file or directory and passes it to `open`;
* `pip_install` &ndash; fixes permission issues with `pip install` commands by adding `--user` or prepending `sudo` if necessary;
* `pip_unknown_command` &ndash; fixes wrong `pip` commands, for example `pip instatl/pip install`;
* `php_s` &ndash; replaces `-s` by `-S` when trying to run a local php server;
* `port_already_in_use` &ndash; kills process that bound port;
* `python_command` &ndash; prepends `python` when you trying to run not executable/without `./` python script;
* `prove_recursively` &ndash; adds `-r` when called with directory;
* `python_command` &ndash; prepends `python` when you try to run non-executable/without `./` python script;
* `python_execute` &ndash; appends missing `.py` when executing Python files;
* `python_module_error` &ndash; fixes ModuleNotFoundError by trying to `pip install` that module;
* `quotation_marks` &ndash; fixes uneven usage of `'` and `"` when containing args';
* `path_from_history` &ndash; replaces not found path with similar absolute path from history;
* `path_from_history` &ndash; replaces not found path with a similar absolute path from history;
* `rails_migrations_pending` &ndash; runs pending migrations;
* `react_native_command_unrecognized` &ndash; fixes unrecognized `react-native` commands;
* `remove_trailing_cedilla` &ndash; remove trailling cedillas `ç`, a common typo for european keyboard layouts;
* `rm_dir` &ndash; adds `-rf` when you trying to remove directory;
* `remove_shell_prompt_literal` &ndash; removes leading shell prompt symbol `$`, common when copying commands from documentations;
* `remove_trailing_cedilla` &ndash; removes trailing cedillas `ç`, a common typo for European keyboard layouts;
* `rm_dir` &ndash; adds `-rf` when you try to remove a directory;
* `scm_correction` &ndash; corrects wrong scm like `hg log` to `git log`;
* `sed_unterminated_s` &ndash; adds missing '/' to `sed`'s `s` commands;
* `sl_ls` &ndash; changes `sl` to `ls`;
* `ssh_known_hosts` &ndash; removes host from `known_hosts` on warning;
* `sudo` &ndash; prepends `sudo` to previous command if it failed because of permissions;
* `sudo` &ndash; prepends `sudo` to the previous command if it failed because of permissions;
* `sudo_command_from_user_path` &ndash; runs commands from users `$PATH` with `sudo`;
* `switch_lang` &ndash; switches command from your local layout to en;
* `systemctl` &ndash; correctly orders parameters of confusing `systemctl`;
* `test.py` &ndash; runs `py.test` instead of `test.py`;
* `terraform_init.py` &ndash; runs `terraform init` before plan or apply;
* `terraform_no_command.py` &ndash; fixes unrecognized `terraform` commands;
* `test.py` &ndash; runs `pytest` instead of `test.py`;
* `touch` &ndash; creates missing directories before "touching";
* `tsuru_login` &ndash; runs `tsuru login` if not authenticated or session expired;
* `tsuru_not_command` &ndash; fixes wrong `tsuru` commands like `tsuru shell`;
* `tmux` &ndash; fixes `tmux` commands;
* `unknown_command` &ndash; fixes hadoop hdfs-style "unknown command", for example adds missing '-' to the command on `hdfs dfs ls`;
* `unsudo` &ndash; removes `sudo` from previous command if a process refuses to run on superuser privilege.
* `vagrant_up` &ndash; starts up the vagrant instance;
* `whois` &ndash; fixes `whois` command;
* `workon_doesnt_exists` &ndash; fixes `virtualenvwrapper` env name os suggests to create new.
* `wrong_hyphen_before_subcommand` &ndash; removes an improperly placed hyphen (`apt-install` -> `apt install`, `git-log` -> `git log`, etc.)
* `yarn_alias` &ndash; fixes aliased `yarn` commands like `yarn ls`;
* `yarn_command_not_found` &ndash; fixes misspelled `yarn` commands;
* `yarn_command_replaced` &ndash; fixes replaced `yarn` commands;
* `yarn_help` &ndash; makes it easier to open `yarn` documentation;
Enabled by default only on specific platforms:
##### [Back to Contents](#contents)
The following rules are enabled by default on specific platforms only:
* `apt_get` &ndash; installs app from apt if it not installed (requires `python-commandnotfound` / `python3-commandnotfound`);
* `apt_get_search` &ndash; changes trying to search using `apt-get` with searching using `apt-cache`;
* `apt_invalid_operation` &ndash; fixes invalid `apt` and `apt-get` calls, like `apt-get isntall vim`;
* `apt_list_upgradable` &ndash; helps you run `apt list --upgradable` after `apt update`;
* `apt_upgrade` &ndash; helps you run `apt upgrade` after `apt list --upgradable`;
* `brew_cask_dependency` &ndash; installs cask dependencies;
* `brew_install` &ndash; fixes formula name for `brew install`;
* `brew_reinstall` &ndash; turns `brew install <formula>` into `brew reinstall <formula>`;
* `brew_link` &ndash; adds `--overwrite --dry-run` if linking fails;
* `brew_uninstall` &ndash; adds `--force` to `brew uninstall` if multiple versions were installed;
* `brew_unknown_command` &ndash; fixes wrong brew commands, for example `brew docto/brew doctor`;
* `brew_update_formula` &ndash; turns `brew update <formula>` into `brew upgrade <formula>`;
* `brew_upgrade` &ndash; appends `--all` to `brew upgrade` as per Homebrew's new behaviour;
* `pacman` &ndash; installs app with `pacman` if it is not installed (uses `yaourt` if available);
* `pacman_not_found` &ndash; fixes package name with `pacman` or `yaourt`.
* `dnf_no_such_command` &ndash; fixes mistyped DNF commands;
* `nixos_cmd_not_found` &ndash; installs apps on NixOS;
* `pacman` &ndash; installs app with `pacman` if it is not installed (uses `yay`, `pikaur` or `yaourt` if available);
* `pacman_invalid_option` &ndash; replaces lowercase `pacman` options with uppercase.
* `pacman_not_found` &ndash; fixes package name with `pacman`, `yay`, `pikaur` or `yaourt`.
* `yum_invalid_operation` &ndash; fixes invalid `yum` calls, like `yum isntall vim`;
Bundled, but not enabled by default:
The following commands are bundled with *The Fuck*, but are not enabled by
default:
* `git_push_force` &ndash; adds `--force-with-lease` to a `git push` (may conflict with `git_push_pull`);
* `rm_root` &ndash; adds `--no-preserve-root` to `rm -rf /` command.
##### [Back to Contents](#contents)
## Creating your own rules
For adding your own rule you should create `your-rule-name.py`
in `~/.config/thefuck/rules`. The rule should contain two functions:
To add your own rule, create a file named `your-rule-name.py`
in `~/.config/thefuck/rules`. The rule file must contain two functions:
```python
match(command: Command) -> bool
get_new_command(command: Command) -> str | list[str]
```
Also the rule can contain an optional function
Additionally, rules can contain optional functions:
```python
side_effect(old_command: Command, fixed_command: str) -> None
```
and optional `enabled_by_default`, `requires_output` and `priority` variables.
Rules can also contain the optional variables `enabled_by_default`, `requires_output` and `priority`.
`Command` has three attributes: `script`, `stdout`, `stderr` and `script_parts`.
Rule shouldn't change `Command`.
`Command` has three attributes: `script`, `output` and `script_parts`.
Your rule should not 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)).
**Rules api changed in 3.0:** To access a rule's settings, import it with
`from thefuck.conf import settings`
Simple example of the rule for running script with `sudo`:
`settings` is a special object assembled from `~/.config/thefuck/settings.py`,
and values from env ([see more below](#settings)).
A simple example rule for running a script with `sudo`:
```python
def match(command):
return ('permission denied' in command.stderr.lower()
or 'EACCES' in command.stderr)
return ('permission denied' in command.output.lower()
or 'EACCES' in command.output)
def get_new_command(command):
@@ -331,23 +433,28 @@ requires_output = True
[utility functions for rules](https://github.com/nvbn/thefuck/tree/master/thefuck/utils.py),
[app/os-specific helpers](https://github.com/nvbn/thefuck/tree/master/thefuck/specific/).
##### [Back to Contents](#contents)
## Settings
The Fuck has a few settings parameters which can be changed in `$XDG_CONFIG_HOME/thefuck/settings.py` (`$XDG_CONFIG_HOME` defaults to `~/.config`):
Several *The Fuck* parameters can be changed in the file `$XDG_CONFIG_HOME/thefuck/settings.py`
(`$XDG_CONFIG_HOME` defaults to `~/.config`):
* `rules` &ndash; list of enabled rules, by default `thefuck.conf.DEFAULT_RULES`;
* `rules` &ndash; list of enabled rules, by default `thefuck.const.DEFAULT_RULES`;
* `exclude_rules` &ndash; list of disabled rules, by default `[]`;
* `require_confirmation` &ndash; requires confirmation before running new command, by default `True`;
* `wait_command` &ndash; max amount of time in seconds for getting previous command output;
* `wait_command` &ndash; the max amount of time in seconds for getting previous command output;
* `no_colors` &ndash; disable colored output;
* `priority` &ndash; dict with rules priorities, rule with lower `priority` will be matched first;
* `debug` &ndash; enables debug output, by default `False`;
* `history_limit` &ndash; numeric value of how many history commands will be scanned, like `2000`;
* `history_limit` &ndash; the numeric value of how many history commands will be scanned, like `2000`;
* `alter_history` &ndash; push fixed command to history, by default `True`;
* `wait_slow_command` &ndash; max amount of time in seconds for getting previous command output if it in `slow_commands` list;
* `slow_commands` &ndash; list of slow commands.
* `slow_commands` &ndash; list of slow commands;
* `num_close_matches` &ndash; the maximum number of close matches to suggest, by default `3`.
* `excluded_search_path_prefixes` &ndash; path prefixes to ignore when searching for commands, by default `[]`.
Example of `settings.py`:
An example of `settings.py`:
```python
rules = ['sudo', 'no_command']
@@ -360,6 +467,7 @@ debug = False
history_limit = 9999
wait_slow_command = 20
slow_commands = ['react-native', 'gradle']
num_close_matches = 5
```
Or via environment variables:
@@ -367,15 +475,17 @@ Or via environment variables:
* `THEFUCK_RULES` &ndash; list of enabled rules, like `DEFAULT_RULES:rm_root` or `sudo:no_command`;
* `THEFUCK_EXCLUDE_RULES` &ndash; list of disabled rules, like `git_pull:git_push`;
* `THEFUCK_REQUIRE_CONFIRMATION` &ndash; require confirmation before running new command, `true/false`;
* `THEFUCK_WAIT_COMMAND` &ndash; max amount of time in seconds for getting previous command output;
* `THEFUCK_WAIT_COMMAND` &ndash; the max amount of time in seconds for getting previous command output;
* `THEFUCK_NO_COLORS` &ndash; disable colored output, `true/false`;
* `THEFUCK_PRIORITY` &ndash; priority of the rules, like `no_command=9999:apt_get=100`,
rule with lower `priority` will be matched first;
* `THEFUCK_DEBUG` &ndash; enables debug output, `true/false`;
* `THEFUCK_HISTORY_LIMIT` &ndash; how many history commands will be scanned, like `2000`;
* `THEFUCK_ALTER_HISTORY` &ndash; push fixed command to history `true/false`;
* `THEFUCK_WAIT_SLOW_COMMAND` &ndash; max amount of time in seconds for getting previous command output if it in `slow_commands` list;
* `THEFUCK_SLOW_COMMANDS` &ndash; list of slow commands, like `lein:gradle`.
* `THEFUCK_WAIT_SLOW_COMMAND` &ndash; the max amount of time in seconds for getting previous command output if it in `slow_commands` list;
* `THEFUCK_SLOW_COMMANDS` &ndash; list of slow commands, like `lein:gradle`;
* `THEFUCK_NUM_CLOSE_MATCHES` &ndash; the maximum number of close matches to suggest, like `5`.
* `THEFUCK_EXCLUDED_SEARCH_PATH_PREFIXES` &ndash; path prefixes to ignore when searching for commands, by default `[]`.
For example:
@@ -387,41 +497,56 @@ export THEFUCK_WAIT_COMMAND=10
export THEFUCK_NO_COLORS='false'
export THEFUCK_PRIORITY='no_command=9999:apt_get=100'
export THEFUCK_HISTORY_LIMIT='2000'
export THEFUCK_NUM_CLOSE_MATCHES='5'
```
##### [Back to Contents](#contents)
## Third-party packages with rules
If you'd like to make a specific set of non-public rules, but would still like
to share them with others, create a package named `thefuck_contrib_*` with
the following structure:
```
thefuck_contrib_foo
thefuck_contrib_foo
rules
__init__.py
*third-party rules*
__init__.py
*third-party-utils*
setup.py
```
*The Fuck* will find rules located in the `rules` module.
##### [Back to Contents](#contents)
## Experimental instant mode
The default behavior of *The Fuck* requires time to re-run previous commands.
When in instant mode, *The Fuck* saves time by logging output with [script](https://en.wikipedia.org/wiki/Script_(Unix)),
then reading the log.
[![gif with instant mode][instant-mode-gif-link]][instant-mode-gif-link]
Currently, instant mode only supports Python 3 with bash or zsh. zsh's autocorrect function also needs to be disabled in order for thefuck to work properly.
To enable instant mode, add `--enable-experimental-instant-mode`
to the alias initialization in `.bashrc`, `.bash_profile` or `.zshrc`.
For example:
```bash
eval $(thefuck --alias --enable-experimental-instant-mode)
```
##### [Back to Contents](#contents)
## Developing
Install `The Fuck` for development:
```bash
pip install -r requirements.txt
python setup.py develop
```
Run code style checks:
```bash
flake8
```
Run unit tests:
```bash
py.test
```
Run unit and functional tests (requires docker):
```bash
py.test --enable-functional
```
For sending package to pypi:
```bash
sudo apt-get install pandoc
./release.py
```
See [CONTRIBUTING.md](CONTRIBUTING.md)
## License MIT
Project License can be found [here](LICENSE.md).
@@ -429,12 +554,13 @@ 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://travis-ci.org/nvbn/thefuck.svg?branch=master
[travis-link]: https://travis-ci.org/nvbn/thefuck
[appveyor-badge]: https://ci.appveyor.com/api/projects/status/1sskj4imj02um0gu/branch/master?svg=true
[appveyor-link]: https://ci.appveyor.com/project/nvbn/thefuck
[workflow-badge]: https://github.com/nvbn/thefuck/workflows/Tests/badge.svg
[workflow-link]: https://github.com/nvbn/thefuck/actions?query=workflow%3ATests
[coverage-badge]: https://img.shields.io/coveralls/nvbn/thefuck.svg
[coverage-link]: https://coveralls.io/github/nvbn/thefuck
[license-badge]: https://img.shields.io/badge/license-MIT-007EC7.svg
[examples-link]: https://raw.githubusercontent.com/nvbn/thefuck/master/example.gif
[homebrew]: http://brew.sh/
[instant-mode-gif-link]: https://raw.githubusercontent.com/nvbn/thefuck/master/example_instant_mode.gif
[homebrew]: https://brew.sh/
##### [Back to Contents](#contents)

View File

@@ -1,24 +0,0 @@
build: false
environment:
matrix:
- PYTHON: "C:/Python27"
- PYTHON: "C:/Python33"
- PYTHON: "C:/Python34"
- PYTHON: "C:/Python35"
- PYTHON: "C:/Python36"
init:
- "ECHO %PYTHON%"
- ps: "ls C:/Python*"
install:
- ps: (new-object net.webclient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:/get-pip.py')
- "%PYTHON%/python.exe C:/get-pip.py"
- "%PYTHON%/Scripts/pip.exe install -U setuptools"
- "%PYTHON%/python.exe setup.py develop"
- "%PYTHON%/Scripts/pip.exe install -U -r requirements.txt"
test_script:
- "%PYTHON%/python.exe -m flake8"
- "%PYTHON%/Scripts/py.test.exe -sv"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 KiB

After

Width:  |  Height:  |  Size: 631 KiB

BIN
example_instant_mode.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 KiB

110
fastentrypoints.py Normal file
View File

@@ -0,0 +1,110 @@
# Copyright (c) 2016, Aaron Christianson
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
Monkey patch setuptools to write faster console_scripts with this format:
import sys
from mymodule import entry_function
sys.exit(entry_function())
This is better.
(c) 2016, Aaron Christianson
http://github.com/ninjaaron/fast-entry_points
'''
from setuptools.command import easy_install
import re
TEMPLATE = r'''\
# -*- coding: utf-8 -*-
# EASY-INSTALL-ENTRY-SCRIPT: '{3}','{4}','{5}'
__requires__ = '{3}'
import re
import sys
from {0} import {1}
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit({2}())'''
@classmethod
def get_args(cls, dist, header=None):
"""
Yield write_script() argument tuples for a distribution's
console_scripts and gui_scripts entry points.
"""
if header is None:
header = cls.get_header()
spec = str(dist.as_requirement())
for type_ in 'console', 'gui':
group = type_ + '_scripts'
for name, ep in dist.get_entry_map(group).items():
# ensure_safe_name
if re.search(r'[\\/]', name):
raise ValueError("Path separators not allowed in script names")
script_text = TEMPLATE.format(
ep.module_name, ep.attrs[0], '.'.join(ep.attrs),
spec, group, name)
args = cls._get_script_args(type_, name, header, script_text)
for res in args:
yield res
easy_install.ScriptWriter.get_args = get_args
def main():
import os
import re
import shutil
import sys
dests = sys.argv[1:] or ['.']
filename = re.sub(r'\.pyc$', '.py', __file__)
for dst in dests:
shutil.copy(filename, dst)
manifest_path = os.path.join(dst, 'MANIFEST.in')
setup_path = os.path.join(dst, 'setup.py')
# Insert the include statement to MANIFEST.in if not present
with open(manifest_path, 'a+') as manifest:
manifest.seek(0)
manifest_content = manifest.read()
if not 'include fastentrypoints.py' in manifest_content:
manifest.write(('\n' if manifest_content else '')
+ 'include fastentrypoints.py')
# Insert the import statement to setup.py if not present
with open(setup_path, 'a+') as setup:
setup.seek(0)
setup_content = setup.read()
if not 'import fastentrypoints' in setup_content:
setup.seek(0)
setup.truncate()
setup.write('import fastentrypoints\n' + setup_content)
print(__name__)

View File

@@ -32,4 +32,6 @@ call('git push --tags', shell=True)
env = os.environ
env['CONVERT_README'] = 'true'
call('python setup.py sdist bdist_wheel upload', shell=True, env=env)
call('rm -rf dist/*', shell=True, env=env)
call('python setup.py sdist bdist_wheel', shell=True, env=env)
call('twine upload dist/*', shell=True, env=env)

View File

@@ -1,4 +1,3 @@
pip
flake8
pytest
mock
@@ -9,3 +8,4 @@ pexpect
pypandoc
pytest-benchmark
pytest-docker-pexpect
twine

2
scripts/fuck.bat Normal file
View File

@@ -0,0 +1,2 @@
@set PYTHONIOENCODING=utf-8
@powershell -noprofile -c "cmd /c \"$(thefuck %* $(doskey /history)[-2])\"; [Console]::ResetColor();"

22
scripts/fuck.ps1 Normal file
View File

@@ -0,0 +1,22 @@
if ((Get-Command "fuck").CommandType -eq "Function") {
fuck @args;
[Console]::ResetColor()
exit
}
"First time use of thefuck detected. "
if ((Get-Content $PROFILE -Raw -ErrorAction Ignore) -like "*thefuck*") {
} else {
" - Adding thefuck intialization to user `$PROFILE"
$script = "`n`$env:PYTHONIOENCODING='utf-8' `niex `"`$(thefuck --alias)`"";
Write-Output $script | Add-Content $PROFILE
}
" - Adding fuck() function to current session..."
$env:PYTHONIOENCODING='utf-8'
iex "$($(thefuck --alias).Replace("function fuck", "function global:fuck"))"
" - Invoking fuck()`n"
fuck @args;
[Console]::ResetColor()

View File

@@ -3,6 +3,8 @@ from setuptools import setup, find_packages
import pkg_resources
import sys
import os
import fastentrypoints
try:
if int(pkg_resources.get_distribution("pip").version.split('.')[0]) < 6:
@@ -24,17 +26,31 @@ if version < (2, 7):
print('thefuck requires Python version 2.7 or later' +
' ({}.{} detected).'.format(*version))
sys.exit(-1)
elif (3, 0) < version < (3, 3):
print('thefuck requires Python version 3.3 or later' +
elif (3, 0) < version < (3, 5):
print('thefuck requires Python version 3.5 or later' +
' ({}.{} detected).'.format(*version))
sys.exit(-1)
VERSION = '3.18'
VERSION = '3.32'
install_requires = ['psutil', 'colorama', 'six', 'decorator']
install_requires = ['psutil', 'colorama', 'six']
extras_require = {':python_version<"3.4"': ['pathlib2'],
':python_version<"3.3"': ['backports.shutil_get_terminal_size'],
':python_version<="2.7"': ['decorator<5', 'pyte<0.8.1'],
':python_version>"2.7"': ['decorator', 'pyte'],
":sys_platform=='win32'": ['win_unicode_console']}
if sys.platform == "win32":
scripts = ['scripts\\fuck.bat', 'scripts\\fuck.ps1']
entry_points = {'console_scripts': [
'thefuck = thefuck.entrypoints.main:main',
'thefuck_firstuse = thefuck.entrypoints.not_configured:main']}
else:
scripts = []
entry_points = {'console_scripts': [
'thefuck = thefuck.entrypoints.main:main',
'fuck = thefuck.entrypoints.not_configured:main']}
setup(name='thefuck',
version=VERSION,
description="Magnificent app which corrects your previous console command",
@@ -47,8 +63,8 @@ setup(name='thefuck',
'tests', 'tests.*', 'release']),
include_package_data=True,
zip_safe=False,
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
install_requires=install_requires,
extras_require=extras_require,
entry_points={'console_scripts': [
'thefuck = thefuck.main:main',
'fuck = thefuck.not_configured:main']})
scripts=scripts,
entry_points=entry_points)

25
snapcraft.yaml Normal file
View File

@@ -0,0 +1,25 @@
name: thefuck
version: stable
version-script: git -C parts/thefuck/build describe --abbrev=0 --tags
summary: Magnificent app which corrects your previous console command.
description: |
The Fuck tries to match a rule for the previous command,
creates a new command using the matched rule and runs it.
grade: stable
confinement: classic
apps:
thefuck:
command: bin/thefuck
environment:
PYTHONIOENCODING: utf-8
fuck:
command: bin/fuck
environment:
PYTHONIOENCODING: utf-8
parts:
thefuck:
source: https://github.com/nvbn/thefuck.git
plugin: python

7
tests/Dockerfile Normal file
View File

@@ -0,0 +1,7 @@
ARG PYTHON_VERSION
FROM python:${PYTHON_VERSION}
RUN apt-get update -y
RUN apt-get install -yy --no-install-recommends --no-install-suggests fish tcsh zsh
RUN pip install --upgrade pip
COPY . /src
RUN pip install /src

View File

@@ -1,3 +1,4 @@
import os
import pytest
from thefuck import shells
from thefuck import conf, const
@@ -6,6 +7,10 @@ from thefuck.system import Path
shells.shell = shells.Generic()
def pytest_configure(config):
config.addinivalue_line("markers", "functional: mark test as functional")
def pytest_addoption(parser):
"""Adds `--enable-functional` argument."""
group = parser.getgroup("thefuck")
@@ -41,7 +46,7 @@ def no_cache(monkeypatch):
@pytest.fixture(autouse=True)
def functional(request):
if request.node.get_marker('functional') \
if request.node.get_closest_marker('functional') \
and not request.config.getoption('enable_functional'):
pytest.skip('functional tests are disabled')
@@ -52,11 +57,17 @@ def source_root():
@pytest.fixture
def set_shell(monkeypatch, request):
def set_shell(monkeypatch):
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

View File

View File

@@ -0,0 +1,39 @@
from mock import Mock
import pytest
from thefuck.entrypoints.alias import _get_alias, print_alias
@pytest.mark.parametrize(
'py2, enable_experimental_instant_mode, which, is_instant', [
(False, True, True, True),
(False, False, True, False),
(False, True, False, False),
(True, True, True, False),
(True, True, False, False),
(True, False, True, False)])
def test_get_alias(monkeypatch, mocker, py2,
enable_experimental_instant_mode,
which, is_instant):
monkeypatch.setattr('six.PY2', py2)
args = Mock(
enable_experimental_instant_mode=enable_experimental_instant_mode,
alias='fuck', )
mocker.patch('thefuck.entrypoints.alias.which', return_value=which)
shell = Mock(app_alias=lambda _: 'app_alias',
instant_mode_alias=lambda _: 'instant_mode_alias')
monkeypatch.setattr('thefuck.entrypoints.alias.shell', shell)
alias = _get_alias(args)
if is_instant:
assert alias == 'instant_mode_alias'
else:
assert alias == 'app_alias'
def test_print_alias(mocker):
settings_mock = mocker.patch('thefuck.entrypoints.alias.settings')
_get_alias_mock = mocker.patch('thefuck.entrypoints.alias._get_alias')
known_args = Mock()
print_alias(known_args)
settings_mock.init.assert_called_once_with(known_args)
_get_alias_mock.assert_called_once_with(known_args)

View File

@@ -0,0 +1,26 @@
import pytest
from mock import Mock
from thefuck.entrypoints.fix_command import _get_raw_command
class TestGetRawCommand(object):
def test_from_force_command_argument(self):
known_args = Mock(force_command='git brunch')
assert _get_raw_command(known_args) == ['git brunch']
def test_from_command_argument(self, os_environ):
os_environ['TF_HISTORY'] = None
known_args = Mock(force_command=None,
command=['sl'])
assert _get_raw_command(known_args) == ['sl']
@pytest.mark.parametrize('history, result', [
('git br', 'git br'),
('git br\nfcuk', 'git br'),
('git br\nfcuk\nls', 'ls'),
('git br\nfcuk\nls\nfuk', 'ls')])
def test_from_history(self, os_environ, history, result):
os_environ['TF_HISTORY'] = history
known_args = Mock(force_command=None,
command=None)
assert _get_raw_command(known_args) == [result]

View File

@@ -1,40 +1,56 @@
import pytest
import json
from six import StringIO
from mock import MagicMock
from thefuck.shells.generic import ShellConfiguration
from thefuck.not_configured import main
from thefuck.entrypoints.not_configured import main
@pytest.fixture(autouse=True)
def usage_tracker(mocker):
return mocker.patch(
'thefuck.not_configured._get_not_configured_usage_tracker_path',
'thefuck.entrypoints.not_configured._get_not_configured_usage_tracker_path',
new_callable=MagicMock)
def _assert_tracker_updated(usage_tracker, pid):
@pytest.fixture(autouse=True)
def usage_tracker_io(usage_tracker):
io = StringIO()
usage_tracker.return_value \
.open.return_value \
.__enter__.return_value \
.write.assert_called_once_with(str(pid))
.open.return_value \
.__enter__.return_value = io
return io
def _change_tracker(usage_tracker, pid):
usage_tracker.return_value.exists.return_value = True
@pytest.fixture(autouse=True)
def usage_tracker_exists(usage_tracker):
usage_tracker.return_value \
.open.return_value \
.__enter__.return_value \
.read.return_value = str(pid)
.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',
return mocker.patch('thefuck.entrypoints.not_configured._get_shell_pid',
new_callable=MagicMock)
@pytest.fixture(autouse=True)
def shell(mocker):
shell = mocker.patch('thefuck.not_configured.shell',
shell = mocker.patch('thefuck.entrypoints.not_configured.shell',
new_callable=MagicMock)
shell.get_history.return_value = []
shell.how_to_configure.return_value = ShellConfiguration(
@@ -47,7 +63,7 @@ def shell(mocker):
@pytest.fixture(autouse=True)
def shell_config(mocker):
path_mock = mocker.patch('thefuck.not_configured.Path',
path_mock = mocker.patch('thefuck.entrypoints.not_configured.Path',
new_callable=MagicMock)
return path_mock.return_value \
.expanduser.return_value \
@@ -57,7 +73,7 @@ def shell_config(mocker):
@pytest.fixture(autouse=True)
def logs(mocker):
return mocker.patch('thefuck.not_configured.logs',
return mocker.patch('thefuck.entrypoints.not_configured.logs',
new_callable=MagicMock)
@@ -67,29 +83,28 @@ def test_for_generic_shell(shell, logs):
logs.how_to_configure_alias.assert_called_once()
def test_on_first_run(usage_tracker, shell_pid, logs):
def test_on_first_run(usage_tracker_io, usage_tracker_exists, shell_pid, logs):
shell_pid.return_value = 12
usage_tracker.return_value.exists.return_value = False
main()
_assert_tracker_updated(usage_tracker, 12)
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, shell_pid, shell, logs):
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, 12)
_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, shell_pid,
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
_change_tracker(usage_tracker, 55)
main()
_assert_tracker_updated(usage_tracker, 12)
_assert_tracker_updated(usage_tracker_io, 12)
logs.how_to_configure_alias.assert_called_once()
@@ -104,21 +119,21 @@ def test_when_cant_configure_automatically(shell_pid, shell, logs):
logs.how_to_configure_alias.assert_called_once()
def test_when_already_configured(usage_tracker, shell_pid,
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, 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_successfuly_configured(usage_tracker, shell_pid,
shell, shell_config, logs):
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, 12)
_change_tracker(usage_tracker_io, 12)
shell_config.read.return_value = ''
main()
shell_config.write.assert_any_call('eval $(thefuck --alias)')

View File

@@ -0,0 +1,20 @@
import pytest
from pytest_docker_pexpect.docker import run as pexpect_docker_run, \
stats as pexpect_docker_stats
@pytest.fixture(autouse=True)
def build_container_mock(mocker):
return mocker.patch('pytest_docker_pexpect.docker.build_container')
def run_side_effect(*args, **kwargs):
container_id = pexpect_docker_run(*args, **kwargs)
pexpect_docker_stats(container_id)
return container_id
@pytest.fixture(autouse=True)
def run_mock(mocker):
return mocker.patch('pytest_docker_pexpect.docker.run', side_effect=run_side_effect)

View File

@@ -20,10 +20,12 @@ def with_confirmation(proc, TIMEOUT):
assert proc.expect([TIMEOUT, u'test'])
def history_changed(proc, TIMEOUT, to):
def history_changed(proc, TIMEOUT, *to):
"""Ensures that history changed."""
proc.send('\033[A')
assert proc.expect([TIMEOUT, to])
pattern = [TIMEOUT]
pattern.extend(to)
assert proc.expect(pattern)
def history_not_changed(proc, TIMEOUT):
@@ -44,14 +46,14 @@ def select_command_with_arrows(proc, TIMEOUT):
proc.send('\033[B')
assert proc.expect([TIMEOUT, u'git push'])
proc.send('\033[B')
assert proc.expect([TIMEOUT, u'git help'])
assert proc.expect([TIMEOUT, u'git help', u'git hook'])
proc.send('\033[A')
assert proc.expect([TIMEOUT, u'git push'])
proc.send('\033[B')
assert proc.expect([TIMEOUT, u'git help'])
assert proc.expect([TIMEOUT, u'git help', u'git hook'])
proc.send('\n')
assert proc.expect([TIMEOUT, u'usage'])
assert proc.expect([TIMEOUT, u'usage', u'fatal: not a git repository'])
def refuse_with_confirmation(proc, TIMEOUT):

View File

@@ -3,22 +3,36 @@ 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/python3-bash',
u'FROM python:3',
u'bash'),
(u'thefuck/python2-bash',
u'FROM python:2',
u'bash'))
python_3 = (u'thefuck/python3',
u'',
u'sh')
python_2 = (u'thefuck/python2',
u'',
u'sh')
@pytest.fixture(params=containers)
init_bashrc = u'''echo '
export SHELL=/bin/bash
export PS1="$ "
echo > $HISTFILE
eval $(thefuck --alias {})
echo "instant mode ready: $THEFUCK_INSTANT_MODE"
' > ~/.bashrc'''
@pytest.fixture(params=[(python_3, False),
(python_3, True),
(python_2, False)])
def proc(request, spawnu, TIMEOUT):
proc = spawnu(*request.param)
proc.sendline(u"pip install /src")
assert proc.expect([TIMEOUT, u'Successfully installed'])
proc.sendline(u"export PS1='$ '")
proc.sendline(u'eval $(thefuck --alias)')
proc.sendline(u'echo > $HISTFILE')
container, instant_mode = request.param
proc = spawnu(*container)
proc.sendline(init_bashrc.format(
u'--enable-experimental-instant-mode' if instant_mode else ''))
proc.sendline(u"bash")
if instant_mode:
assert proc.expect([TIMEOUT, u'instant mode ready: True'])
return proc
@@ -31,7 +45,7 @@ def test_with_confirmation(proc, TIMEOUT):
@pytest.mark.functional
def test_select_command_with_arrows(proc, TIMEOUT):
select_command_with_arrows(proc, TIMEOUT)
history_changed(proc, TIMEOUT, u'git help')
history_changed(proc, TIMEOUT, u'git help', u'git hook')
@pytest.mark.functional

View File

@@ -2,29 +2,13 @@ import pytest
from tests.functional.plots import with_confirmation, without_confirmation, \
refuse_with_confirmation, select_command_with_arrows
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 fish''',
u'fish'),
('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 fish''',
u'fish'))
containers = ((u'thefuck/python3', u'', u'fish'),
(u'thefuck/python2', u'', u'fish'))
@pytest.fixture(params=containers)
def proc(request, spawnu, TIMEOUT):
proc = spawnu(*request.param)
proc.sendline(u"pip install /src")
assert proc.expect([TIMEOUT, u'Successfully installed'])
proc.sendline(u'thefuck --alias > ~/.config/fish/config.fish')
proc.sendline(u'fish')
return proc

View File

@@ -1,45 +0,0 @@
import pytest
import time
dockerfile = u'''
FROM python:3
RUN adduser --disabled-password --gecos '' test
ENV SEED "{seed}"
WORKDIR /src
USER test
RUN echo 'eval $(thefuck --alias)' > /home/test/.bashrc
RUN echo > /home/test/.bash_history
RUN git config --global user.email "you@example.com"
RUN git config --global user.name "Your Name"
USER root
'''.format(seed=time.time())
def plot(proc, TIMEOUT):
proc.sendline(u'cd /home/test/')
proc.sendline(u'fuck')
assert proc.expect([TIMEOUT, u'No fucks given'])
proc.sendline(u'git init')
proc.sendline(u'git add .')
proc.sendline(u'git commit -a -m init')
proc.sendline(u'git brnch')
proc.sendline(u'fuck')
assert proc.expect([TIMEOUT, u'git branch'])
proc.send('\n')
assert proc.expect([TIMEOUT, u'master'])
proc.sendline(u'echo test')
proc.sendline(u'echo tst')
proc.sendline(u'fuck')
assert proc.expect([TIMEOUT, u'echo test'])
proc.send('\n')
assert proc.expect([TIMEOUT, u'test'])
@pytest.mark.functional
@pytest.mark.benchmark(min_rounds=10)
def test_performance(spawnu, TIMEOUT, benchmark):
proc = spawnu(u'thefuck/python3-bash-performance',
dockerfile, u'bash')
proc.sendline(u'pip install /src')
proc.sendline(u'su test')
assert benchmark(plot, proc, TIMEOUT) is None

View File

@@ -2,23 +2,13 @@ import pytest
from tests.functional.plots import with_confirmation, without_confirmation, \
refuse_with_confirmation, select_command_with_arrows
containers = (('thefuck/python3-tcsh',
u'''FROM python:3
RUN apt-get update
RUN apt-get install -yy tcsh''',
u'tcsh'),
('thefuck/python2-tcsh',
u'''FROM python:2
RUN apt-get update
RUN apt-get install -yy tcsh''',
u'tcsh'))
containers = ((u'thefuck/python3', u'', u'tcsh'),
(u'thefuck/python2', u'', u'tcsh'))
@pytest.fixture(params=containers)
def proc(request, spawnu, TIMEOUT):
proc = spawnu(*request.param)
proc.sendline(u'pip install /src')
assert proc.expect([TIMEOUT, u'Successfully installed'])
proc.sendline(u'tcsh')
proc.sendline(u'setenv PYTHONIOENCODING utf8')
proc.sendline(u'eval `thefuck --alias`')

View File

@@ -3,29 +3,34 @@ 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/python3-zsh',
u'''FROM python:3
RUN apt-get update
RUN apt-get install -yy zsh''',
u'zsh'),
('thefuck/python2-zsh',
u'''FROM python:2
RUN apt-get update
RUN apt-get install -yy zsh''',
u'zsh'))
python_3 = (u'thefuck/python3', u'', u'sh')
python_2 = (u'thefuck/python2', u'', u'sh')
@pytest.fixture(params=containers)
init_zshrc = u'''echo '
export SHELL=/usr/bin/zsh
export HISTFILE=~/.zsh_history
echo > $HISTFILE
export SAVEHIST=100
export HISTSIZE=100
eval $(thefuck --alias {})
setopt INC_APPEND_HISTORY
echo "instant mode ready: $THEFUCK_INSTANT_MODE"
' > ~/.zshrc'''
@pytest.fixture(params=[(python_3, False),
(python_3, True),
(python_2, False)])
def proc(request, spawnu, TIMEOUT):
proc = spawnu(*request.param)
proc.sendline(u'pip install /src')
assert proc.expect([TIMEOUT, u'Successfully installed'])
proc.sendline(u'eval $(thefuck --alias)')
proc.sendline(u'export HISTFILE=~/.zsh_history')
proc.sendline(u'echo > $HISTFILE')
proc.sendline(u'export SAVEHIST=100')
proc.sendline(u'export HISTSIZE=100')
proc.sendline(u'setopt INC_APPEND_HISTORY')
container, instant_mode = request.param
proc = spawnu(*container)
proc.sendline(init_zshrc.format(
u'--enable-experimental-instant-mode' if instant_mode else ''))
proc.sendline(u"zsh")
if instant_mode:
assert proc.expect([TIMEOUT, u'instant mode ready: True'])
return proc
@@ -38,7 +43,7 @@ def test_with_confirmation(proc, TIMEOUT):
@pytest.mark.functional
def test_select_command_with_arrows(proc, TIMEOUT):
select_command_with_arrows(proc, TIMEOUT)
history_changed(proc, TIMEOUT, u'git help')
history_changed(proc, TIMEOUT, u'git help', u'git hook')
@pytest.mark.functional

View File

@@ -0,0 +1,74 @@
# -*- encoding: utf-8 -*-
import pytest
import sys
from mock import Mock, patch
from psutil import AccessDenied, TimeoutExpired
from thefuck.output_readers import rerun
class TestRerun(object):
def setup_method(self, test_method):
self.patcher = patch('thefuck.output_readers.rerun.Process')
process_mock = self.patcher.start()
self.proc_mock = process_mock.return_value = Mock()
def teardown_method(self, test_method):
self.patcher.stop()
@patch('thefuck.output_readers.rerun._wait_output', return_value=False)
@patch('thefuck.output_readers.rerun.Popen')
def test_get_output(self, popen_mock, wait_output_mock):
popen_mock.return_value.stdout.read.return_value = b'output'
assert rerun.get_output('', '') is None
wait_output_mock.assert_called_once()
@patch('thefuck.output_readers.rerun.Popen')
def test_get_output_invalid_continuation_byte(self, popen_mock):
output = b'ls: illegal option -- \xc3\nusage: ls [-@ABC...] [file ...]\n'
expected = u'ls: illegal option -- \ufffd\nusage: ls [-@ABC...] [file ...]\n'
popen_mock.return_value.stdout.read.return_value = output
actual = rerun.get_output('', '')
assert actual == expected
@pytest.mark.skipif(sys.platform == 'win32', reason="skip when running on Windows")
@patch('thefuck.output_readers.rerun._wait_output')
def test_get_output_unicode_misspell(self, wait_output_mock):
rerun.get_output(u'pácman', u'pácman')
wait_output_mock.assert_called_once()
def test_wait_output_is_slow(self, settings):
assert rerun._wait_output(Mock(), True)
self.proc_mock.wait.assert_called_once_with(settings.wait_slow_command)
def test_wait_output_is_not_slow(self, settings):
assert rerun._wait_output(Mock(), False)
self.proc_mock.wait.assert_called_once_with(settings.wait_command)
@patch('thefuck.output_readers.rerun._kill_process')
def test_wait_output_timeout(self, kill_process_mock):
self.proc_mock.wait.side_effect = TimeoutExpired(3)
self.proc_mock.children.return_value = []
assert not rerun._wait_output(Mock(), False)
kill_process_mock.assert_called_once_with(self.proc_mock)
@patch('thefuck.output_readers.rerun._kill_process')
def test_wait_output_timeout_children(self, kill_process_mock):
self.proc_mock.wait.side_effect = TimeoutExpired(3)
self.proc_mock.children.return_value = [Mock()] * 2
assert not rerun._wait_output(Mock(), False)
assert kill_process_mock.call_count == 3
def test_kill_process(self):
proc = Mock()
rerun._kill_process(proc)
proc.kill.assert_called_once_with()
@patch('thefuck.output_readers.rerun.logs')
def test_kill_process_access_denied(self, logs_mock):
proc = Mock()
proc.kill.side_effect = AccessDenied()
rerun._kill_process(proc)
proc.kill.assert_called_once_with()
logs_mock.debug.assert_called_once()

View File

@@ -0,0 +1,41 @@
import pytest
from thefuck.rules.adb_unknown_command import match, get_new_command
from thefuck.types import Command
@pytest.fixture
def output():
return '''Android Debug Bridge version 1.0.31
-d - directs command to the only connected USB device
returns an error if more than one USB device is present.
-e - directs command to the only running emulator.
returns an error if more than one emulator is running.
-s <specific device> - directs command to the device or emulator with the given
serial number or qualifier. Overrides ANDROID_SERIAL
environment variable.
'''
@pytest.mark.parametrize('script', [
('adb lgcat'),
('adb puhs')])
def test_match(output, script):
assert match(Command(script, output))
@pytest.mark.parametrize('script', [
'git branch foo',
'abd push'])
def test_not_match(script):
assert not match(Command(script, ''))
@pytest.mark.parametrize('script, new_command', [
('adb puhs test.bin /sdcard/test.bin', 'adb push test.bin /sdcard/test.bin'),
('adb -s 1111 logcta', 'adb -s 1111 logcat'),
('adb -P 666 pulll /sdcard/test.bin', 'adb -P 666 pull /sdcard/test.bin'),
('adb -d logcatt', 'adb -d logcat'),
('adb -e reboott', 'adb -e reboot')])
def test_get_new_command(script, output, new_command):
assert get_new_command(Command(script, output)) == new_command

View File

@@ -1,25 +1,25 @@
import pytest
from thefuck.rules.ag_literal import get_new_command, match
from tests.utils import Command
from thefuck.types import Command
@pytest.fixture
def stderr():
def output():
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 \\('])
def test_match(script, output):
assert match(Command(script, output))
@pytest.mark.parametrize('script', ['ag foo'])
def test_not_match(script):
assert not match(Command(script=script))
assert not match(Command(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
('ag \\(', 'ag -Q \\(')])
def test_get_new_command(script, new_cmd, output):
assert get_new_command((Command(script, output))) == new_cmd

View File

@@ -1,55 +1,53 @@
import pytest
from thefuck.rules.apt_get import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.mark.parametrize('command, packages', [
(Command(script='vim', stderr='vim: command not found'),
(Command('vim', 'vim: command not found'),
[('vim', 'main'), ('vim-tiny', 'main')]),
(Command(script='sudo vim', stderr='vim: command not found'),
(Command('sudo vim', '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"),
(Command('vim', "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)
mock = mocker.patch('thefuck.rules.apt_get.command_not_found',
create=True)
mock.getPackages.return_value = packages
mocker.patch('thefuck.rules.apt_get._get_packages',
create=True, return_value=packages)
assert match(command)
@pytest.mark.parametrize('command, packages, which', [
(Command(script='a_bad_cmd', stderr='a_bad_cmd: command not found'),
(Command('a_bad_cmd', 'a_bad_cmd: command not found'),
[], None),
(Command(script='vim', stderr=''), [], None),
(Command(), [], None),
(Command(script='vim', stderr='vim: command not found'),
(Command('vim', ''), [], None),
(Command('', ''), [], None),
(Command('vim', 'vim: command not found'),
['vim'], '/usr/bin/vim'),
(Command(script='sudo vim', stderr='vim: command not found'),
(Command('sudo vim', 'vim: command not found'),
['vim'], '/usr/bin/vim')])
def test_not_match(mocker, command, packages, which):
mocker.patch('thefuck.rules.apt_get.which', return_value=which)
mock = mocker.patch('thefuck.rules.apt_get.command_not_found',
create=True)
mock.getPackages.return_value = packages
mocker.patch('thefuck.rules.apt_get._get_packages',
create=True, return_value=packages)
assert not match(command)
@pytest.mark.parametrize('command, new_command, packages', [
(Command('vim'), 'sudo apt-get install vim && vim',
(Command('vim', ''), 'sudo apt-get install vim && vim',
[('vim', 'main'), ('vim-tiny', 'main')]),
(Command('convert'), 'sudo apt-get install imagemagick && convert',
(Command('convert', ''), 'sudo apt-get install imagemagick && convert',
[('imagemagick', 'main'),
('graphicsmagick-imagemagick-compat', 'universe')]),
(Command('sudo vim'), 'sudo apt-get install vim && sudo vim',
(Command('sudo vim', ''), 'sudo apt-get install vim && sudo vim',
[('vim', 'main'), ('vim-tiny', 'main')]),
(Command('sudo convert'), 'sudo apt-get install imagemagick && sudo convert',
(Command('sudo convert', ''), 'sudo apt-get install imagemagick && sudo convert',
[('imagemagick', 'main'),
('graphicsmagick-imagemagick-compat', 'universe')])])
def test_get_new_command(mocker, command, new_command, packages):
mock = mocker.patch('thefuck.rules.apt_get.command_not_found',
create=True)
mock.getPackages.return_value = packages
mocker.patch('thefuck.rules.apt_get._get_packages',
create=True, return_value=packages)
assert get_new_command(command) == new_command

View File

@@ -1,25 +1,26 @@
import pytest
from thefuck.rules.apt_get_search import get_new_command, match
from tests.utils import Command
from thefuck.types import Command
def test_match():
assert match(Command('apt-get search foo'))
assert match(Command('apt-get search foo', ''))
@pytest.mark.parametrize('command', [
Command('apt-cache search foo'),
Command('aptitude search foo'),
Command('apt search foo'),
Command('apt-get install foo'),
Command('apt-get source foo'),
Command('apt-get clean'),
Command('apt-get remove'),
Command('apt-get update')
Command('apt-cache search foo', ''),
Command('aptitude search foo', ''),
Command('apt search foo', ''),
Command('apt-get install foo', ''),
Command('apt-get source foo', ''),
Command('apt-get clean', ''),
Command('apt-get remove', ''),
Command('apt-get update', '')
])
def test_not_match(command):
assert not match(command)
def test_get_new_command():
assert get_new_command(Command('apt-get search foo')) == 'apt-cache search foo'
new_command = get_new_command(Command('apt-get search foo', ''))
assert new_command == 'apt-cache search foo'

View File

@@ -1,6 +1,6 @@
from io import BytesIO
import pytest
from tests.utils import Command
from thefuck.types import Command
from thefuck.rules.apt_invalid_operation import match, get_new_command, \
_get_operations
@@ -76,20 +76,59 @@ apt_get_operations = ['update', 'upgrade', 'install', 'remove', 'autoremove',
'dselect-upgrade', 'clean', 'autoclean', 'check',
'changelog', 'download']
new_apt_get_help = b'''apt 1.6.12 (amd64)
Usage: apt-get [options] command
apt-get [options] install|remove pkg1 [pkg2 ...]
apt-get [options] source pkg1 [pkg2 ...]
@pytest.mark.parametrize('script, stderr', [
apt-get is a command line interface for retrieval of packages
and information about them from authenticated sources and
for installation, upgrade and removal of packages together
with their dependencies.
Most used commands:
update - Retrieve new lists of packages
upgrade - Perform an upgrade
install - Install new packages (pkg is libc6 not libc6.deb)
remove - Remove packages
purge - Remove packages and config files
autoremove - Remove automatically all unused packages
dist-upgrade - Distribution upgrade, see apt-get(8)
dselect-upgrade - Follow dselect selections
build-dep - Configure build-dependencies for source packages
clean - Erase downloaded archive files
autoclean - Erase old downloaded archive files
check - Verify that there are no broken dependencies
source - Download source archives
download - Download the binary package into the current directory
changelog - Download and display the changelog for the given package
See apt-get(8) for more information about the available commands.
Configuration options and syntax is detailed in apt.conf(5).
Information about how to configure sources can be found in sources.list(5).
Package and version choices can be expressed via apt_preferences(5).
Security details are available in apt-secure(8).
This APT has Super Cow Powers.
'''
new_apt_get_operations = ['update', 'upgrade', 'install', 'remove', 'purge',
'autoremove', 'dist-upgrade', 'dselect-upgrade',
'build-dep', 'clean', 'autoclean', 'check',
'source', 'download', 'changelog']
@pytest.mark.parametrize('script, output', [
('apt', invalid_operation('saerch')),
('apt-get', invalid_operation('isntall')),
('apt-cache', invalid_operation('rumove'))])
def test_match(script, stderr):
assert match(Command(script, stderr=stderr))
def test_match(script, output):
assert match(Command(script, output))
@pytest.mark.parametrize('script, stderr', [
@pytest.mark.parametrize('script, output', [
('vim', invalid_operation('vim')),
('apt-get', "")])
def test_not_match(script, stderr):
assert not match(Command(script, stderr=stderr))
def test_not_match(script, output):
assert not match(Command(script, output))
@pytest.fixture
@@ -104,19 +143,22 @@ def set_help(mocker):
@pytest.mark.parametrize('app, help_text, operations', [
('apt', apt_help, apt_operations),
('apt-get', apt_get_help, apt_get_operations)
('apt-get', apt_get_help, apt_get_operations),
('apt-get', new_apt_get_help, new_apt_get_operations)
])
def test_get_operations(set_help, app, help_text, operations):
set_help(help_text)
assert _get_operations(app) == operations
@pytest.mark.parametrize('script, stderr, help_text, result', [
@pytest.mark.parametrize('script, output, help_text, result', [
('apt-get isntall vim', invalid_operation('isntall'),
apt_get_help, 'apt-get install vim'),
('apt saerch vim', invalid_operation('saerch'),
apt_help, 'apt search vim'),
('apt uninstall vim', invalid_operation('uninstall'),
apt_help, 'apt remove vim'),
])
def test_get_new_command(set_help, stderr, script, help_text, result):
def test_get_new_command(set_help, output, script, help_text, result):
set_help(help_text)
assert get_new_command(Command(script, stderr=stderr))[0] == result
assert get_new_command(Command(script, output))[0] == result

View File

@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
import pytest
from thefuck.rules.apt_list_upgradable import get_new_command, match
from thefuck.types import Command
full_english_output = '''
Hit:1 http://us.archive.ubuntu.com/ubuntu zesty InRelease
Hit:2 http://us.archive.ubuntu.com/ubuntu zesty-updates InRelease
Get:3 http://us.archive.ubuntu.com/ubuntu zesty-backports InRelease [89.2 kB]
Hit:4 http://security.ubuntu.com/ubuntu zesty-security InRelease
Hit:5 http://ppa.launchpad.net/ubuntu-mozilla-daily/ppa/ubuntu zesty InRelease
Hit:6 https://download.docker.com/linux/ubuntu zesty InRelease
Hit:7 https://cli-assets.heroku.com/branches/stable/apt ./ InRelease
Fetched 89.2 kB in 0s (122 kB/s)
Reading package lists... Done
Building dependency tree
Reading state information... Done
8 packages can be upgraded. Run 'apt list --upgradable' to see them.
'''
match_output = [
full_english_output,
'Führen Sie »apt list --upgradable« aus, um sie anzuzeigen.' # German
]
no_match_output = '''
Hit:1 http://us.archive.ubuntu.com/ubuntu zesty InRelease
Get:2 http://us.archive.ubuntu.com/ubuntu zesty-updates InRelease [89.2 kB]
Get:3 http://us.archive.ubuntu.com/ubuntu zesty-backports InRelease [89.2 kB]
Get:4 http://security.ubuntu.com/ubuntu zesty-security InRelease [89.2 kB]
Hit:5 https://cli-assets.heroku.com/branches/stable/apt ./ InRelease
Hit:6 http://ppa.launchpad.net/ubuntu-mozilla-daily/ppa/ubuntu zesty InRelease
Hit:7 https://download.docker.com/linux/ubuntu zesty InRelease
Get:8 http://us.archive.ubuntu.com/ubuntu zesty-updates/main i386 Packages [232 kB]
Get:9 http://us.archive.ubuntu.com/ubuntu zesty-updates/main amd64 Packages [235 kB]
Get:10 http://us.archive.ubuntu.com/ubuntu zesty-updates/main amd64 DEP-11 Metadata [55.2 kB]
Get:11 http://us.archive.ubuntu.com/ubuntu zesty-updates/main DEP-11 64x64 Icons [32.3 kB]
Get:12 http://us.archive.ubuntu.com/ubuntu zesty-updates/universe amd64 Packages [156 kB]
Get:13 http://us.archive.ubuntu.com/ubuntu zesty-updates/universe i386 Packages [156 kB]
Get:14 http://us.archive.ubuntu.com/ubuntu zesty-updates/universe amd64 DEP-11 Metadata [175 kB]
Get:15 http://us.archive.ubuntu.com/ubuntu zesty-updates/universe DEP-11 64x64 Icons [253 kB]
Get:16 http://us.archive.ubuntu.com/ubuntu zesty-updates/multiverse amd64 DEP-11 Metadata [5,840 B]
Get:17 http://us.archive.ubuntu.com/ubuntu zesty-backports/universe amd64 DEP-11 Metadata [4,588 B]
Get:18 http://security.ubuntu.com/ubuntu zesty-security/main amd64 DEP-11 Metadata [12.7 kB]
Get:19 http://security.ubuntu.com/ubuntu zesty-security/main DEP-11 64x64 Icons [17.6 kB]
Get:20 http://security.ubuntu.com/ubuntu zesty-security/universe amd64 DEP-11 Metadata [21.6 kB]
Get:21 http://security.ubuntu.com/ubuntu zesty-security/universe DEP-11 64x64 Icons [47.7 kB]
Get:22 http://security.ubuntu.com/ubuntu zesty-security/multiverse amd64 DEP-11 Metadata [208 B]
Fetched 1,673 kB in 0s (1,716 kB/s)
Reading package lists... Done
Building dependency tree
Reading state information... Done
All packages are up to date.
'''
@pytest.mark.parametrize('output', match_output)
def test_match(output):
assert match(Command('sudo apt update', output))
@pytest.mark.parametrize('command', [
Command('apt-cache search foo', ''),
Command('aptitude search foo', ''),
Command('apt search foo', ''),
Command('apt-get install foo', ''),
Command('apt-get source foo', ''),
Command('apt-get clean', ''),
Command('apt-get remove', ''),
Command('apt-get update', ''),
Command('sudo apt update', no_match_output)
])
def test_not_match(command):
assert not match(command)
@pytest.mark.parametrize('output', match_output)
def test_get_new_command(output):
new_command = get_new_command(Command('sudo apt update', output))
assert new_command == 'sudo apt list --upgradable'
new_command = get_new_command(Command('apt update', output))
assert new_command == 'apt list --upgradable'

View File

@@ -0,0 +1,36 @@
import pytest
from thefuck.rules.apt_upgrade import get_new_command, match
from thefuck.types import Command
match_output = '''
Listing... Done
heroku/stable 6.15.2-1 amd64 [upgradable from: 6.14.43-1]
resolvconf/zesty-updates,zesty-updates 1.79ubuntu4.1 all [upgradable from: 1.79ubuntu4]
squashfs-tools/zesty-updates 1:4.3-3ubuntu2.17.04.1 amd64 [upgradable from: 1:4.3-3ubuntu2]
unattended-upgrades/zesty-updates,zesty-updates 0.93.1ubuntu2.4 all [upgradable from: 0.93.1ubuntu2.3]
'''
no_match_output = '''
Listing... Done
'''
def test_match():
assert match(Command('apt list --upgradable', match_output))
assert match(Command('sudo apt list --upgradable', match_output))
@pytest.mark.parametrize('command', [
Command('apt list --upgradable', no_match_output),
Command('sudo apt list --upgradable', no_match_output)
])
def test_not_match(command):
assert not match(command)
def test_get_new_command():
new_command = get_new_command(Command('apt list --upgradable', match_output))
assert new_command == 'apt upgrade'
new_command = get_new_command(Command('sudo apt list --upgradable', match_output))
assert new_command == 'sudo apt upgrade'

View File

@@ -1,7 +1,7 @@
import pytest
from thefuck.rules.aws_cli import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
no_suggestions = '''\
@@ -77,25 +77,25 @@ Invalid choice: 't-item', maybe you meant:
@pytest.mark.parametrize('command', [
Command('aws dynamdb scan', stderr=misspelled_command),
Command('aws dynamodb scn', stderr=misspelled_subcommand),
Command('aws dynamdb scan', misspelled_command),
Command('aws dynamodb scn', misspelled_subcommand),
Command('aws dynamodb t-item',
stderr=misspelled_subcommand_with_multiple_options)])
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))
assert not match(Command('aws dynamodb invalid', no_suggestions))
@pytest.mark.parametrize('command, result', [
(Command('aws dynamdb scan', stderr=misspelled_command),
(Command('aws dynamdb scan', misspelled_command),
['aws dynamodb scan']),
(Command('aws dynamodb scn', stderr=misspelled_subcommand),
(Command('aws dynamodb scn', misspelled_subcommand),
['aws dynamodb scan']),
(Command('aws dynamodb t-item',
stderr=misspelled_subcommand_with_multiple_options),
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

View File

@@ -0,0 +1,44 @@
import pytest
from thefuck.rules.az_cli import match, get_new_command
from thefuck.types import Command
no_suggestions = '''\
az provider: error: the following arguments are required: _subcommand
usage: az provider [-h] {list,show,register,unregister,operation} ...
'''
misspelled_command = '''\
az: 'providers' is not in the 'az' command group. See 'az --help'.
The most similar choice to 'providers' is:
provider
'''
misspelled_subcommand = '''\
az provider: 'lis' is not in the 'az provider' command group. See 'az provider --help'.
The most similar choice to 'lis' is:
list
'''
@pytest.mark.parametrize('command', [
Command('az providers', misspelled_command),
Command('az provider lis', misspelled_subcommand)])
def test_match(command):
assert match(command)
def test_not_match():
assert not match(Command('az provider', no_suggestions))
@pytest.mark.parametrize('command, result', [
(Command('az providers list', misspelled_command), ['az provider list']),
(Command('az provider lis', misspelled_subcommand), ['az provider list'])
])
def test_get_new_command(command, result):
assert get_new_command(command) == result

View File

@@ -0,0 +1,35 @@
import pytest
from thefuck.rules.brew_cask_dependency import match, get_new_command
from thefuck.types import Command
output = '''sshfs: OsxfuseRequirement unsatisfied!
You can install with Homebrew-Cask:
brew cask install osxfuse
You can download from:
https://osxfuse.github.io/
Error: An unsatisfied requirement failed this build.'''
def test_match():
command = Command('brew install sshfs', output)
assert match(command)
@pytest.mark.parametrize('script, output', [
('brew link sshfs', output),
('cat output', output),
('brew install sshfs', '')])
def test_not_match(script, output):
command = Command(script, output)
assert not match(command)
@pytest.mark.parametrize('before, after', [
('brew install sshfs',
'brew cask install osxfuse && brew install sshfs')])
def test_get_new_command(before, after):
command = Command(before, output)
assert get_new_command(command) == after

View File

@@ -1,17 +1,26 @@
import pytest
from thefuck.rules.brew_install import match, get_new_command
from thefuck.rules.brew_install import _get_formulas
from tests.utils import Command
from thefuck.rules.brew_install import match, get_new_command, _get_suggestions
from thefuck.types import Command
@pytest.fixture
def brew_no_available_formula():
return '''Error: No available formula for elsticsearch '''
def brew_no_available_formula_one():
return '''Warning: No available formula with the name "giss". Did you mean gist?'''
@pytest.fixture
def brew_no_available_formula_two():
return '''Warning: No available formula with the name "elasticserar". Did you mean elasticsearch or elasticsearch@6?'''
@pytest.fixture
def brew_no_available_formula_three():
return '''Warning: No available formula with the name "gitt". Did you mean git, gitg or gist?'''
@pytest.fixture
def brew_install_no_argument():
return '''This command requires a formula argument'''
return '''Install a formula or cask. Additional options specific to a formula may be'''
@pytest.fixture
@@ -19,28 +28,38 @@ def brew_already_installed():
return '''Warning: git-2.3.5 already installed'''
def _is_not_okay_to_test():
return 'elasticsearch' not in _get_formulas()
def test_suggestions():
assert _get_suggestions("one") == ['one']
assert _get_suggestions("one or two") == ['one', 'two']
assert _get_suggestions("one, two or three") == ['one', 'two', 'three']
@pytest.mark.skipif(_is_not_okay_to_test(),
reason='No need to run if there\'s no formula')
def test_match(brew_no_available_formula, brew_already_installed,
def test_match(brew_no_available_formula_one, brew_no_available_formula_two,
brew_no_available_formula_three, brew_already_installed,
brew_install_no_argument):
assert match(Command('brew install elsticsearch',
stderr=brew_no_available_formula))
assert match(Command('brew install giss',
brew_no_available_formula_one))
assert match(Command('brew install elasticserar',
brew_no_available_formula_two))
assert match(Command('brew install gitt',
brew_no_available_formula_three))
assert not match(Command('brew install git',
stderr=brew_already_installed))
assert not match(Command('brew install', stderr=brew_install_no_argument))
brew_already_installed))
assert not match(Command('brew install', brew_install_no_argument))
@pytest.mark.skipif(_is_not_okay_to_test(),
reason='No need to run if there\'s no formula')
def test_get_new_command(brew_no_available_formula):
assert get_new_command(Command('brew install elsticsearch',
stderr=brew_no_available_formula))\
== 'brew install elasticsearch'
def test_get_new_command(brew_no_available_formula_one, brew_no_available_formula_two,
brew_no_available_formula_three):
assert get_new_command(Command('brew install giss',
brew_no_available_formula_one))\
== ['brew install gist']
assert get_new_command(Command('brew install elasticsear',
brew_no_available_formula_two))\
== ['brew install elasticsearch', 'brew install elasticsearch@6']
assert get_new_command(Command('brew install gitt',
brew_no_available_formula_three))\
== ['brew install git', 'brew install gitg', 'brew install gist']
assert get_new_command(Command('brew install aa',
stderr=brew_no_available_formula))\
brew_no_available_formula_one))\
!= 'brew install aha'

View File

@@ -1,10 +1,10 @@
import pytest
from tests.utils import Command
from thefuck.types import Command
from thefuck.rules.brew_link import get_new_command, match
@pytest.fixture
def stderr():
def output():
return ("Error: Could not symlink bin/gcp\n"
"Target /usr/local/bin/gcp\n"
"already exists. You may want to remove it:\n"
@@ -23,16 +23,15 @@ def new_command(formula):
@pytest.mark.parametrize('script', ['brew link coreutils', 'brew ln coreutils'])
def test_match(stderr, script):
assert match(Command(script=script, stderr=stderr))
def test_match(output, script):
assert match(Command(script, output))
@pytest.mark.parametrize('script', ['brew link coreutils'])
def test_not_match(script):
stderr = ''
assert not match(Command(script=script, stderr=stderr))
assert not match(Command(script, ''))
@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
def test_get_new_command(output, new_command, script, formula):
assert get_new_command(Command(script, output)) == new_command

View File

@@ -0,0 +1,28 @@
import pytest
from thefuck.types import Command
from thefuck.rules.brew_reinstall import get_new_command, match
output = ("Warning: thefuck 9.9 is already installed and up-to-date\nTo "
"reinstall 9.9, run `brew reinstall thefuck`")
def test_match():
command = Command('brew install thefuck', output)
assert match(command)
@pytest.mark.parametrize('script', [
'brew reinstall thefuck',
'brew install foo'])
def test_not_match(script):
assert not match(Command(script, ''))
@pytest.mark.parametrize('script, formula, ', [
('brew install foo', 'foo'),
('brew install bar zap', 'bar zap')])
def test_get_new_command(script, formula):
command = Command(script, output)
new_command = 'brew reinstall {}'.format(formula)
assert get_new_command(command) == new_command

View File

@@ -1,10 +1,10 @@
import pytest
from tests.utils import Command
from thefuck.types import Command
from thefuck.rules.brew_uninstall import get_new_command, match
@pytest.fixture
def stdout():
def output():
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")
@@ -16,16 +16,16 @@ def new_command(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))
def test_match(output, script):
assert match(Command(script, output))
@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))
output = 'Uninstalling /usr/local/Cellar/gnuplot/5.0.4_1... (44 files, 2.3M)\n'
assert not match(Command(script, output))
@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
def test_get_new_command(output, new_command, script, formula):
assert get_new_command(Command(script, output)) == new_command

View File

@@ -1,7 +1,7 @@
import pytest
from thefuck.rules.brew_unknown_command import match, get_new_command
from thefuck.rules.brew_unknown_command import _brew_commands
from tests.utils import Command
from thefuck.types import Command
@pytest.fixture
@@ -15,15 +15,15 @@ def brew_unknown_cmd2():
def test_match(brew_unknown_cmd):
assert match(Command('brew inst', stderr=brew_unknown_cmd))
assert match(Command('brew inst', brew_unknown_cmd))
for command in _brew_commands():
assert not match(Command('brew ' + command))
assert not match(Command('brew ' + command, ''))
def test_get_new_command(brew_unknown_cmd, brew_unknown_cmd2):
assert (get_new_command(Command('brew inst', stderr=brew_unknown_cmd))
assert (get_new_command(Command('brew inst', brew_unknown_cmd))
== ['brew list', 'brew install', 'brew uninstall'])
cmds = get_new_command(Command('brew instaa', stderr=brew_unknown_cmd2))
cmds = get_new_command(Command('brew instaa', brew_unknown_cmd2))
assert 'brew install' in cmds
assert 'brew uninstall' in cmds

View File

@@ -1,30 +1,28 @@
import pytest
from tests.utils import Command
from thefuck.types import Command
from thefuck.rules.brew_update_formula import get_new_command, match
@pytest.fixture
def stderr():
return ("Error: This command updates brew itself, and does not take formula"
" names.\nUse 'brew upgrade <formula>'.")
output = ("Error: This command updates brew itself, and does not take formula"
" names.\nUse `brew upgrade thefuck`.")
@pytest.fixture
def new_command(formula):
return 'brew upgrade {}'.format(formula)
def test_match():
command = Command('brew update thefuck', output)
assert match(command)
@pytest.mark.parametrize('script', ['brew update foo', 'brew update bar zap'])
def test_match(stderr, script):
assert match(Command(script=script, stderr=stderr))
@pytest.mark.parametrize('script', ['brew upgrade foo', 'brew update'])
@pytest.mark.parametrize('script', [
'brew upgrade foo',
'brew update'])
def test_not_match(script):
assert not match(Command(script=script, stderr=''))
assert not match(Command(script, ''))
@pytest.mark.parametrize('script, formula, ', [
('brew update foo', 'foo'), ('brew update bar zap', 'bar zap')])
def test_get_new_command(stderr, new_command, script, formula):
assert get_new_command(Command(script=script, stderr=stderr)) == new_command
('brew update foo', 'foo'),
('brew update bar zap', 'bar zap')])
def test_get_new_command(script, formula):
command = Command(script, output)
new_command = 'brew upgrade {}'.format(formula)
assert get_new_command(command) == new_command

View File

@@ -1,15 +0,0 @@
import pytest
from thefuck.rules.brew_upgrade import match, get_new_command
from tests.utils import Command
@pytest.mark.parametrize('command', [
Command(script='brew upgrade')])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('brew upgrade'), 'brew upgrade --all')])
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command

View File

@@ -1,6 +1,6 @@
import pytest
from thefuck.rules.cargo_no_command import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
no_such_subcommand_old = """No such subcommand
@@ -15,14 +15,14 @@ no_such_subcommand = """error: no such subcommand
@pytest.mark.parametrize('command', [
Command(script='cargo buid', stderr=no_such_subcommand_old),
Command(script='cargo buils', stderr=no_such_subcommand)])
Command('cargo buid', no_such_subcommand_old),
Command('cargo buils', no_such_subcommand)])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('cargo buid', stderr=no_such_subcommand_old), 'cargo build'),
(Command('cargo buils', stderr=no_such_subcommand), 'cargo build')])
(Command('cargo buid', no_such_subcommand_old), 'cargo build'),
(Command('cargo buils', no_such_subcommand), 'cargo build')])
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command

View File

@@ -0,0 +1,39 @@
import pytest
from thefuck.rules.cat_dir import match, get_new_command
from thefuck.types import Command
@pytest.fixture
def isdir(mocker):
return mocker.patch('thefuck.rules.cat_dir'
'.os.path.isdir')
@pytest.mark.parametrize('command', [
Command('cat foo', 'cat: foo: Is a directory\n'),
Command('cat /foo/bar/', 'cat: /foo/bar/: Is a directory\n'),
Command('cat cat/', 'cat: cat/: Is a directory\n'),
])
def test_match(command, isdir):
isdir.return_value = True
assert match(command)
@pytest.mark.parametrize('command', [
Command('cat foo', 'foo bar baz'),
Command('cat foo bar', 'foo bar baz'),
Command('notcat foo bar', 'some output'),
])
def test_not_match(command, isdir):
isdir.return_value = False
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('cat foo', 'cat: foo: Is a directory\n'), 'ls foo'),
(Command('cat /foo/bar/', 'cat: /foo/bar/: Is a directory\n'), 'ls /foo/bar/'),
(Command('cat cat', 'cat: cat: Is a directory\n'), 'ls cat'),
])
def test_get_new_command(command, new_command):
isdir.return_value = True
assert get_new_command(command) == new_command

View File

@@ -0,0 +1,23 @@
import pytest
from thefuck.rules.cd_correction import match
from thefuck.types import Command
@pytest.mark.parametrize('command', [
Command('cd foo', 'cd: foo: No such file or directory'),
Command('cd foo/bar/baz',
'cd: foo: No such file or directory'),
Command('cd foo/bar/baz', 'cd: can\'t cd to foo/bar/baz'),
Command('cd /foo/bar/', 'cd: The directory "/foo/bar/" does not exist')])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command', [
Command('cd foo', ''), Command('', '')])
def test_not_match(command):
assert not match(command)
# Note that get_new_command uses local filesystem, so not testing it here.
# Instead, see the functional test `functional.test_cd_correction`

11
tests/rules/test_cd_cs.py Normal file
View File

@@ -0,0 +1,11 @@
from thefuck.rules.cd_cs import match, get_new_command
from thefuck.types import Command
def test_match():
assert match(Command('cs', 'cs: command not found'))
assert match(Command('cs /etc/', 'cs: command not found'))
def test_get_new_command():
assert get_new_command(Command('cs /etc/', 'cs: command not found')) == 'cd /etc/'

View File

@@ -1,25 +1,26 @@
import pytest
from thefuck.rules.cd_mkdir import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.mark.parametrize('command', [
Command(script='cd foo', stderr='cd: foo: No such file or directory'),
Command(script='cd foo/bar/baz',
stderr='cd: foo: No such file or directory'),
Command(script='cd foo/bar/baz', stderr='cd: can\'t cd to foo/bar/baz')])
Command('cd foo', 'cd: foo: No such file or directory'),
Command('cd foo/bar/baz',
'cd: foo: No such file or directory'),
Command('cd foo/bar/baz', 'cd: can\'t cd to foo/bar/baz'),
Command('cd /foo/bar/', 'cd: The directory "/foo/bar/" does not exist')])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command', [
Command(script='cd foo', stderr=''), Command()])
Command('cd foo', ''), Command('', '')])
def test_not_match(command):
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('cd foo'), 'mkdir -p foo && cd foo'),
(Command('cd foo/bar/baz'), 'mkdir -p foo/bar/baz && cd foo/bar/baz')])
(Command('cd foo', ''), 'mkdir -p foo && cd foo'),
(Command('cd foo/bar/baz', ''), 'mkdir -p foo/bar/baz && cd foo/bar/baz')])
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command

View File

@@ -1,12 +1,11 @@
from thefuck.rules.cd_parent import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
def test_match():
assert match(Command('cd..', stderr='cd..: command not found'))
assert not match(Command())
assert match(Command('cd..', 'cd..: command not found'))
assert not match(Command('', ''))
def test_get_new_command():
assert get_new_command(
Command('cd..')) == 'cd ..'
assert get_new_command(Command('cd..', '')) == 'cd ..'

View File

@@ -1,5 +1,5 @@
import pytest
from tests.utils import Command
from thefuck.types import Command
from thefuck.rules.chmod_x import match, get_new_command
@@ -14,26 +14,26 @@ def file_access(mocker):
@pytest.mark.usefixtures('file_exists', 'file_access')
@pytest.mark.parametrize('script, stderr', [
@pytest.mark.parametrize('script, output', [
('./gradlew build', 'gradlew: Permission denied'),
('./install.sh --help', 'install.sh: permission denied')])
def test_match(script, stderr):
assert match(Command(script, stderr=stderr))
def test_match(script, output):
assert match(Command(script, output))
@pytest.mark.parametrize('script, stderr, exists, callable', [
@pytest.mark.parametrize('script, output, exists, callable', [
('./gradlew build', 'gradlew: Permission denied', True, True),
('./gradlew build', 'gradlew: Permission denied', False, False),
('./gradlew build', 'gradlew: error', True, False),
('gradlew build', 'gradlew: Permission denied', True, False)])
def test_not_match(file_exists, file_access, script, stderr, exists, callable):
def test_not_match(file_exists, file_access, script, output, exists, callable):
file_exists.return_value = exists
file_access.return_value = callable
assert not match(Command(script, stderr=stderr))
assert not match(Command(script, output))
@pytest.mark.parametrize('script, result', [
('./gradlew build', 'chmod +x gradlew && ./gradlew build'),
('./install.sh --help', 'chmod +x install.sh && ./install.sh --help')])
def test_get_new_command(script, result):
assert get_new_command(Command(script)) == result
assert get_new_command(Command(script, '')) == result

View File

@@ -0,0 +1,86 @@
import pytest
from thefuck.rules.choco_install import match, get_new_command
from thefuck.types import Command
package_not_found_error = (
'Chocolatey v0.10.15\n'
'Installing the following packages:\n'
'logstitcher\n'
'By installing you accept licenses for the packages.\n'
'logstitcher not installed. The package was not found with the source(s) listed.\n'
' Source(s): \'https://chocolatey.org/api/v2/\'\n'
' NOTE: When you specify explicit sources, it overrides default sources.\n'
'If the package version is a prerelease and you didn\'t specify `--pre`,\n'
' the package may not be found.\n'
'Please see https://chocolatey.org/docs/troubleshooting for more\n'
' assistance.\n'
'\n'
'Chocolatey installed 0/1 packages. 1 packages failed.\n'
' See the log for details (C:\\ProgramData\\chocolatey\\logs\\chocolatey.log).\n'
'\n'
'Failures\n'
' - logstitcher - logstitcher not installed. The package was not found with the source(s) listed.\n'
' Source(s): \'https://chocolatey.org/api/v2/\'\n'
' NOTE: When you specify explicit sources, it overrides default sources.\n'
'If the package version is a prerelease and you didn\'t specify `--pre`,\n'
' the package may not be found.\n'
'Please see https://chocolatey.org/docs/troubleshooting for more\n'
' assistance.\n'
)
@pytest.mark.parametrize('command', [
Command('choco install logstitcher', package_not_found_error),
Command('cinst logstitcher', package_not_found_error),
Command('choco install logstitcher -y', package_not_found_error),
Command('cinst logstitcher -y', package_not_found_error),
Command('choco install logstitcher -y -n=test', package_not_found_error),
Command('cinst logstitcher -y -n=test', package_not_found_error),
Command('choco install logstitcher -y -n=test /env', package_not_found_error),
Command('cinst logstitcher -y -n=test /env', package_not_found_error),
Command('choco install chocolatey -y', package_not_found_error),
Command('cinst chocolatey -y', package_not_found_error)])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command', [
Command('choco /?', ''),
Command('choco upgrade logstitcher', ''),
Command('cup logstitcher', ''),
Command('choco upgrade logstitcher -y', ''),
Command('cup logstitcher -y', ''),
Command('choco upgrade logstitcher -y -n=test', ''),
Command('cup logstitcher -y -n=test', ''),
Command('choco upgrade logstitcher -y -n=test /env', ''),
Command('cup logstitcher -y -n=test /env', ''),
Command('choco upgrade chocolatey -y', ''),
Command('cup chocolatey -y', ''),
Command('choco uninstall logstitcher', ''),
Command('cuninst logstitcher', ''),
Command('choco uninstall logstitcher -y', ''),
Command('cuninst logstitcher -y', ''),
Command('choco uninstall logstitcher -y -n=test', ''),
Command('cuninst logstitcher -y -n=test', ''),
Command('choco uninstall logstitcher -y -n=test /env', ''),
Command('cuninst logstitcher -y -n=test /env', ''),
Command('choco uninstall chocolatey -y', ''),
Command('cuninst chocolatey -y', '')])
def not_test_match(command):
assert not match(command)
@pytest.mark.parametrize('before, after', [
('choco install logstitcher', 'choco install logstitcher.install'),
('cinst logstitcher', 'cinst logstitcher.install'),
('choco install logstitcher -y', 'choco install logstitcher.install -y'),
('cinst logstitcher -y', 'cinst logstitcher.install -y'),
('choco install logstitcher -y -n=test', 'choco install logstitcher.install -y -n=test'),
('cinst logstitcher -y -n=test', 'cinst logstitcher.install -y -n=test'),
('choco install logstitcher -y -n=test /env', 'choco install logstitcher.install -y -n=test /env'),
('cinst logstitcher -y -n=test /env', 'cinst logstitcher.install -y -n=test /env'),
('choco install chocolatey -y', 'choco install chocolatey.install -y'),
('cinst chocolatey -y', 'cinst chocolatey.install -y'), ])
def test_get_new_command(before, after):
assert (get_new_command(Command(before, '')) == after)

View File

@@ -1,6 +1,6 @@
import pytest
from thefuck.rules.composer_not_command import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.fixture
@@ -39,18 +39,28 @@ def composer_not_command_one_of_this():
)
def test_match(composer_not_command, composer_not_command_one_of_this):
@pytest.fixture
def composer_require_instead_of_install():
return 'Invalid argument package. Use "composer require package" instead to add packages to your composer.json.'
def test_match(composer_not_command, composer_not_command_one_of_this, composer_require_instead_of_install):
assert match(Command('composer udpate',
stderr=composer_not_command))
composer_not_command))
assert match(Command('composer pdate',
stderr=composer_not_command_one_of_this))
assert not match(Command('ls update', stderr=composer_not_command))
composer_not_command_one_of_this))
assert match(Command('composer install package',
composer_require_instead_of_install))
assert not match(Command('ls update', composer_not_command))
def test_get_new_command(composer_not_command, composer_not_command_one_of_this):
def test_get_new_command(composer_not_command, composer_not_command_one_of_this, composer_require_instead_of_install):
assert (get_new_command(Command('composer udpate',
stderr=composer_not_command))
composer_not_command))
== 'composer update')
assert (get_new_command(Command('composer pdate',
stderr=composer_not_command_one_of_this))
composer_not_command_one_of_this))
== 'composer selfupdate')
assert (get_new_command(Command('composer install package',
composer_require_instead_of_install))
== 'composer require package')

View File

@@ -0,0 +1,24 @@
import pytest
from thefuck.rules.conda_mistype import match, get_new_command
from thefuck.types import Command
@pytest.fixture
def mistype_response():
return """
CommandNotFoundError: No command 'conda lst'.
Did you mean 'conda list'?
"""
def test_match(mistype_response):
assert match(Command('conda lst', mistype_response))
err_response = 'bash: codna: command not found'
assert not match(Command('codna list', err_response))
def test_get_new_command(mistype_response):
assert (get_new_command(Command('conda lst', mistype_response)) == ['conda list'])

View File

@@ -0,0 +1,30 @@
import pytest
from thefuck.rules.cp_create_destination import match, get_new_command
from thefuck.types import Command
@pytest.mark.parametrize(
"script, output",
[("cp", "cp: directory foo does not exist\n"), ("mv", "No such file or directory")],
)
def test_match(script, output):
assert match(Command(script, output))
@pytest.mark.parametrize(
"script, output", [("cp", ""), ("mv", ""), ("ls", "No such file or directory")]
)
def test_not_match(script, output):
assert not match(Command(script, output))
@pytest.mark.parametrize(
"script, output, new_command",
[
("cp foo bar/", "cp: directory foo does not exist\n", "mkdir -p bar/ && cp foo bar/"),
("mv foo bar/", "No such file or directory", "mkdir -p bar/ && mv foo bar/"),
("cp foo bar/baz/", "cp: directory foo does not exist\n", "mkdir -p bar/baz/ && cp foo bar/baz/"),
],
)
def test_get_new_command(script, output, new_command):
assert get_new_command(Command(script, output)) == new_command

View File

@@ -1,22 +1,22 @@
import pytest
from thefuck.rules.cp_omitting_directory import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.mark.parametrize('script, stderr', [
@pytest.mark.parametrize('script, output', [
('cp dir', 'cp: dor: is a directory'),
('cp dir', "cp: omitting directory 'dir'")])
def test_match(script, stderr):
assert match(Command(script, stderr=stderr))
def test_match(script, output):
assert match(Command(script, output))
@pytest.mark.parametrize('script, stderr', [
@pytest.mark.parametrize('script, output', [
('some dir', 'cp: dor: is a directory'),
('some dir', "cp: omitting directory 'dir'"),
('cp dir', '')])
def test_not_match(script, stderr):
assert not match(Command(script, stderr=stderr))
def test_not_match(script, output):
assert not match(Command(script, output))
def test_get_new_command():
assert get_new_command(Command(script='cp dir')) == 'cp -a dir'
assert get_new_command(Command('cp dir', '')) == 'cp -a dir'

View File

@@ -3,7 +3,7 @@ import pytest
import tarfile
from thefuck.rules.dirty_untar import match, get_new_command, side_effect, \
tar_extensions # noqa: E126
from tests.utils import Command
from thefuck.types import Command
@pytest.fixture
@@ -39,7 +39,6 @@ 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', [
@@ -53,7 +52,7 @@ parametrize_script = pytest.mark.parametrize('script, fixed', [
@parametrize_script
def test_match(ext, tar_error, filename, unquoted, quoted, script, fixed):
tar_error(unquoted.format(ext))
assert match(Command(script=script.format(filename.format(ext))))
assert match(Command(script.format(filename.format(ext)), ''))
@parametrize_extensions
@@ -61,7 +60,7 @@ def test_match(ext, tar_error, filename, unquoted, quoted, script, fixed):
@parametrize_script
def test_side_effect(ext, tar_error, filename, unquoted, quoted, script, fixed):
tar_error(unquoted.format(ext))
side_effect(Command(script=script.format(filename.format(ext))), None)
side_effect(Command(script.format(filename.format(ext)), ''), None)
assert set(os.listdir('.')) == {unquoted.format(ext), 'd'}
@@ -70,5 +69,5 @@ def test_side_effect(ext, tar_error, filename, unquoted, quoted, script, fixed):
@parametrize_script
def test_get_new_command(ext, tar_error, filename, unquoted, quoted, script, fixed):
tar_error(unquoted.format(ext))
assert (get_new_command(Command(script=script.format(filename.format(ext))))
assert (get_new_command(Command(script.format(filename.format(ext)), ''))
== fixed.format(dir=quoted.format(''), filename=filename.format(ext)))

View File

@@ -4,7 +4,7 @@ import os
import pytest
import zipfile
from thefuck.rules.dirty_unzip import match, get_new_command, side_effect
from tests.utils import Command
from thefuck.types import Command
from unicodedata import normalize
@@ -42,7 +42,7 @@ def zip_error(tmpdir):
(u'unzip foo.zip', u'foo.zip')])
def test_match(zip_error, script, filename):
zip_error(filename)
assert match(Command(script=script))
assert match(Command(script, ''))
@pytest.mark.parametrize('script,filename', [
@@ -52,7 +52,7 @@ def test_match(zip_error, script, filename):
(u'unzip foo.zip', u'foo.zip')])
def test_side_effect(zip_error, script, filename):
zip_error(filename)
side_effect(Command(script=script), None)
side_effect(Command(script, ''), None)
dir_list = os.listdir(u'.')
if filename not in set(dir_list):
@@ -64,9 +64,8 @@ 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):
zip_error(filename)
assert get_new_command(Command(script=script)) == fixed
assert get_new_command(Command(script, '')) == fixed

View File

@@ -1,10 +1,10 @@
import pytest
from thefuck.rules.django_south_ghost import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.fixture
def stderr():
def output():
return '''Traceback (most recent call last):
File "/home/nvbn/work/.../bin/python", line 42, in <module>
exec(compile(__file__f.read(), __file__, "exec"))
@@ -40,14 +40,14 @@ south.exceptions.GhostMigrations:
''' # noqa
def test_match(stderr):
assert match(Command('./manage.py migrate', stderr=stderr))
assert match(Command('python manage.py migrate', stderr=stderr))
assert not match(Command('./manage.py migrate'))
assert not match(Command('app migrate', stderr=stderr))
assert not match(Command('./manage.py test', stderr=stderr))
def test_match(output):
assert match(Command('./manage.py migrate', output))
assert match(Command('python manage.py migrate', output))
assert not match(Command('./manage.py migrate', ''))
assert not match(Command('app migrate', output))
assert not match(Command('./manage.py test', output))
def test_get_new_command():
assert get_new_command(Command('./manage.py migrate auth'))\
assert get_new_command(Command('./manage.py migrate auth', ''))\
== './manage.py migrate auth --delete-ghost-migrations'

View File

@@ -1,10 +1,10 @@
import pytest
from thefuck.rules.django_south_merge import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.fixture
def stderr():
def output():
return '''Running migrations for app:
! Migration app:0003_auto... should not have been applied before app:0002_auto__add_field_query_due_date_ but was.
Traceback (most recent call last):
@@ -30,14 +30,14 @@ The following options are available:
'''
def test_match(stderr):
assert match(Command('./manage.py migrate', stderr=stderr))
assert match(Command('python manage.py migrate', stderr=stderr))
assert not match(Command('./manage.py migrate'))
assert not match(Command('app migrate', stderr=stderr))
assert not match(Command('./manage.py test', stderr=stderr))
def test_match(output):
assert match(Command('./manage.py migrate', output))
assert match(Command('python manage.py migrate', output))
assert not match(Command('./manage.py migrate', ''))
assert not match(Command('app migrate', output))
assert not match(Command('./manage.py test', output))
def test_get_new_command():
assert (get_new_command(Command('./manage.py migrate auth'))
assert (get_new_command(Command('./manage.py migrate auth', ''))
== './manage.py migrate auth --merge')

View File

@@ -0,0 +1,190 @@
from io import BytesIO
import pytest
from thefuck.types import Command
from thefuck.rules.dnf_no_such_command import match, get_new_command, _get_operations
help_text = b'''usage: dnf [options] COMMAND
List of Main Commands:
autoremove remove all unneeded packages that were originally installed as dependencies
check check for problems in the packagedb
check-update check for available package upgrades
clean remove cached data
deplist List package's dependencies and what packages provide them
distro-sync synchronize installed packages to the latest available versions
downgrade Downgrade a package
group display, or use, the groups information
help display a helpful usage message
history display, or use, the transaction history
info display details about a package or group of packages
install install a package or packages on your system
list list a package or groups of packages
makecache generate the metadata cache
mark mark or unmark installed packages as installed by user.
provides find what package provides the given value
reinstall reinstall a package
remove remove a package or packages from your system
repolist display the configured software repositories
repoquery search for packages matching keyword
repository-packages run commands on top of all packages in given repository
search search package details for the given string
shell run an interactive DNF shell
swap run an interactive dnf mod for remove and install one spec
updateinfo display advisories about packages
upgrade upgrade a package or packages on your system
upgrade-minimal upgrade, but only 'newest' package match which fixes a problem that affects your system
List of Plugin Commands:
builddep Install build dependencies for package or spec file
config-manager manage dnf configuration options and repositories
copr Interact with Copr repositories.
debug-dump dump information about installed rpm packages to file
debug-restore restore packages recorded in debug-dump file
debuginfo-install install debuginfo packages
download Download package to current directory
needs-restarting determine updated binaries that need restarting
playground Interact with Playground repository.
repoclosure Display a list of unresolved dependencies for repositories
repograph Output a full package dependency graph in dot format
repomanage Manage a directory of rpm packages
reposync download all packages from remote repo
Optional arguments:
-c [config file], --config [config file]
config file location
-q, --quiet quiet operation
-v, --verbose verbose operation
--version show DNF version and exit
--installroot [path] set install root
--nodocs do not install documentations
--noplugins disable all plugins
--enableplugin [plugin]
enable plugins by name
--disableplugin [plugin]
disable plugins by name
--releasever RELEASEVER
override the value of $releasever in config and repo
files
--setopt SETOPTS set arbitrary config and repo options
--skip-broken resolve depsolve problems by skipping packages
-h, --help, --help-cmd
show command help
--allowerasing allow erasing of installed packages to resolve
dependencies
-b, --best try the best available package versions in
transactions.
-C, --cacheonly run entirely from system cache, don't update cache
-R [minutes], --randomwait [minutes]
maximum command wait time
-d [debug level], --debuglevel [debug level]
debugging output level
--debugsolver dumps detailed solving results into files
--showduplicates show duplicates, in repos, in list/search commands
-e ERRORLEVEL, --errorlevel ERRORLEVEL
error output level
--obsoletes enables dnf's obsoletes processing logic for upgrade
or display capabilities that the package obsoletes for
info, list and repoquery
--rpmverbosity [debug level name]
debugging output level for rpm
-y, --assumeyes automatically answer yes for all questions
--assumeno automatically answer no for all questions
--enablerepo [repo]
--disablerepo [repo]
--repo [repo], --repoid [repo]
enable just specific repositories by an id or a glob,
can be specified multiple times
-x [package], --exclude [package], --excludepkgs [package]
exclude packages by name or glob
--disableexcludes [repo], --disableexcludepkgs [repo]
disable excludepkgs
--repofrompath [repo,path]
label and path to additional repository, can be
specified multiple times.
--noautoremove disable removal of dependencies that are no longer
used
--nogpgcheck disable gpg signature checking
--color COLOR control whether colour is used
--refresh set metadata as expired before running the command
-4 resolve to IPv4 addresses only
-6 resolve to IPv6 addresses only
--destdir DESTDIR, --downloaddir DESTDIR
set directory to copy packages to
--downloadonly only download packages
--bugfix Include bugfix relevant packages, in updates
--enhancement Include enhancement relevant packages, in updates
--newpackage Include newpackage relevant packages, in updates
--security Include security relevant packages, in updates
--advisory ADVISORY, --advisories ADVISORY
Include packages needed to fix the given advisory, in
updates
--bzs BUGZILLA Include packages needed to fix the given BZ, in
updates
--cves CVES Include packages needed to fix the given CVE, in
updates
--sec-severity {Critical,Important,Moderate,Low}, --secseverity {Critical,Important,Moderate,Low}
Include security relevant packages matching the
severity, in updates
--forcearch ARCH Force the use of an architecture
'''
dnf_operations = ['autoremove', 'check', 'check-update', 'clean', 'deplist',
'distro-sync', 'downgrade', 'group', 'help', 'history',
'info', 'install', 'list', 'makecache', 'mark', 'provides',
'reinstall', 'remove', 'repolist', 'repoquery',
'repository-packages', 'search', 'shell', 'swap', 'updateinfo',
'upgrade', 'upgrade-minimal', 'builddep', 'config-manager',
'copr', 'debug-dump', 'debug-restore', 'debuginfo-install',
'download', 'needs-restarting', 'playground', 'repoclosure',
'repograph', 'repomanage', 'reposync']
def invalid_command(command):
return """No such command: %s. Please use /usr/bin/dnf --help
It could be a DNF plugin command, try: "dnf install 'dnf-command(%s)'"
""" % (command, command)
@pytest.mark.parametrize('output', [
(invalid_command('saerch')),
(invalid_command('isntall'))
])
def test_match(output):
assert match(Command('dnf', output))
@pytest.mark.parametrize('script, output', [
('pip', invalid_command('isntall')),
('vim', "")
])
def test_not_match(script, output):
assert not match(Command(script, output))
@pytest.fixture
def set_help(mocker):
mock = mocker.patch('subprocess.Popen')
def _set_text(text):
mock.return_value.stdout = BytesIO(text)
return _set_text
def test_get_operations(set_help):
set_help(help_text)
assert _get_operations() == dnf_operations
@pytest.mark.parametrize('script, output, result', [
('dnf isntall vim', invalid_command('isntall'),
'dnf install vim'),
('dnf saerch vim', invalid_command('saerch'),
'dnf search vim'),
])
def test_get_new_command(set_help, output, script, result):
set_help(help_text)
assert result in get_new_command(Command(script, output))

View File

@@ -0,0 +1,27 @@
from thefuck.rules.docker_image_being_used_by_container import match, get_new_command
from thefuck.types import Command
def test_match():
err_response = """Error response from daemon: conflict: unable to delete cd809b04b6ff (cannot be forced) - image is being used by running container e5e2591040d1"""
assert match(Command('docker image rm -f cd809b04b6ff', err_response))
def test_not_match():
err_response = 'bash: docker: command not found'
assert not match(Command('docker image rm -f cd809b04b6ff', err_response))
def test_not_docker_command():
err_response = """Error response from daemon: conflict: unable to delete cd809b04b6ff (cannot be forced) - image is being used by running container e5e2591040d1"""
assert not match(Command('git image rm -f cd809b04b6ff', err_response))
def test_get_new_command():
err_response = """
Error response from daemon: conflict: unable to delete cd809b04b6ff (cannot be forced) - image
is being used by running container e5e2591040d1
"""
result = get_new_command(Command('docker image rm -f cd809b04b6ff', err_response))
expected = 'docker container rm -f e5e2591040d1 && docker image rm -f cd809b04b6ff'
assert result == expected

View File

@@ -0,0 +1,37 @@
from thefuck.rules.docker_login import match, get_new_command
from thefuck.types import Command
def test_match():
err_response1 = """
Sending build context to Docker daemon 118.8kB
Step 1/6 : FROM foo/bar:fdb7c6d
pull access denied for foo/bar, repository does not exist or may require 'docker login'
"""
assert match(Command('docker build -t artifactory:9090/foo/bar:fdb7c6d .', err_response1))
err_response2 = """
The push refers to repository [artifactory:9090/foo/bar]
push access denied for foo/bar, repository does not exist or may require 'docker login'
"""
assert match(Command('docker push artifactory:9090/foo/bar:fdb7c6d', err_response2))
err_response3 = """
docker push artifactory:9090/foo/bar:fdb7c6d
The push refers to repository [artifactory:9090/foo/bar]
9c29c7ad209d: Preparing
71f3ad53dfe0: Preparing
f58ee068224c: Preparing
aeddc924d0f7: Preparing
c2040e5d6363: Preparing
4d42df4f350f: Preparing
35723dab26f9: Preparing
71f3ad53dfe0: Pushed
cb95fa0faeb1: Layer already exists
"""
assert not match(Command('docker push artifactory:9090/foo/bar:fdb7c6d', err_response3))
def test_get_new_command():
assert get_new_command(Command('docker build -t artifactory:9090/foo/bar:fdb7c6d .', '')) == 'docker login && docker build -t artifactory:9090/foo/bar:fdb7c6d .'
assert get_new_command(Command('docker push artifactory:9090/foo/bar:fdb7c6d', '')) == 'docker login && docker push artifactory:9090/foo/bar:fdb7c6d'

View File

@@ -1,9 +1,49 @@
import pytest
from io import BytesIO
from tests.utils import Command
from thefuck.types import Command
from thefuck.rules.docker_not_command import get_new_command, match
_DOCKER_SWARM_OUTPUT = '''
Usage: docker swarm COMMAND
Manage Swarm
Commands:
ca Display and rotate the root CA
init Initialize a swarm
join Join a swarm as a node and/or manager
join-token Manage join tokens
leave Leave the swarm
unlock Unlock swarm
unlock-key Manage the unlock key
update Update the swarm
Run 'docker swarm COMMAND --help' for more information on a command.
'''
_DOCKER_IMAGE_OUTPUT = '''
Usage: docker image COMMAND
Manage images
Commands:
build Build an image from a Dockerfile
history Show the history of an image
import Import the contents from a tarball to create a filesystem image
inspect Display detailed information on one or more images
load Load an image from a tar archive or STDIN
ls List images
prune Remove unused images
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rm Remove one or more images
save Save one or more images to a tar archive (streamed to STDOUT by default)
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
Run 'docker image COMMAND --help' for more information on a command.
'''
@pytest.fixture
def docker_help(mocker):
help = b'''Usage: docker [OPTIONS] COMMAND [arg...]
@@ -104,26 +144,150 @@ Run 'docker COMMAND --help' for more information on a command.
return mock
def stderr(cmd):
@pytest.fixture
def docker_help_new(mocker):
helptext_new = b'''
Usage: docker [OPTIONS] COMMAND
A self-sufficient runtime for containers
Options:
--config string Location of client config files (default "/Users/ik1ne/.docker")
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var
and default context set with "docker context use")
-D, --debug Enable debug mode
-H, --host list Daemon socket(s) to connect to
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/Users/ik1ne/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/Users/ik1ne/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/Users/ik1ne/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit
Management Commands:
builder Manage builds
config Manage Docker configs
container Manage containers
context Manage contexts
image Manage images
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
secret Manage Docker secrets
service Manage services
stack Manage Docker stacks
swarm Manage Swarm
system Manage Docker
trust Manage trust on Docker images
volume Manage volumes
Commands:
attach Attach local standard input, output, and error streams to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container's filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes
Run 'docker COMMAND --help' for more information on a command.
'''
mock = mocker.patch('subprocess.Popen')
mock.return_value.stdout = BytesIO(b'')
mock.return_value.stderr = BytesIO(helptext_new)
return mock
def output(cmd):
return "docker: '{}' is not a docker command.\n" \
"See 'docker --help'.".format(cmd)
def test_match():
assert match(Command('docker pes', stderr=stderr('pes')))
assert match(Command('docker pes', output('pes')))
@pytest.mark.parametrize('script, stderr', [
# tests docker (management command)
@pytest.mark.usefixtures('no_memoize')
@pytest.mark.parametrize('script, output', [
('docker swarn', output('swarn')),
('docker imge', output('imge'))])
def test_match_management_cmd(script, output):
assert match(Command(script, output))
# tests docker (management cmd) (management subcmd)
@pytest.mark.usefixtures('no_memoize')
@pytest.mark.parametrize('script, output', [
('docker swarm int', _DOCKER_SWARM_OUTPUT),
('docker image la', _DOCKER_IMAGE_OUTPUT)])
def test_match_management_subcmd(script, output):
assert match(Command(script, output))
@pytest.mark.parametrize('script, output', [
('docker ps', ''),
('cat pes', stderr('pes'))])
def test_not_match(script, stderr):
assert not match(Command(script, stderr=stderr))
('cat pes', output('pes'))])
def test_not_match(script, output):
assert not match(Command(script, output))
@pytest.mark.usefixtures('docker_help')
@pytest.mark.usefixtures('no_memoize', 'docker_help')
@pytest.mark.parametrize('wrong, fixed', [
('pes', ['ps', 'push', 'pause']),
('tags', ['tag', 'stats', 'images'])])
def test_get_new_command(wrong, fixed):
command = Command('docker {}'.format(wrong), stderr=stderr(wrong))
command = Command('docker {}'.format(wrong), output(wrong))
assert get_new_command(command) == ['docker {}'.format(x) for x in fixed]
@pytest.mark.usefixtures('no_memoize', 'docker_help_new')
@pytest.mark.parametrize('wrong, fixed', [
('swarn', ['swarm', 'start', 'search']),
('inage', ['image', 'images', 'rename'])])
def test_get_new_management_command(wrong, fixed):
command = Command('docker {}'.format(wrong), output(wrong))
assert get_new_command(command) == ['docker {}'.format(x) for x in fixed]
@pytest.mark.usefixtures('no_memoize', 'docker_help_new')
@pytest.mark.parametrize('wrong, fixed, output', [
('swarm int', ['swarm init', 'swarm join', 'swarm join-token'], _DOCKER_SWARM_OUTPUT),
('image la', ['image load', 'image ls', 'image tag'], _DOCKER_IMAGE_OUTPUT)])
def test_get_new_management_command_subcommand(wrong, fixed, output):
command = Command('docker {}'.format(wrong), output)
assert get_new_command(command) == ['docker {}'.format(x) for x in fixed]

View File

@@ -1,17 +1,17 @@
import pytest
from thefuck.rules.dry import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.mark.parametrize('command', [
Command(script='cd cd foo'),
Command(script='git git push origin/master')])
Command('cd cd foo', ''),
Command('git git push origin/master', '')])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('cd cd foo'), 'cd foo'),
(Command('git git push origin/master'), 'git push origin/master')])
(Command('cd cd foo', ''), 'cd foo'),
(Command('git git push origin/master', ''), 'git push origin/master')])
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command

View File

@@ -1,13 +1,12 @@
import pytest
from thefuck.rules.fab_command_not_found import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
stderr = '''
output = '''
Warning: Command(s) not found:
extenson
deloyp
'''
stdout = '''
Available commands:
update_config
@@ -21,16 +20,16 @@ Available commands:
@pytest.mark.parametrize('command', [
Command('fab extenson', stderr=stderr),
Command('fab deloyp', stderr=stderr),
Command('fab extenson deloyp', stderr=stderr)])
Command('fab extenson', output),
Command('fab deloyp', output),
Command('fab extenson deloyp', output)])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command', [
Command('gulp extenson', stderr=stderr),
Command('fab deloyp')])
Command('gulp extenson', output),
Command('fab deloyp', '')])
def test_not_match(command):
assert not match(command)
@@ -45,5 +44,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, output)
assert get_new_command(command) == result

View File

@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
from thefuck.rules.fix_alt_space import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
def test_match():
@@ -11,12 +11,12 @@ def test_match():
"""
assert match(Command(u'ps -ef | grep foo',
stderr=u'-bash:  grep: command not found'))
assert not match(Command('ps -ef | grep foo'))
assert not match(Command())
u'-bash:  grep: command not found'))
assert not match(Command('ps -ef | grep foo', ''))
assert not match(Command('', ''))
def test_get_new_command():
""" Replace the Alt+Space character by a simple space """
assert (get_new_command(Command(u'ps -ef | grep foo'))
assert (get_new_command(Command(u'ps -ef | grep foo', ''))
== 'ps -ef | grep foo')

View File

@@ -2,62 +2,54 @@
import pytest
import os
from collections import namedtuple
from thefuck.rules.fix_file import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
FixFileTest = namedtuple('FixFileTest', ['script', 'file', 'line', 'col', 'output'])
# (script, file, line, col (or None), stdout, stderr)
tests = (
('gcc a.c', 'a.c', 3, 1, '',
"""
FixFileTest('gcc a.c', 'a.c', 3, 1, """
a.c: In function 'main':
a.c:3:1: error: expected expression before '}' token
}
^
"""),
('clang a.c', 'a.c', 3, 1, '',
"""
FixFileTest('clang a.c', 'a.c', 3, 1, """
a.c:3:1: error: expected expression
}
^
"""),
('perl a.pl', 'a.pl', 3, None, '',
"""
FixFileTest('perl a.pl', 'a.pl', 3, None, """
syntax error at a.pl line 3, at EOF
Execution of a.pl aborted due to compilation errors.
"""),
('perl a.pl', 'a.pl', 2, None, '',
"""
FixFileTest('perl a.pl', 'a.pl', 2, None, """
Search pattern not terminated at a.pl line 2.
"""),
('sh a.sh', 'a.sh', 2, None, '',
"""
FixFileTest('sh a.sh', 'a.sh', 2, None, """
a.sh: line 2: foo: command not found
"""),
('zsh a.sh', 'a.sh', 2, None, '',
"""
FixFileTest('zsh a.sh', 'a.sh', 2, None, """
a.sh:2: command not found: foo
"""),
('bash a.sh', 'a.sh', 2, None, '',
"""
FixFileTest('bash a.sh', 'a.sh', 2, None, """
a.sh: line 2: foo: command not found
"""),
('rustc a.rs', 'a.rs', 2, 5, '',
"""
FixFileTest('rustc a.rs', 'a.rs', 2, 5, """
a.rs:2:5: 2:6 error: unexpected token: `+`
a.rs:2 +
^
"""),
('cargo build', 'src/lib.rs', 3, 5, '',
"""
FixFileTest('cargo build', 'src/lib.rs', 3, 5, """
Compiling test v0.1.0 (file:///tmp/fix-error/test)
src/lib.rs:3:5: 3:6 error: unexpected token: `+`
src/lib.rs:3 +
@@ -67,16 +59,14 @@ Could not compile `test`.
To learn more, run the command again with --verbose.
"""),
('python a.py', 'a.py', 2, None, '',
"""
FixFileTest('python a.py', 'a.py', 2, None, """
File "a.py", line 2
+
^
SyntaxError: invalid syntax
"""),
('python a.py', 'a.py', 8, None, '',
"""
FixFileTest('python a.py', 'a.py', 8, None, """
Traceback (most recent call last):
File "a.py", line 8, in <module>
match("foo")
@@ -89,8 +79,7 @@ Traceback (most recent call last):
TypeError: first argument must be string or compiled pattern
"""),
(u'python café.py', u'café.py', 8, None, '',
u"""
FixFileTest(u'python café.py', u'café.py', 8, None, u"""
Traceback (most recent call last):
File "café.py", line 8, in <module>
match("foo")
@@ -103,57 +92,48 @@ Traceback (most recent call last):
TypeError: first argument must be string or compiled pattern
"""),
('ruby a.rb', 'a.rb', 3, None, '',
"""
FixFileTest('ruby a.rb', 'a.rb', 3, None, """
a.rb:3: syntax error, unexpected keyword_end
"""),
('lua a.lua', 'a.lua', 2, None, '',
"""
FixFileTest('lua a.lua', 'a.lua', 2, None, """
lua: a.lua:2: unexpected symbol near '+'
"""),
('fish a.sh', '/tmp/fix-error/a.sh', 2, None, '',
"""
FixFileTest('fish a.sh', '/tmp/fix-error/a.sh', 2, None, """
fish: Unknown command 'foo'
/tmp/fix-error/a.sh (line 2): foo
^
"""),
('./a', './a', 2, None, '',
"""
FixFileTest('./a', './a', 2, None, """
awk: ./a:2: BEGIN { print "Hello, world!" + }
awk: ./a:2: ^ syntax error
"""),
('llc a.ll', 'a.ll', 1, 2, '',
"""
FixFileTest('llc a.ll', 'a.ll', 1, 2, """
llc: a.ll:1:2: error: expected top-level entity
+
^
"""),
('go build a.go', 'a.go', 1, 2, '',
"""
FixFileTest('go build a.go', 'a.go', 1, 2, """
can't load package:
a.go:1:2: expected 'package', found '+'
"""),
('make', 'Makefile', 2, None, '',
"""
FixFileTest('make', 'Makefile', 2, None, """
bidule
make: bidule: Command not found
Makefile:2: recipe for target 'target' failed
make: *** [target] Error 127
"""),
('git st', '/home/martin/.config/git/config', 1, None, '',
"""
FixFileTest('git st', '/home/martin/.config/git/config', 1, None, """
fatal: bad config file line 1 in /home/martin/.config/git/config
"""),
('node fuck.js asdf qwer', '/Users/pablo/Workspace/barebones/fuck.js', '2', 5, '',
"""
FixFileTest('node fuck.js asdf qwer', '/Users/pablo/Workspace/barebones/fuck.js', '2', 5, """
/Users/pablo/Workspace/barebones/fuck.js:2
conole.log(arg); // this should read console.log(arg);
^
@@ -170,16 +150,14 @@ ReferenceError: conole is not defined
at node.js:814:3
"""),
('pep8', './tests/rules/test_systemctl.py', 17, 80,
"""
FixFileTest('pep8', './tests/rules/test_systemctl.py', 17, 80, """
./tests/rules/test_systemctl.py:17:80: E501 line too long (93 > 79 characters)
./tests/rules/test_systemctl.py:18:80: E501 line too long (103 > 79 characters)
./tests/rules/test_whois.py:20:80: E501 line too long (89 > 79 characters)
./tests/rules/test_whois.py:22:80: E501 line too long (83 > 79 characters)
""", ''),
"""),
('py.test', '/home/thefuck/tests/rules/test_fix_file.py', 218, None,
"""
FixFileTest('pytest', '/home/thefuck/tests/rules/test_fix_file.py', 218, None, """
monkeypatch = <_pytest.monkeypatch.monkeypatch object at 0x7fdb76a25b38>
test = ('fish a.sh', '/tmp/fix-error/a.sh', 2, None, '', "\\nfish: Unknown command 'foo'\\n/tmp/fix-error/a.sh (line 2): foo\\n ^\\n")
@@ -190,8 +168,8 @@ test = ('fish a.sh', '/tmp/fix-error/a.sh', 2, None, '', "\\nfish: Unknown comma
E NameError: name 'mocker' is not defined
/home/thefuck/tests/rules/test_fix_file.py:218: NameError
""", ''),
) # noqa
"""),
)
@pytest.mark.parametrize('test', tests)
@@ -199,7 +177,7 @@ E NameError: name 'mocker' is not defined
def test_match(mocker, monkeypatch, test):
mocker.patch('os.path.isfile', return_value=True)
monkeypatch.setenv('EDITOR', 'dummy_editor')
assert match(Command(stdout=test[4], stderr=test[5]))
assert match(Command('', test.output))
@pytest.mark.parametrize('test', tests)
@@ -209,7 +187,7 @@ def test_no_editor(mocker, monkeypatch, test):
if 'EDITOR' in os.environ:
monkeypatch.delenv('EDITOR')
assert not match(Command(stdout=test[4], stderr=test[5]))
assert not match(Command('', test.output))
@pytest.mark.parametrize('test', tests)
@@ -218,7 +196,7 @@ def test_not_file(mocker, monkeypatch, test):
mocker.patch('os.path.isfile', return_value=False)
monkeypatch.setenv('EDITOR', 'dummy_editor')
assert not match(Command(stdout=test[4], stderr=test[5]))
assert not match(Command('', test.output))
@pytest.mark.parametrize('test', tests)
@@ -234,12 +212,12 @@ def test_get_new_command_with_settings(mocker, monkeypatch, test, settings):
mocker.patch('os.path.isfile', return_value=True)
monkeypatch.setenv('EDITOR', 'dummy_editor')
cmd = Command(script=test[0], stdout=test[4], stderr=test[5])
cmd = Command(test.script, test.output)
settings.fixcolcmd = '{editor} {file} +{line}:{col}'
if test[3]:
if test.col:
assert (get_new_command(cmd) ==
u'dummy_editor {} +{}:{} && {}'.format(test[1], test[2], test[3], test[0]))
u'dummy_editor {} +{}:{} && {}'.format(test.file, test.line, test.col, test.script))
else:
assert (get_new_command(cmd) ==
u'dummy_editor {} +{} && {}'.format(test[1], test[2], test[0]))
u'dummy_editor {} +{} && {}'.format(test.file, test.line, test.script))

View File

@@ -1,9 +1,9 @@
import pytest
from six import BytesIO
from thefuck.rules.gem_unknown_command import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
stderr = '''
output = '''
ERROR: While executing gem ... (Gem::CommandLineError)
Unknown command {}
'''
@@ -64,19 +64,19 @@ def gem_help_commands(mocker):
('gem isntall jekyll', 'isntall'),
('gem last --local', 'last')])
def test_match(script, command):
assert match(Command(script, stderr=stderr.format(command)))
assert match(Command(script, output.format(command)))
@pytest.mark.parametrize('script, stderr', [
@pytest.mark.parametrize('script, output', [
('gem install jekyll', ''),
('git log', stderr.format('log'))])
def test_not_match(script, stderr):
assert not match(Command(script, stderr=stderr))
('git log', output.format('log'))])
def test_not_match(script, output):
assert not match(Command(script, output))
@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))
@pytest.mark.parametrize('script, output, result', [
('gem isntall jekyll', output.format('isntall'), 'gem install jekyll'),
('gem last --local', output.format('last'), 'gem list --local')])
def test_get_new_command(script, output, result):
new_command = get_new_command(Command(script, output))
assert new_command[0] == result

View File

@@ -1,6 +1,6 @@
import pytest
from thefuck.rules.git_add import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.fixture(autouse=True)
@@ -10,7 +10,7 @@ def path_exists(mocker):
@pytest.fixture
def stderr(target):
def output(target):
return ("error: pathspec '{}' did not match any "
'file(s) known to git.'.format(target))
@@ -18,17 +18,17 @@ def stderr(target):
@pytest.mark.parametrize('script, target', [
('git submodule update unknown', 'unknown'),
('git commit unknown', 'unknown')])
def test_match(stderr, script, target):
assert match(Command(script=script, stderr=stderr))
def test_match(output, script, target):
assert match(Command(script, output))
@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):
('git submodule update known', output, False)])
def test_not_match(path_exists, output, script, target, exists):
path_exists.return_value = exists
assert not match(Command(script=script, stderr=stderr))
assert not match(Command(script, output))
@pytest.mark.parametrize('script, target, new_command', [
@@ -36,5 +36,5 @@ def test_not_match(path_exists, stderr, script, target, exists):
'git add -- unknown && git submodule update unknown'),
('git commit unknown', 'unknown',
'git add -- unknown && git commit unknown')])
def test_get_new_command(stderr, script, target, new_command):
assert get_new_command(Command(script=script, stderr=stderr)) == new_command
def test_get_new_command(output, script, target, new_command):
assert get_new_command(Command(script, output)) == new_command

View File

@@ -1,10 +1,10 @@
import pytest
from thefuck.rules.git_add_force import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.fixture
def stderr():
def output():
return ('The following paths are ignored by one of your .gitignore files:\n'
'dist/app.js\n'
'dist/background.js\n'
@@ -12,11 +12,11 @@ def stderr():
'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_match(output):
assert match(Command('git add dist/*.js', output))
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))
def test_get_new_command(output):
assert (get_new_command(Command('git add dist/*.js', output))
== "git add --force dist/*.js")

View File

@@ -1,30 +1,30 @@
import pytest
from tests.utils import Command
from thefuck.types import Command
from thefuck.rules.git_bisect_usage import match, get_new_command
@pytest.fixture
def stderr():
def output():
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))
def test_match(output, script):
assert match(Command(script, output))
@pytest.mark.parametrize('script', [
'git bisect', 'git bisect start', 'git bisect good'])
def test_not_match(script):
assert not match(Command(script=script, stderr=''))
assert not match(Command(script, ''))
@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):
def test_get_new_command(output, 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
assert get_new_command(Command(script, output)) == new_cmd

View File

@@ -0,0 +1,70 @@
import pytest
from thefuck.rules.git_branch_0flag import get_new_command, match
from thefuck.types import Command
@pytest.fixture
def output_branch_exists():
return "fatal: A branch named 'bar' already exists."
@pytest.mark.parametrize(
"script",
[
"git branch 0a",
"git branch 0d",
"git branch 0f",
"git branch 0r",
"git branch 0v",
"git branch 0d foo",
"git branch 0D foo",
],
)
def test_match(script, output_branch_exists):
assert match(Command(script, output_branch_exists))
@pytest.mark.parametrize(
"script",
[
"git branch -a",
"git branch -r",
"git branch -v",
"git branch -d foo",
"git branch -D foo",
],
)
def test_not_match(script, output_branch_exists):
assert not match(Command(script, ""))
@pytest.mark.parametrize(
"script, new_command",
[
("git branch 0a", "git branch -D 0a && git branch -a"),
("git branch 0v", "git branch -D 0v && git branch -v"),
("git branch 0d foo", "git branch -D 0d && git branch -d foo"),
("git branch 0D foo", "git branch -D 0D && git branch -D foo"),
("git branch 0l 'maint-*'", "git branch -D 0l && git branch -l 'maint-*'"),
("git branch 0u upstream", "git branch -D 0u && git branch -u upstream"),
],
)
def test_get_new_command_branch_exists(script, output_branch_exists, new_command):
assert get_new_command(Command(script, output_branch_exists)) == new_command
@pytest.fixture
def output_not_valid_object():
return "fatal: Not a valid object name: 'bar'."
@pytest.mark.parametrize(
"script, new_command",
[
("git branch 0l 'maint-*'", "git branch -l 'maint-*'"),
("git branch 0u upstream", "git branch -u upstream"),
],
)
def test_get_new_command_not_valid_object(script, output_not_valid_object, new_command):
assert get_new_command(Command(script, output_not_valid_object)) == new_command

View File

@@ -1,22 +1,22 @@
import pytest
from thefuck.rules.git_branch_delete import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.fixture
def stderr():
def output():
return '''error: The branch 'branch' is not fully merged.
If you are sure you want to delete it, run 'git branch -D branch'.
'''
def test_match(stderr):
assert match(Command('git branch -d branch', stderr=stderr))
assert not match(Command('git branch -d branch'))
assert not match(Command('ls', stderr=stderr))
def test_match(output):
assert match(Command('git branch -d branch', output))
assert not match(Command('git branch -d branch', ''))
assert not match(Command('ls', output))
def test_get_new_command(stderr):
assert get_new_command(Command('git branch -d branch', stderr=stderr))\
def test_get_new_command(output):
assert get_new_command(Command('git branch -d branch', output))\
== "git branch -D branch"

View File

@@ -0,0 +1,29 @@
import pytest
from thefuck.rules.git_branch_delete_checked_out import match, get_new_command
from thefuck.types import Command
@pytest.fixture
def output():
return "error: Cannot delete branch 'foo' checked out at '/bar/foo'"
@pytest.mark.parametrize("script", ["git branch -d foo", "git branch -D foo"])
def test_match(script, output):
assert match(Command(script, output))
@pytest.mark.parametrize("script", ["git branch -d foo", "git branch -D foo"])
def test_not_match(script):
assert not match(Command(script, "Deleted branch foo (was a1b2c3d)."))
@pytest.mark.parametrize(
"script, new_command",
[
("git branch -d foo", "git checkout master && git branch -D foo"),
("git branch -D foo", "git checkout master && git branch -D foo"),
],
)
def test_get_new_command(script, new_command, output):
assert get_new_command(Command(script, output)) == new_command

View File

@@ -1,11 +1,11 @@
import pytest
from thefuck.rules.git_branch_exists import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.fixture
def stderr(branch_name):
return "fatal: A branch named '{}' already exists.".format(branch_name)
def output(src_branch_name):
return "fatal: A branch named '{}' already exists.".format(src_branch_name)
@pytest.fixture
@@ -17,18 +17,25 @@ def new_command(branch_name):
'git branch -D {0} && git checkout -b {0}', 'git checkout {0}']]
@pytest.mark.parametrize('script, branch_name', [
('git branch foo', 'foo'), ('git checkout bar', 'bar')])
def test_match(stderr, script, branch_name):
assert match(Command(script=script, stderr=stderr))
@pytest.mark.parametrize('script, src_branch_name, branch_name', [
('git branch foo', 'foo', 'foo'),
('git checkout bar', 'bar', 'bar'),
('git checkout -b "let\'s-push-this"', '"let\'s-push-this"', '"let\'s-push-this"')])
def test_match(output, script, branch_name):
assert match(Command(script, output))
@pytest.mark.parametrize('script', ['git branch foo', 'git checkout bar'])
@pytest.mark.parametrize('script', [
'git branch foo',
'git checkout bar',
'git checkout -b "let\'s-push-this"'])
def test_not_match(script):
assert not match(Command(script=script, stderr=''))
assert not match(Command(script, ''))
@pytest.mark.parametrize('script, branch_name, ', [
('git branch foo', 'foo'), ('git checkout bar', 'bar')])
def test_get_new_command(stderr, new_command, script, branch_name):
assert get_new_command(Command(script=script, stderr=stderr)) == new_command
@pytest.mark.parametrize('script, src_branch_name, branch_name', [
('git branch foo', 'foo', 'foo'),
('git checkout bar', 'bar', 'bar'),
('git checkout -b "let\'s-push-this"', "let's-push-this", "let\\'s-push-this")])
def test_get_new_command(output, new_command, script, src_branch_name, branch_name):
assert get_new_command(Command(script, output)) == new_command

View File

@@ -1,19 +1,19 @@
from thefuck.rules.git_branch_list import match, get_new_command
from thefuck.shells import shell
from tests.utils import Command
from thefuck.types import Command
def test_match():
assert match(Command('git branch list'))
assert match(Command('git branch list', ''))
def test_not_match():
assert not match(Command())
assert not match(Command('git commit'))
assert not match(Command('git branch'))
assert not match(Command('git stash list'))
assert not match(Command('', ''))
assert not match(Command('git commit', ''))
assert not match(Command('git branch', ''))
assert not match(Command('git stash list', ''))
def test_get_new_command():
assert (get_new_command(Command('git branch list')) ==
assert (get_new_command(Command('git branch list', '')) ==
shell.and_('git branch --delete list', 'git branch'))

View File

@@ -1,10 +1,9 @@
import pytest
from io import BytesIO
from thefuck.rules.git_checkout import match, get_branches, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.fixture
def did_not_match(target, did_you_forget=False):
error = ("error: pathspec '{}' did not match any "
"file(s) known to git.".format(target))
@@ -21,17 +20,17 @@ def git_branch(mocker, branches):
@pytest.mark.parametrize('command', [
Command(script='git checkout unknown', stderr=did_not_match('unknown')),
Command(script='git commit unknown', stderr=did_not_match('unknown'))])
Command('git checkout unknown', did_not_match('unknown')),
Command('git commit unknown', did_not_match('unknown'))])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command', [
Command(script='git submodule update unknown',
stderr=did_not_match('unknown', True)),
Command(script='git checkout known', stderr=('')),
Command(script='git commit known', stderr=(''))])
Command('git submodule update unknown',
did_not_match('unknown', True)),
Command('git checkout known', ''),
Command('git commit known', '')])
def test_not_match(command):
assert not match(command)
@@ -40,6 +39,11 @@ def test_not_match(command):
(b'', []),
(b'* master', ['master']),
(b' remotes/origin/master', ['master']),
(b' remotes/origin/test/1', ['test/1']),
(b' remotes/origin/test/1/2/3', ['test/1/2/3']),
(b' test/1', ['test/1']),
(b' test/1/2/3', ['test/1/2/3']),
(b' remotes/origin/HEAD -> origin/master', []),
(b' just-another-branch', ['just-another-branch']),
(b'* master\n just-another-branch', ['master', 'just-another-branch']),
(b'* master\n remotes/origin/master\n just-another-branch',
@@ -51,19 +55,19 @@ def test_get_branches(branches, branch_list, git_branch):
@pytest.mark.parametrize('branches, command, new_command', [
(b'',
Command(script='git checkout unknown', stderr=did_not_match('unknown')),
'git branch unknown && git checkout unknown'),
Command('git checkout unknown', did_not_match('unknown')),
['git checkout -b unknown']),
(b'',
Command('git commit unknown', stderr=did_not_match('unknown')),
'git branch unknown && git commit unknown'),
Command('git commit unknown', did_not_match('unknown')),
['git branch unknown && git commit unknown']),
(b' test-random-branch-123',
Command(script='git checkout tst-rdm-brnch-123',
stderr=did_not_match('tst-rdm-brnch-123')),
'git checkout test-random-branch-123'),
Command('git checkout tst-rdm-brnch-123',
did_not_match('tst-rdm-brnch-123')),
['git checkout test-random-branch-123', 'git checkout -b tst-rdm-brnch-123']),
(b' test-random-branch-123',
Command(script='git commit tst-rdm-brnch-123',
stderr=did_not_match('tst-rdm-brnch-123')),
'git commit test-random-branch-123')])
Command('git commit tst-rdm-brnch-123',
did_not_match('tst-rdm-brnch-123')),
['git commit test-random-branch-123'])])
def test_get_new_command(branches, command, new_command, git_branch):
git_branch(branches)
assert get_new_command(command) == new_command

View File

@@ -0,0 +1,24 @@
from thefuck.rules.git_clone_git_clone import match, get_new_command
from thefuck.types import Command
output_clean = """
fatal: Too many arguments.
usage: git clone [<options>] [--] <repo> [<dir>]
"""
def test_match():
assert match(Command('git clone git clone foo', output_clean))
def test_not_match():
assert not match(Command('', ''))
assert not match(Command('git branch', ''))
assert not match(Command('git clone foo', ''))
assert not match(Command('git clone foo bar baz', output_clean))
def test_get_new_command():
assert get_new_command(Command('git clone git clone foo', output_clean)) == 'git clone foo'

View File

@@ -0,0 +1,50 @@
import pytest
from thefuck.rules.git_clone_missing import match, get_new_command
from thefuck.types import Command
valid_urls = [
'https://github.com/nvbn/thefuck.git',
'https://github.com/nvbn/thefuck',
'http://github.com/nvbn/thefuck.git',
'git@github.com:nvbn/thefuck.git',
'git@github.com:nvbn/thefuck',
'ssh://git@github.com:nvbn/thefuck.git',
]
invalid_urls = [
'', # No command
'notacommand', # Command not found
'ssh git@github.com:nvbn/thefrick.git', # ssh command, not a git clone
'git clone foo', # Valid clone
'git clone https://github.com/nvbn/thefuck.git', # Full command
'github.com/nvbn/thefuck.git', # Missing protocol
'github.com:nvbn/thefuck.git', # SSH missing username
'git clone git clone ssh://git@github.com:nvbn/thefrick.git', # 2x clone
'https:/github.com/nvbn/thefuck.git' # Bad protocol
]
outputs = [
'No such file or directory',
'not found',
'is not recognised as',
]
@pytest.mark.parametrize('cmd', valid_urls)
@pytest.mark.parametrize('output', outputs)
def test_match(cmd, output):
c = Command(cmd, output)
assert match(c)
@pytest.mark.parametrize('cmd', invalid_urls)
@pytest.mark.parametrize('output', outputs + ["some other output"])
def test_not_match(cmd, output):
c = Command(cmd, output)
assert not match(c)
@pytest.mark.parametrize('script', valid_urls)
@pytest.mark.parametrize('output', outputs)
def test_get_new_command(script, output):
command = Command(script, output)
new_command = 'git clone ' + script
assert get_new_command(command) == new_command

View File

@@ -0,0 +1,38 @@
import pytest
from thefuck.rules.git_commit_add import match, get_new_command
from thefuck.types import Command
@pytest.mark.parametrize(
"script, output",
[
('git commit -m "test"', "no changes added to commit"),
("git commit", "no changes added to commit"),
],
)
def test_match(output, script):
assert match(Command(script, output))
@pytest.mark.parametrize(
"script, output",
[
('git commit -m "test"', " 1 file changed, 15 insertions(+), 14 deletions(-)"),
("git branch foo", ""),
("git checkout feature/test_commit", ""),
("git push", ""),
],
)
def test_not_match(output, script):
assert not match(Command(script, output))
@pytest.mark.parametrize(
"script, new_command",
[
("git commit", ["git commit -a", "git commit -p"]),
('git commit -m "foo"', ['git commit -a -m "foo"', 'git commit -p -m "foo"']),
],
)
def test_get_new_command(script, new_command):
assert get_new_command(Command(script, "")) == new_command

View File

@@ -0,0 +1,25 @@
import pytest
from thefuck.rules.git_commit_amend import match, get_new_command
from thefuck.types import Command
@pytest.mark.parametrize('script, output', [
('git commit -m "test"', 'test output'),
('git commit', '')])
def test_match(output, script):
assert match(Command(script, output))
@pytest.mark.parametrize('script', [
'git branch foo',
'git checkout feature/test_commit',
'git push'])
def test_not_match(script):
assert not match(Command(script, ''))
@pytest.mark.parametrize('script', [
('git commit -m "test commit"'),
('git commit')])
def test_get_new_command(script):
assert get_new_command(Command(script, '')) == 'git commit --amend'

View File

@@ -0,0 +1,25 @@
import pytest
from thefuck.rules.git_commit_reset import match, get_new_command
from thefuck.types import Command
@pytest.mark.parametrize('script, output', [
('git commit -m "test"', 'test output'),
('git commit', '')])
def test_match(output, script):
assert match(Command(script, output))
@pytest.mark.parametrize('script', [
'git branch foo',
'git checkout feature/test_commit',
'git push'])
def test_not_match(script):
assert not match(Command(script, ''))
@pytest.mark.parametrize('script', [
('git commit -m "test commit"'),
('git commit')])
def test_get_new_command(script):
assert get_new_command(Command(script, '')) == 'git reset HEAD~'

View File

@@ -1,23 +1,23 @@
import pytest
from thefuck.rules.git_diff_no_index import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.mark.parametrize('command', [
Command(script='git diff foo bar')])
Command('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')])
Command('git diff --no-index foo bar', ''),
Command('git diff foo', ''),
Command('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')])
(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

View File

@@ -1,26 +1,26 @@
import pytest
from thefuck.rules.git_diff_staged import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.mark.parametrize('command', [
Command(script='git diff foo'),
Command(script='git diff')])
Command('git diff foo', ''),
Command('git diff', '')])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command', [
Command(script='git diff --staged'),
Command(script='git tag'),
Command(script='git branch'),
Command(script='git log')])
Command('git diff --staged', ''),
Command('git tag', ''),
Command('git branch', ''),
Command('git log', '')])
def test_not_match(command):
assert not match(command)
@pytest.mark.parametrize('command, new_command', [
(Command('git diff'), 'git diff --staged'),
(Command('git diff foo'), 'git diff --staged foo')])
(Command('git diff', ''), 'git diff --staged'),
(Command('git diff foo', ''), 'git diff --staged foo')])
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command

View File

@@ -1,6 +1,6 @@
import pytest
from thefuck.rules.git_fix_stash import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
git_stash_err = '''
@@ -20,11 +20,11 @@ usage: git stash list [<options>]
'git stash Some message',
'git stash saev Some message'])
def test_match(wrong):
assert match(Command(wrong, stderr=git_stash_err))
assert match(Command(wrong, git_stash_err))
def test_not_match():
assert not match(Command("git", stderr=git_stash_err))
assert not match(Command("git", git_stash_err))
@pytest.mark.parametrize('wrong,fixed', [
@@ -32,4 +32,4 @@ def test_not_match():
('git stash Some message', 'git stash save Some message'),
('git stash saev Some message', 'git stash save Some message')])
def test_get_new_command(wrong, fixed):
assert get_new_command(Command(wrong, stderr=git_stash_err)) == fixed
assert get_new_command(Command(wrong, git_stash_err)) == fixed

View File

@@ -1,24 +1,30 @@
import pytest
from thefuck.rules.git_flag_after_filename import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
command1 = Command('git log README.md -p',
stderr="fatal: bad flag '-p' used after filename")
"fatal: bad flag '-p' used after filename")
command2 = Command('git log README.md -p CONTRIBUTING.md',
stderr="fatal: bad flag '-p' used after filename")
"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")
"fatal: bad flag '--name-only' used after filename")
command4 = Command('git log README.md -p',
"fatal: option '-p' must come before non-option arguments")
command5 = Command('git log README.md -p CONTRIBUTING.md',
"fatal: option '-p' must come before non-option arguments")
command6 = Command('git log -p README.md --name-only',
"fatal: option '--name-only' must come before non-option arguments")
@pytest.mark.parametrize('command', [
command1, command2, command3])
command1, command2, command3, command4, command5, command6])
def test_match(command):
assert match(command)
@pytest.mark.parametrize('command', [
Command('git log README.md'),
Command('git log -p README.md')])
Command('git log README.md', ''),
Command('git log -p README.md', '')])
def test_not_match(command):
assert not match(command)
@@ -26,6 +32,9 @@ def test_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")])
(command3, "git log -p --name-only README.md"),
(command4, "git log -p README.md"),
(command5, "git log -p README.md CONTRIBUTING.md"),
(command6, "git log -p --name-only README.md")])
def test_get_new_command(command, result):
assert get_new_command(command) == result

View File

@@ -1,24 +1,24 @@
import pytest
from thefuck.rules.git_help_aliased import match, get_new_command
from tests.utils import Command
from thefuck.types import Command
@pytest.mark.parametrize('script, stdout', [
@pytest.mark.parametrize('script, output', [
('git help st', "`git st' is aliased to `status'"),
('git help ds', "`git ds' is aliased to `diff --staged'")])
def test_match(script, stdout):
assert match(Command(script=script, stdout=stdout))
def test_match(script, output):
assert match(Command(script, output))
@pytest.mark.parametrize('script, stdout', [
@pytest.mark.parametrize('script, output', [
('git help status', "GIT-STATUS(1)...Git Manual...GIT-STATUS(1)"),
('git help diff', "GIT-DIFF(1)...Git Manual...GIT-DIFF(1)")])
def test_not_match(script, stdout):
assert not match(Command(script=script, stdout=stdout))
def test_not_match(script, output):
assert not match(Command(script, output))
@pytest.mark.parametrize('script, stdout, new_command', [
@pytest.mark.parametrize('script, output, new_command', [
('git help st', "`git st' is aliased to `status'", 'git help status'),
('git help ds', "`git ds' is aliased to `diff --staged'", 'git help diff')])
def test_get_new_command(script, stdout, new_command):
assert get_new_command(Command(script=script, stdout=stdout)) == new_command
def test_get_new_command(script, output, new_command):
assert get_new_command(Command(script, output)) == new_command

View File

@@ -0,0 +1,43 @@
import pytest
from thefuck.rules.git_hook_bypass import match, get_new_command
from thefuck.types import Command
@pytest.mark.parametrize(
"command",
[
Command("git am", ""),
Command("git commit", ""),
Command("git commit -m 'foo bar'", ""),
Command("git push", ""),
Command("git push -u foo bar", ""),
],
)
def test_match(command):
assert match(command)
@pytest.mark.parametrize(
"command",
[
Command("git add foo", ""),
Command("git status", ""),
Command("git diff foo bar", ""),
],
)
def test_not_match(command):
assert not match(command)
@pytest.mark.parametrize(
"command, new_command",
[
(Command("git am", ""), "git am --no-verify"),
(Command("git commit", ""), "git commit --no-verify"),
(Command("git commit -m 'foo bar'", ""), "git commit --no-verify -m 'foo bar'"),
(Command("git push", ""), "git push --no-verify"),
(Command("git push -p", ""), "git push --no-verify -p"),
],
)
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command

View File

@@ -0,0 +1,29 @@
import pytest
from thefuck.rules.git_lfs_mistype import match, get_new_command
from thefuck.types import Command
@pytest.fixture
def mistype_response():
return """
Error: unknown command "evn" for "git-lfs"
Did you mean this?
env
ext
Run 'git-lfs --help' for usage.
"""
def test_match(mistype_response):
assert match(Command('git lfs evn', mistype_response))
err_response = 'bash: git: command not found'
assert not match(Command('git lfs env', err_response))
assert not match(Command('docker lfs env', mistype_response))
def test_get_new_command(mistype_response):
assert (get_new_command(Command('git lfs evn', mistype_response))
== ['git lfs env', 'git lfs ext'])

View File

@@ -0,0 +1,47 @@
import pytest
from thefuck.rules.git_main_master import match, get_new_command
from thefuck.types import Command
@pytest.fixture
def output(branch_name):
if not branch_name:
return ""
output_str = u"error: pathspec '{}' did not match any file(s) known to git"
return output_str.format(branch_name)
@pytest.mark.parametrize(
"script, branch_name",
[
("git checkout main", "main"),
("git checkout master", "master"),
("git show main", "main"),
],
)
def test_match(script, branch_name, output):
assert match(Command(script, output))
@pytest.mark.parametrize(
"script, branch_name",
[
("git checkout master", ""),
("git checkout main", ""),
("git checkout wibble", "wibble"),
],
)
def test_not_match(script, branch_name, output):
assert not match(Command(script, output))
@pytest.mark.parametrize(
"script, branch_name, new_command",
[
("git checkout main", "main", "git checkout master"),
("git checkout master", "master", "git checkout main"),
("git checkout wibble", "wibble", "git checkout wibble"),
],
)
def test_get_new_command(script, branch_name, new_command, output):
assert get_new_command(Command(script, output)) == new_command

View File

@@ -0,0 +1,24 @@
import pytest
from thefuck.rules.git_merge import match, get_new_command
from thefuck.types import Command
output = 'merge: local - not something we can merge\n\n' \
'Did you mean this?\n\tremote/local'
def test_match():
assert match(Command('git merge test', output))
assert not match(Command('git merge master', ''))
assert not match(Command('ls', output))
@pytest.mark.parametrize('command, new_command', [
(Command('git merge local', output),
'git merge remote/local'),
(Command('git merge -m "test" local', output),
'git merge -m "test" remote/local'),
(Command('git merge -m "test local" local', output),
'git merge -m "test local" remote/local')])
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command

View File

@@ -0,0 +1,23 @@
import pytest
from thefuck.rules.git_merge_unrelated import match, get_new_command
from thefuck.types import Command
output = 'fatal: refusing to merge unrelated histories'
def test_match():
assert match(Command('git merge test', output))
assert not match(Command('git merge master', ''))
assert not match(Command('ls', output))
@pytest.mark.parametrize('command, new_command', [
(Command('git merge local', output),
'git merge local --allow-unrelated-histories'),
(Command('git merge -m "test" local', output),
'git merge -m "test" local --allow-unrelated-histories'),
(Command('git merge -m "test local" local', output),
'git merge -m "test local" local --allow-unrelated-histories')])
def test_get_new_command(command, new_command):
assert get_new_command(command) == new_command

Some files were not shown because too many files have changed in this diff Show More