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