mirror of
https://github.com/nvbn/thefuck.git
synced 2025-03-20 09:39:01 +00:00
Changed form .replace() to re.sub()
This commit is contained in:
parent
f9f757f618
commit
877714ca35
31
release.py
Executable file
31
release.py
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
from subprocess import call
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
version = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_setup_py_lines():
|
||||||
|
global version
|
||||||
|
with open('setup.py', 'r') as sf:
|
||||||
|
current_setup = sf.readlines()
|
||||||
|
for line in current_setup:
|
||||||
|
if line.startswith('VERSION = '):
|
||||||
|
major, minor = re.findall(r"VERSION = '(\d+)\.(\d+)'", line)[0]
|
||||||
|
version = "{}.{}".format(major, int(minor) + 1)
|
||||||
|
yield "VERSION = '{}'\n".format(version)
|
||||||
|
else:
|
||||||
|
yield line
|
||||||
|
|
||||||
|
|
||||||
|
lines = list(get_new_setup_py_lines())
|
||||||
|
with open('setup.py', 'w') as sf:
|
||||||
|
sf.writelines(lines)
|
||||||
|
|
||||||
|
call('git pull', shell=True)
|
||||||
|
call('git commit -am "Bump to {}"'.format(version), shell=True)
|
||||||
|
call('git tag {}'.format(version), shell=True)
|
||||||
|
call('git push', shell=True)
|
||||||
|
call('git push --tags', shell=True)
|
||||||
|
call('python setup.py sdist upload', shell=True)
|
12
tests/rules/test_cd_parent.py
Normal file
12
tests/rules/test_cd_parent.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from thefuck.main import Command
|
||||||
|
from thefuck.rules.cd_parent import match, get_new_command
|
||||||
|
|
||||||
|
|
||||||
|
def test_match():
|
||||||
|
assert match(Command('cd..', '', 'cd..: command not found'), None)
|
||||||
|
assert not match(Command('', '', ''), None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_new_command():
|
||||||
|
assert get_new_command(
|
||||||
|
Command('cd..', '', ''), None) == 'cd ..'
|
14
tests/rules/test_cp_omitting_directory.py
Normal file
14
tests/rules/test_cp_omitting_directory.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from mock import Mock
|
||||||
|
from thefuck.rules.cp_omitting_directory import match, get_new_command
|
||||||
|
|
||||||
|
|
||||||
|
def test_match():
|
||||||
|
assert match(Mock(script='cp dir', stderr="cp: omitting directory 'dir'"),
|
||||||
|
None)
|
||||||
|
assert not match(Mock(script='some dir',
|
||||||
|
stderr="cp: omitting directory 'dir'"), None)
|
||||||
|
assert not match(Mock(script='cp dir', stderr=""), None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_new_command():
|
||||||
|
assert get_new_command(Mock(script='cp dir'), None) == 'cp -a dir'
|
20
tests/rules/test_has_exists_script.py
Normal file
20
tests/rules/test_has_exists_script.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from mock import Mock, patch
|
||||||
|
from thefuck.rules. has_exists_script import match, get_new_command
|
||||||
|
|
||||||
|
|
||||||
|
def test_match():
|
||||||
|
with patch('os.path.exists', return_value=True):
|
||||||
|
assert match(Mock(script='main', stderr='main: command not found'),
|
||||||
|
None)
|
||||||
|
assert match(Mock(script='main --help',
|
||||||
|
stderr='main: command not found'),
|
||||||
|
None)
|
||||||
|
assert not match(Mock(script='main', stderr=''), None)
|
||||||
|
|
||||||
|
with patch('os.path.exists', return_value=False):
|
||||||
|
assert not match(Mock(script='main', stderr='main: command not found'),
|
||||||
|
None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_new_command():
|
||||||
|
assert get_new_command(Mock(script='main --help'), None) == './main --help'
|
13
tests/rules/test_mkdir_p.py
Normal file
13
tests/rules/test_mkdir_p.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from thefuck.main import Command
|
||||||
|
from thefuck.rules.mkdir_p import match, get_new_command
|
||||||
|
|
||||||
|
|
||||||
|
def test_match():
|
||||||
|
assert match(Command('mkdir foo/bar/baz', '', 'mkdir: foo/bar: No such file or directory'), None)
|
||||||
|
assert not match(Command('mkdir foo/bar/baz', '', ''), None)
|
||||||
|
assert not match(Command('mkdir foo/bar/baz', '', 'foo bar baz'), None)
|
||||||
|
assert not match(Command('', '', ''), None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_new_command():
|
||||||
|
assert get_new_command(Command('mkdir foo/bar/baz', '', ''), None) == 'mkdir -p foo/bar/baz'
|
9
tests/rules/test_python_command.py
Normal file
9
tests/rules/test_python_command.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from thefuck.main import Command
|
||||||
|
from thefuck.rules.python_command import match, get_new_command
|
||||||
|
|
||||||
|
def test_match():
|
||||||
|
assert match(Command('temp.py', '', 'Permission denied'), None)
|
||||||
|
assert not match(Command('', '', ''), None)
|
||||||
|
|
||||||
|
def test_get_new_command():
|
||||||
|
assert get_new_command(Command('./test_sudo.py', '', ''), None) == 'python ./test_sudo.py'
|
13
tests/rules/test_rm_dir.py
Normal file
13
tests/rules/test_rm_dir.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from thefuck.main import Command
|
||||||
|
from thefuck.rules.rm_dir import match, get_new_command
|
||||||
|
|
||||||
|
|
||||||
|
def test_match():
|
||||||
|
assert match(Command('rm foo', '', 'rm: foo: is a directory'), None)
|
||||||
|
assert not match(Command('rm foo', '', ''), None)
|
||||||
|
assert not match(Command('rm foo', '', 'foo bar baz'), None)
|
||||||
|
assert not match(Command('', '', ''), None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_new_command():
|
||||||
|
assert get_new_command(Command('rm foo', '', ''), None) == 'rm -rf foo'
|
69
tests/rules/test_ssh_known_host.py
Normal file
69
tests/rules/test_ssh_known_host.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
from mock import Mock
|
||||||
|
from thefuck.main import Command
|
||||||
|
from thefuck.rules.ssh_known_hosts import match, get_new_command, remove_offending_keys
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def ssh_error(tmpdir):
|
||||||
|
path = os.path.join(str(tmpdir), 'known_hosts')
|
||||||
|
|
||||||
|
def reset(path):
|
||||||
|
with open(path, 'w') as fh:
|
||||||
|
lines = [
|
||||||
|
'123.234.567.890 asdjkasjdakjsd\n'
|
||||||
|
'98.765.432.321 ejioweojwejrosj\n'
|
||||||
|
'111.222.333.444 qwepoiwqepoiss\n'
|
||||||
|
]
|
||||||
|
fh.writelines(lines)
|
||||||
|
|
||||||
|
def known_hosts(path):
|
||||||
|
with open(path, 'r') as fh:
|
||||||
|
return fh.readlines()
|
||||||
|
|
||||||
|
reset(path)
|
||||||
|
|
||||||
|
errormsg = u"""@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||||
|
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
|
||||||
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||||
|
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
|
||||||
|
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
|
||||||
|
It is also possible that a host key has just been changed.
|
||||||
|
The fingerprint for the RSA key sent by the remote host is
|
||||||
|
b6:cb:07:34:c0:a0:94:d3:0d:69:83:31:f4:c5:20:9b.
|
||||||
|
Please contact your system administrator.
|
||||||
|
Add correct host key in {0} to get rid of this message.
|
||||||
|
Offending RSA key in {0}:2
|
||||||
|
RSA host key for {1} has changed and you have requested strict checking.
|
||||||
|
Host key verification failed.""".format(path, '98.765.432.321')
|
||||||
|
|
||||||
|
return errormsg, path, reset, known_hosts
|
||||||
|
|
||||||
|
|
||||||
|
def test_match(ssh_error):
|
||||||
|
errormsg, _, _, _ = ssh_error
|
||||||
|
assert match(Command('ssh', '', errormsg), None)
|
||||||
|
assert match(Command('ssh', '', errormsg), None)
|
||||||
|
assert match(Command('scp something something', '', errormsg), None)
|
||||||
|
assert match(Command('scp something something', '', errormsg), None)
|
||||||
|
assert not match(Command('', '', errormsg), None)
|
||||||
|
assert not match(Command('notssh', '', errormsg), None)
|
||||||
|
assert not match(Command('ssh', '', ''), None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_remove_offending_keys(ssh_error):
|
||||||
|
errormsg, path, reset, known_hosts = ssh_error
|
||||||
|
command = Command('ssh user@host', '', errormsg)
|
||||||
|
remove_offending_keys(command, None)
|
||||||
|
expected = ['123.234.567.890 asdjkasjdakjsd\n', '111.222.333.444 qwepoiwqepoiss\n']
|
||||||
|
assert known_hosts(path) == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_new_command(ssh_error, monkeypatch):
|
||||||
|
errormsg, _, _, _ = ssh_error
|
||||||
|
|
||||||
|
method = Mock()
|
||||||
|
monkeypatch.setattr('thefuck.rules.ssh_known_hosts.remove_offending_keys', method)
|
||||||
|
assert get_new_command(Command('ssh user@host', '', errormsg), None) == 'ssh user@host'
|
||||||
|
assert method.call_count
|
25
tests/rules/test_switch_lang.py
Normal file
25
tests/rules/test_switch_lang.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
from mock import Mock
|
||||||
|
from thefuck.rules import switch_lang
|
||||||
|
|
||||||
|
|
||||||
|
def test_match():
|
||||||
|
assert switch_lang.match(Mock(stderr='command not found: фзе-пуе',
|
||||||
|
script=u'фзе-пуе'), None)
|
||||||
|
assert switch_lang.match(Mock(stderr='command not found: λσ',
|
||||||
|
script=u'λσ'), None)
|
||||||
|
|
||||||
|
assert not switch_lang.match(Mock(stderr='command not found: pat-get',
|
||||||
|
script=u'pat-get'), None)
|
||||||
|
assert not switch_lang.match(Mock(stderr='command not found: ls',
|
||||||
|
script=u'ls'), None)
|
||||||
|
assert not switch_lang.match(Mock(stderr='some info',
|
||||||
|
script=u'фзе-пуе'), None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_new_command():
|
||||||
|
assert switch_lang.get_new_command(
|
||||||
|
Mock(script=u'фзе-пуе штыефдд мшь'), None) == 'apt-get install vim'
|
||||||
|
assert switch_lang.get_new_command(
|
||||||
|
Mock(script=u'λσ -λα'), None) == 'ls -la'
|
7
tests/test_logs.py
Normal file
7
tests/test_logs.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from mock import Mock
|
||||||
|
from thefuck import logs
|
||||||
|
|
||||||
|
|
||||||
|
def test_color():
|
||||||
|
assert logs.color('red', Mock(no_colors=False)) == 'red'
|
||||||
|
assert logs.color('red', Mock(no_colors=True)) == ''
|
47
thefuck/logs.py
Normal file
47
thefuck/logs.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import sys
|
||||||
|
from traceback import format_exception
|
||||||
|
import colorama
|
||||||
|
|
||||||
|
|
||||||
|
def color(color_, settings):
|
||||||
|
"""Utility for ability to disabling colored output."""
|
||||||
|
if settings.no_colors:
|
||||||
|
return ''
|
||||||
|
else:
|
||||||
|
return color_
|
||||||
|
|
||||||
|
|
||||||
|
def rule_failed(rule, exc_info, settings):
|
||||||
|
sys.stderr.write(
|
||||||
|
u'{warn}[WARN] Rule {name}:{reset}\n{trace}'
|
||||||
|
u'{warn}----------------------------{reset}\n\n'.format(
|
||||||
|
warn=color(colorama.Back.RED + colorama.Fore.WHITE
|
||||||
|
+ colorama.Style.BRIGHT, settings),
|
||||||
|
reset=color(colorama.Style.RESET_ALL, settings),
|
||||||
|
name=rule.name,
|
||||||
|
trace=''.join(format_exception(*exc_info))))
|
||||||
|
|
||||||
|
|
||||||
|
def show_command(new_command, settings):
|
||||||
|
sys.stderr.write('{bold}{command}{reset}\n'.format(
|
||||||
|
command=new_command,
|
||||||
|
bold=color(colorama.Style.BRIGHT, settings),
|
||||||
|
reset=color(colorama.Style.RESET_ALL, settings)))
|
||||||
|
|
||||||
|
|
||||||
|
def confirm_command(new_command, settings):
|
||||||
|
sys.stderr.write(
|
||||||
|
'{bold}{command}{reset} [{green}enter{reset}/{red}ctrl+c{reset}]'.format(
|
||||||
|
command=new_command,
|
||||||
|
bold=color(colorama.Style.BRIGHT, settings),
|
||||||
|
green=color(colorama.Fore.GREEN, settings),
|
||||||
|
red=color(colorama.Fore.RED, settings),
|
||||||
|
reset=color(colorama.Style.RESET_ALL, settings)))
|
||||||
|
sys.stderr.flush()
|
||||||
|
|
||||||
|
|
||||||
|
def failed(msg, settings):
|
||||||
|
sys.stderr.write('{red}{msg}{reset}\n'.format(
|
||||||
|
msg=msg,
|
||||||
|
red=color(colorama.Fore.RED, settings),
|
||||||
|
reset=color(colorama.Style.RESET_ALL, settings)))
|
11
thefuck/rules/has_exists_script.py
Normal file
11
thefuck/rules/has_exists_script.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def match(command, settings):
|
||||||
|
return os.path.exists(command.script.split()[0]) \
|
||||||
|
and 'command not found' in command.stderr
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command, settings):
|
||||||
|
return u'./{}'.format(command.script)
|
||||||
|
|
9
thefuck/rules/mkdir_p.py
Normal file
9
thefuck/rules/mkdir_p.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
def match(command, settings):
|
||||||
|
return ('mkdir' in command.script
|
||||||
|
and 'No such file or directory' in command.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command, settings):
|
||||||
|
return re.sub('^mkdir (.*)', 'mkdir -p \\1', command.script)
|
14
thefuck/rules/python_command.py
Normal file
14
thefuck/rules/python_command.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# add 'python' suffix to the command if
|
||||||
|
# 1) The script does not have execute permission or
|
||||||
|
# 2) is interpreted as shell script
|
||||||
|
|
||||||
|
def match(command, settings):
|
||||||
|
toks = command.script.split()
|
||||||
|
return (len(toks) > 0
|
||||||
|
and toks[0].endswith('.py')
|
||||||
|
and ('Permission denied' in command.stderr or
|
||||||
|
'command not found' in command.stderr))
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command, settings):
|
||||||
|
return 'python ' + command.script
|
9
thefuck/rules/rm_dir.py
Normal file
9
thefuck/rules/rm_dir.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
def match(command, settings):
|
||||||
|
return ('rm' in command.script
|
||||||
|
and 'is a directory' in command.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command, settings):
|
||||||
|
return re.sub('^rm (.*)', 'rm -rf \\1', command.script)
|
37
thefuck/rules/ssh_known_hosts.py
Normal file
37
thefuck/rules/ssh_known_hosts.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
patterns = [
|
||||||
|
r'WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!',
|
||||||
|
r'WARNING: POSSIBLE DNS SPOOFING DETECTED!',
|
||||||
|
r"Warning: the \S+ host key for '([^']+)' differs from the key for the IP address '([^']+)'",
|
||||||
|
]
|
||||||
|
offending_pattern = re.compile(
|
||||||
|
r'(?:Offending (?:key for IP|\S+ key)|Matching host key) in ([^:]+):(\d+)',
|
||||||
|
re.MULTILINE)
|
||||||
|
|
||||||
|
commands = ['ssh', 'scp']
|
||||||
|
|
||||||
|
|
||||||
|
def match(command, settings):
|
||||||
|
if not command.script:
|
||||||
|
return False
|
||||||
|
if not command.script.split()[0] in commands:
|
||||||
|
return False
|
||||||
|
if not any([re.findall(pattern, command.stderr) for pattern in patterns]):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def remove_offending_keys(command, settings):
|
||||||
|
offending = offending_pattern.findall(command.stderr)
|
||||||
|
for filepath, lineno in offending:
|
||||||
|
with open(filepath, 'r') as fh:
|
||||||
|
lines = fh.readlines()
|
||||||
|
del lines[int(lineno) - 1]
|
||||||
|
with open(filepath, 'w') as fh:
|
||||||
|
fh.writelines(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command, settings):
|
||||||
|
remove_offending_keys(command, settings)
|
||||||
|
return command.script
|
31
thefuck/rules/switch_lang.py
Normal file
31
thefuck/rules/switch_lang.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
target_layout = '''qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?'''
|
||||||
|
|
||||||
|
source_layouts = [u'''йцукенгшщзхъфывапролджэячсмитьбю.ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,''',
|
||||||
|
u'''ضصثقفغعهخحجچشسیبلاتنمکگظطزرذدپو./ًٌٍَُِّْ][}{ؤئيإأآة»«:؛كٓژٰٔء><؟''',
|
||||||
|
u''';ςερτυθιοπ[]ασδφγηξκλ΄ζχψωβνμ,./:΅ΕΡΤΥΘΙΟΠ{}ΑΣΔΦΓΗΞΚΛ¨"ΖΧΨΩΒΝΜ<>?''']
|
||||||
|
|
||||||
|
|
||||||
|
def _get_matched_layout(command):
|
||||||
|
for source_layout in source_layouts:
|
||||||
|
if all([ch in source_layout or ch in '-_'
|
||||||
|
for ch in command.script.split(' ')[0]]):
|
||||||
|
return source_layout
|
||||||
|
|
||||||
|
|
||||||
|
def match(command, settings):
|
||||||
|
return 'not found' in command.stderr and _get_matched_layout(command)
|
||||||
|
|
||||||
|
|
||||||
|
def _switch(ch, layout):
|
||||||
|
if ch in layout:
|
||||||
|
return target_layout[layout.index(ch)]
|
||||||
|
else:
|
||||||
|
return ch
|
||||||
|
|
||||||
|
|
||||||
|
def get_new_command(command, settings):
|
||||||
|
matched_layout = _get_matched_layout(command)
|
||||||
|
return ''.join(_switch(ch, matched_layout) for ch in command.script)
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user