From 5f79217e97fc5617f03bdbe7121a7dee8cdb7927 Mon Sep 17 00:00:00 2001 From: Vladimir Iakovlev Date: Sat, 13 Aug 2016 18:55:11 +0300 Subject: [PATCH] #N/A: Add `slow_commands` and `wait_slow_command` settings options --- README.md | 11 +++++++++-- tests/test_conf.py | 6 +++++- thefuck/conf.py | 6 +++--- thefuck/const.py | 6 +++++- thefuck/types.py | 26 +++++++++++++++----------- 5 files changed, 37 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 75bf43fc..d736c585 100644 --- a/README.md +++ b/README.md @@ -303,7 +303,9 @@ The Fuck has a few settings parameters which can be changed in `$XDG_CONFIG_HOME * `priority` – dict with rules priorities, rule with lower `priority` will be matched first; * `debug` – enables debug output, by default `False`; * `history_limit` – numeric value of how many history commands will be scanned, like `2000`; -* `alter_history` – push fixed command to history, by default `True`. +* `alter_history` – push fixed command to history, by default `True`; +* `wait_slow_command` – max amount of time in seconds for getting previous command output if it in `slow_commands` list; +* `slow_commands` – list of slow commands. Example of `settings.py`: @@ -315,6 +317,9 @@ wait_command = 10 no_colors = False priority = {'sudo': 100, 'no_command': 9999} debug = False +history_limit = 9999 +wait_slow_command = 20 +slow_commands = ['react-native', 'gradle'] ``` Or via environment variables: @@ -328,7 +333,9 @@ Or via environment variables: rule with lower `priority` will be matched first; * `THEFUCK_DEBUG` – enables debug output, `true/false`; * `THEFUCK_HISTORY_LIMIT` – how many history commands will be scanned, like `2000`; -* `THEFUCK_ALTER_HISTORY` – push fixed command to history `true/false`. +* `THEFUCK_ALTER_HISTORY` – push fixed command to history `true/false`; +* `THEFUCK_WAIT_SLOW_COMMAND` – max amount of time in seconds for getting previous command output if it in `slow_commands` list; +* `THEFUCK_SLOW_COMMANDS` – list of slow commands, like `lein:gradle`. For example: diff --git a/tests/test_conf.py b/tests/test_conf.py index db894031..b8ab5d9f 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -59,7 +59,9 @@ class TestSettingsFromEnv(object): 'THEFUCK_WAIT_COMMAND': '55', 'THEFUCK_REQUIRE_CONFIRMATION': 'true', 'THEFUCK_NO_COLORS': 'false', - 'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15'}) + 'THEFUCK_PRIORITY': 'bash=10:lisp=wrong:vim=15', + 'THEFUCK_WAIT_SLOW_COMMAND': '999', + 'THEFUCK_SLOW_COMMANDS': 'lein:react-native:./gradlew'}) settings.init() assert settings.rules == ['bash', 'lisp'] assert settings.exclude_rules == ['git', 'vim'] @@ -67,6 +69,8 @@ class TestSettingsFromEnv(object): assert settings.require_confirmation is True assert settings.no_colors is False assert settings.priority == {'bash': 10, 'vim': 15} + assert settings.wait_slow_command == 999 + assert settings.slow_commands == ['lein', 'react-native', './gradlew'] def test_from_env_with_DEFAULT(self, environ, settings): environ.update({'THEFUCK_RULES': 'DEFAULT_RULES:bash:lisp'}) diff --git a/thefuck/conf.py b/thefuck/conf.py index 755d3ff9..5ae87d3a 100644 --- a/thefuck/conf.py +++ b/thefuck/conf.py @@ -92,13 +92,13 @@ class Settings(dict): return self._rules_from_env(val) elif attr == 'priority': return dict(self._priority_from_env(val)) - elif attr == 'wait_command': + elif attr in ('wait_command', 'history_limit', 'wait_slow_command'): return int(val) elif attr in ('require_confirmation', 'no_colors', 'debug', 'alter_history'): return val.lower() == 'true' - elif attr == 'history_limit': - return int(val) + elif attr == 'slow_commands': + return val.split(':') else: return val diff --git a/thefuck/const.py b/thefuck/const.py index 6c4d3491..4ca546c4 100644 --- a/thefuck/const.py +++ b/thefuck/const.py @@ -31,6 +31,8 @@ DEFAULT_SETTINGS = {'rules': DEFAULT_RULES, 'priority': {}, 'history_limit': None, 'alter_history': True, + 'wait_slow_command': 15, + 'slow_commands': ['lein'], 'env': {'LC_ALL': 'C', 'LANG': 'C', 'GIT_TRACE': '1'}} ENV_TO_ATTR = {'THEFUCK_RULES': 'rules', @@ -41,7 +43,9 @@ ENV_TO_ATTR = {'THEFUCK_RULES': 'rules', 'THEFUCK_DEBUG': 'debug', 'THEFUCK_PRIORITY': 'priority', 'THEFUCK_HISTORY_LIMIT': 'history_limit', - 'THEFUCK_ALTER_HISTORY': 'alter_history'} + 'THEFUCK_ALTER_HISTORY': 'alter_history', + 'THEFUCK_WAIT_SLOW_COMMAND': 'wait_slow_command', + 'THEFUCK_SLOW_COMMANDS': 'slow_commands'} SETTINGS_HEADER = u"""# The Fuck settings file # diff --git a/thefuck/types.py b/thefuck/types.py index 30968be1..742f52ec 100644 --- a/thefuck/types.py +++ b/thefuck/types.py @@ -34,7 +34,7 @@ class Command(object): self._script_parts = shell.split_command(self.script) except Exception: logs.debug(u"Can't split command script {} because:\n {}".format( - self, sys.exc_info())) + self, sys.exc_info())) self._script_parts = None return self._script_parts @@ -47,7 +47,7 @@ class Command(object): def __repr__(self): return u'Command(script={}, stdout={}, stderr={})'.format( - self.script, self.stdout, self.stderr) + self.script, self.stdout, self.stderr) def update(self, **kwargs): """Returns new command with replaced fields. @@ -61,7 +61,7 @@ class Command(object): return Command(**kwargs) @staticmethod - def _wait_output(popen): + def _wait_output(popen, is_slow): """Returns `True` if we can get output of the command in the `settings.wait_command` time. @@ -73,7 +73,8 @@ class Command(object): """ proc = Process(popen.pid) try: - proc.wait(settings.wait_command) + proc.wait(settings.wait_slow_command if is_slow + else settings.wait_command) return True except TimeoutExpired: for child in proc.children(recursive=True): @@ -113,9 +114,12 @@ class Command(object): env = dict(os.environ) env.update(settings.env) - with logs.debug_time(u'Call: {}; with env: {};'.format(script, env)): - result = Popen(script, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env) - if cls._wait_output(result): + is_slow = script.split(' ')[0] in settings.slow_commands + with logs.debug_time(u'Call: {}; with env: {}; is slow: '.format( + script, env, is_slow)): + result = Popen(script, shell=True, stdin=PIPE, + stdout=PIPE, stderr=PIPE, env=env) + if cls._wait_output(result, is_slow): stdout = result.stdout.read().decode('utf-8') stderr = result.stderr.read().decode('utf-8') @@ -168,9 +172,9 @@ class Rule(object): return 'Rule(name={}, match={}, get_new_command={}, ' \ 'enabled_by_default={}, side_effect={}, ' \ 'priority={}, requires_output)'.format( - self.name, self.match, self.get_new_command, - self.enabled_by_default, self.side_effect, - self.priority, self.requires_output) + self.name, self.match, self.get_new_command, + self.enabled_by_default, self.side_effect, + self.priority, self.requires_output) @classmethod def from_path(cls, path): @@ -270,7 +274,7 @@ class CorrectedCommand(object): def __repr__(self): return u'CorrectedCommand(script={}, side_effect={}, priority={})'.format( - self.script, self.side_effect, self.priority) + self.script, self.side_effect, self.priority) def run(self, old_cmd): """Runs command from rule for passed command.