Add ability to change settings via environment variables
This commit is contained in:
+120
@@ -0,0 +1,120 @@
|
||||
from copy import copy
|
||||
from imp import load_source
|
||||
import os
|
||||
import sys
|
||||
from six import text_type
|
||||
from . import logs
|
||||
|
||||
|
||||
class RulesList(object):
|
||||
"""Wrapper a top of list for string rules names."""
|
||||
|
||||
def __init__(self, rules):
|
||||
self.rules = rules
|
||||
|
||||
def __contains__(self, item):
|
||||
return item.name in self.rules
|
||||
|
||||
def __getattr__(self, item):
|
||||
return getattr(self.rules, item)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.rules == other
|
||||
|
||||
|
||||
class _DefaultRules(RulesList):
|
||||
def __add__(self, items):
|
||||
return _DefaultRules(self.rules + items)
|
||||
|
||||
def __contains__(self, item):
|
||||
return item.enabled_by_default or \
|
||||
super(_DefaultRules, self).__contains__(item)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, _DefaultRules):
|
||||
return self.rules == other.rules
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
DEFAULT = _DefaultRules([])
|
||||
|
||||
|
||||
class BaseSettings(object):
|
||||
def __init__(self, conf):
|
||||
self._conf = conf
|
||||
|
||||
def __getattr__(self, item):
|
||||
return self._conf.get(item)
|
||||
|
||||
def update(self, **kwargs):
|
||||
"""Returns new settings with new values from `kwargs`."""
|
||||
conf = copy(self._conf)
|
||||
conf.update(kwargs)
|
||||
return BaseSettings(conf)
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
"""Settings loaded from defaults/file/env."""
|
||||
defaults = {'rules': DEFAULT,
|
||||
'wait_command': 3,
|
||||
'require_confirmation': False,
|
||||
'no_colors': False}
|
||||
|
||||
env_to_attr = {'THEFUCK_RULES': 'rules',
|
||||
'THEFUCK_WAIT_COMMAND': 'wait_command',
|
||||
'THEFUCK_REQUIRE_CONFIRMATION': 'require_confirmation',
|
||||
'THEFUCK_NO_COLORS': 'no_colors'}
|
||||
|
||||
def __init__(self, user_dir):
|
||||
super(Settings, self).__init__(self._load_conf(user_dir))
|
||||
|
||||
def _load_conf(self, user_dir):
|
||||
conf = copy(self.defaults)
|
||||
try:
|
||||
conf.update(self._load_from_file(user_dir))
|
||||
except:
|
||||
logs.exception("Can't load settings from file",
|
||||
sys.exc_info(),
|
||||
BaseSettings(conf))
|
||||
try:
|
||||
conf.update(self._load_from_env())
|
||||
except:
|
||||
logs.exception("Can't load settings from env",
|
||||
sys.exc_info(),
|
||||
BaseSettings(conf))
|
||||
if not isinstance(conf['rules'], RulesList):
|
||||
conf['rules'] = RulesList(conf['rules'])
|
||||
return conf
|
||||
|
||||
def _load_from_file(self, user_dir):
|
||||
"""Loads settings from file."""
|
||||
settings = load_source('settings',
|
||||
text_type(user_dir.joinpath('settings.py')))
|
||||
return {key: getattr(settings, key)
|
||||
for key in self.defaults.keys()
|
||||
if hasattr(settings, key)}
|
||||
|
||||
def _load_from_env(self):
|
||||
"""Loads settings from env."""
|
||||
return {attr: self._val_from_env(env, attr)
|
||||
for env, attr in self.env_to_attr.items()
|
||||
if env in os.environ}
|
||||
|
||||
def _val_from_env(self, env, attr):
|
||||
"""Transforms env-strings to python."""
|
||||
val = os.environ[env]
|
||||
if attr == 'rules':
|
||||
val = self._rules_from_env(val)
|
||||
elif attr == 'wait_command':
|
||||
val = int(val)
|
||||
elif attr in ('require_confirmation', 'no_colors'):
|
||||
val = val.lower() == 'true'
|
||||
return val
|
||||
|
||||
def _rules_from_env(self, val):
|
||||
"""Transforms rules list from env-string to python."""
|
||||
val = val.split(':')
|
||||
if 'DEFAULT' in val:
|
||||
val = DEFAULT + [rule for rule in val if rule != 'DEFAULT']
|
||||
return val
|
||||
+7
-3
@@ -11,17 +11,21 @@ def color(color_, settings):
|
||||
return color_
|
||||
|
||||
|
||||
def rule_failed(rule, exc_info, settings):
|
||||
def exception(title, exc_info, settings):
|
||||
sys.stderr.write(
|
||||
u'{warn}[WARN] Rule {name}:{reset}\n{trace}'
|
||||
u'{warn}[WARN] {title}:{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,
|
||||
title=title,
|
||||
trace=''.join(format_exception(*exc_info))))
|
||||
|
||||
|
||||
def rule_failed(rule, exc_info, settings):
|
||||
exception('Rule {}'.format(rule.name), exc_info, settings)
|
||||
|
||||
|
||||
def show_command(new_command, settings):
|
||||
sys.stderr.write('{bold}{command}{reset}\n'.format(
|
||||
command=new_command,
|
||||
|
||||
+3
-27
@@ -7,7 +7,7 @@ import os
|
||||
import sys
|
||||
from psutil import Process, TimeoutExpired
|
||||
import colorama
|
||||
from thefuck import logs
|
||||
from . import logs, conf
|
||||
|
||||
|
||||
Command = namedtuple('Command', ('script', 'stdout', 'stderr'))
|
||||
@@ -25,30 +25,6 @@ def setup_user_dir():
|
||||
return user_dir
|
||||
|
||||
|
||||
def get_settings(user_dir):
|
||||
"""Returns prepared settings module."""
|
||||
settings = load_source('settings',
|
||||
str(user_dir.joinpath('settings.py')))
|
||||
settings.__dict__.setdefault('rules', None)
|
||||
settings.__dict__.setdefault('wait_command', 3)
|
||||
settings.__dict__.setdefault('require_confirmation', False)
|
||||
settings.__dict__.setdefault('no_colors', False)
|
||||
return settings
|
||||
|
||||
|
||||
def is_rule_enabled(settings, rule):
|
||||
"""Returns `True` when rule mentioned in `rules` or `rules`
|
||||
isn't defined.
|
||||
|
||||
"""
|
||||
if settings.rules is None and rule.enabled_by_default:
|
||||
return True
|
||||
elif settings.rules and rule.name in settings.rules:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def load_rule(rule):
|
||||
"""Imports rule module and returns it."""
|
||||
rule_module = load_source(rule.name[:-3], str(rule))
|
||||
@@ -66,7 +42,7 @@ def get_rules(user_dir, settings):
|
||||
for rule in sorted(list(bundled)) + list(user):
|
||||
if rule.name != '__init__.py':
|
||||
loaded_rule = load_rule(rule)
|
||||
if is_rule_enabled(settings, loaded_rule):
|
||||
if loaded_rule in settings.rules:
|
||||
yield loaded_rule
|
||||
|
||||
|
||||
@@ -145,7 +121,7 @@ def is_second_run(command):
|
||||
def main():
|
||||
colorama.init()
|
||||
user_dir = setup_user_dir()
|
||||
settings = get_settings(user_dir)
|
||||
settings = conf.Settings(user_dir)
|
||||
|
||||
command = get_command(settings, sys.argv)
|
||||
if command:
|
||||
|
||||
+1
-4
@@ -37,10 +37,7 @@ def wrap_settings(params):
|
||||
def decorator(fn):
|
||||
@wraps(fn)
|
||||
def wrapper(command, settings):
|
||||
for key, val in params.items():
|
||||
if not hasattr(settings, key):
|
||||
setattr(settings, key, val)
|
||||
return fn(command, settings)
|
||||
return fn(command, settings.update(**params))
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
Reference in New Issue
Block a user