Files
urlbot-native/config.py

132 lines
3.2 KiB
Python
Raw Permalink Normal View History

"""
Interface to access:
- local configuration
- shared configuration
- shared runtime state
All configuration is stored in a single ini-file and
persistent state is pickle-dumped into a binary file.
TODO: check lock safety
"""
import json
import logging
import os
import sys
from contextlib import contextmanager
2016-04-05 14:18:22 +02:00
import threading
from fasteners import interprocess_locked
from configobj import ConfigObj
from validate import Validator
CONFIG_SUFFIX = os.environ.get('BOTSUFFIX', '')
__initialized = False
__config_store = ConfigObj(
'local_config{}.ini'.format(CONFIG_SUFFIX),
configspec='local_config.ini.spec',
encoding='utf-8'
)
runtime_config_store = ConfigObj(
'persistent_config.ini'.format(CONFIG_SUFFIX),
configspec='persistent_config.ini.spec',
encoding='utf-8'
)
2016-04-05 14:18:22 +02:00
config_lock = threading.Lock()
result = __config_store.validate(Validator())
# copy is essential to store values with a default.. see configobj.py:2053
assert runtime_config_store.validate(Validator(), copy=True)
# oh look, a bug: https://github.com/DiffSK/configobj/issues/86
# workaround: set the encoding after validating
runtime_config_store.encoding = 'utf-8'
if not result:
print('Config file validation failed!')
sys.exit(1)
else:
__initialized = True
__config_store.write()
2015-12-20 15:24:42 +01:00
def conf_get(key):
if not __initialized:
raise RuntimeError("not __initialized")
try:
return __config_store[key]
except KeyError as e:
logger = logging.getLogger(__name__)
logger.warn('conf(): unknown key ' + str(key))
print(json.dumps(__config_store, indent=2))
raise
2015-12-20 15:24:42 +01:00
def conf_set(key, val):
__config_store[key] = val
__config_store.write()
return None
2015-12-20 15:24:42 +01:00
def runtimeconf_set(key, value):
runtime_config_store[key] = value
runtimeconf_persist()
2015-12-20 15:24:42 +01:00
def runtimeconf_get(key, default=None):
if key is None:
return runtime_config_store
else:
return runtime_config_store.get(key, default=default)
@interprocess_locked(runtime_config_store.filename)
def runtimeconf_persist():
# logging.getLogger(__name__).debug(json.dumps(runtime_config_store, indent=2))
runtime_config_store.write()
2016-04-05 14:18:22 +02:00
def config_locked(f):
"""A decorator that makes access to the config thread-safe"""
def decorate(*args, **kwargs):
config_lock.acquire()
try:
return f(*args, **kwargs)
except:
raise
finally:
config_lock.release()
return decorate
2015-12-20 15:24:42 +01:00
def runtimeconf_deepget(key, default=None):
2015-12-21 10:46:17 +01:00
"""
access a nested key with get("plugins.moin.enabled")
:param key: string of nested properties joined with dots
:param default: default key if None found
:return:
"""
2015-12-20 15:24:42 +01:00
if '.' not in key:
return runtimeconf_get(key, default)
else:
path = key.split('.')
value = runtimeconf_get(path.pop(0))
for p in path:
2015-12-21 10:46:17 +01:00
value = value.get(p, default)
2015-12-20 15:24:42 +01:00
if value is None:
2015-12-21 10:46:17 +01:00
break
2015-12-20 15:24:42 +01:00
return value
@contextmanager
def plugin_config(name):
cfg = runtimeconf_deepget('plugins.{}'.format(name), {})
yield cfg
runtime_config_store['plugins'][name] = cfg
runtimeconf_persist()