mirror of
https://git.zavage.net/Zavage-Software/wikicrawl.git
synced 2024-12-04 05:39:20 -07:00
185 lines
6.1 KiB
Python
185 lines
6.1 KiB
Python
import appdirs
|
|
|
|
from . import _util
|
|
import argparse
|
|
import configobj
|
|
import os
|
|
import sys
|
|
import validate
|
|
|
|
from ._bootstrap import _bootstrap_logger
|
|
from . import _util
|
|
|
|
class Config:
|
|
"""
|
|
Structure to store application runtime configuration. Also contains
|
|
functionality to load configuration from local site file.
|
|
"""
|
|
def __init__(self, configspec_filepath=None):
|
|
self.config_obj = None
|
|
self._config_filepaths = []
|
|
self._configspec_filepath = None
|
|
self.configspec_filepath = configspec_filepath
|
|
|
|
def __delitem__(self, key):
|
|
"""
|
|
Deletes the configuration item identified by <key> in the internal
|
|
configuration storage.
|
|
"""
|
|
try:
|
|
del self[key]
|
|
except KeyError as ex:
|
|
pass
|
|
|
|
def __getitem__(self, key):
|
|
"""
|
|
Returns the vaLue of the configuration item identified by <key>.
|
|
"""
|
|
try:
|
|
return self.config_obj[key].dict()
|
|
except KeyError as ex:
|
|
# raise ConfigurationItemNotFoundError()
|
|
raise
|
|
|
|
def __setitem__(self, key, value):
|
|
"""
|
|
Assigns the value of the configuration item
|
|
identified by <key> as <value>.
|
|
"""
|
|
self[key] = value
|
|
|
|
@property
|
|
def config_filepath(self, idx=0):
|
|
"""
|
|
Returns the config filepath (optionally specified by index
|
|
when using multiple config files).
|
|
"""
|
|
assert idx>=0, 'invalid idx argument: index must be greater than 0'
|
|
if len(self._config_filepaths) > 0:
|
|
try:
|
|
return self._config_filepaths[idx]
|
|
except ValueError as ex:
|
|
return
|
|
|
|
@config_filepath.setter
|
|
def config_filepath(self, value, idx=0):
|
|
"""
|
|
Assigns <value> as the config filepath (optionally specified by index
|
|
when using multiple config files).
|
|
"""
|
|
assert idx>=0, 'invalid idx argument: index must be greater than 0'
|
|
self._config_filepaths[idx] = value
|
|
|
|
@property
|
|
def configspec_filepath(self):
|
|
return self._configspec_filepath
|
|
|
|
@configspec_filepath.setter
|
|
def configspec_filepath(self, filepath):
|
|
if _util.does_file_exist(filepath):
|
|
self._configspec_filepath = filepath
|
|
else:
|
|
_bootstrap_logger.error(
|
|
'failed to set config.spec: file not found '
|
|
'(%s)', filepath)
|
|
|
|
def load_config_from_file(self, config_filepath):
|
|
"""
|
|
Loads configuration settings from file, overwritting all configuration.
|
|
"""
|
|
# Record all config.ini files passed in
|
|
if config_filepath not in self._config_filepaths:
|
|
self._config_filepaths.append(config_filepath)
|
|
|
|
# Check for config.spec
|
|
if self.configspec_filepath:
|
|
_bootstrap_logger.info('using config.spec: %s', self.configspec_filepath)
|
|
else:
|
|
_bootstrap_logger.info('config.spec not defined')
|
|
_bootstrap_logger.info('using config file: %s', config_filepath)
|
|
|
|
# Pre-check for config.ini existence
|
|
if _util.does_file_exist(config_filepath):
|
|
_bootstrap_logger.info('existing config file found')
|
|
else:
|
|
_bootstrap_logger.info('no config file found: using defaults')
|
|
|
|
# interpolation='template' changes config file variable replacement to
|
|
# use the form $var instead of %(var)s, which is useful to enable
|
|
# literal %(text)s values in the config.
|
|
try:
|
|
configspec_filepath = self.configspec_filepath
|
|
if configspec_filepath:
|
|
self.config_obj = configobj.ConfigObj(
|
|
config_filepath,
|
|
configspec=configspec_filepath,
|
|
interpolation='template'
|
|
)
|
|
else:
|
|
self.config_obj = configobj.ConfigObj(
|
|
config_filepath,
|
|
# configspec=configspec_filepath,
|
|
interpolation='template'
|
|
)
|
|
except configobj.ParseError as ex:
|
|
msg = 'failed to load config: error in config.spec configuration: {}'.format(config_filepath)
|
|
_bootstrap_logger.error(msg)
|
|
_util.eprint(msg)
|
|
return False
|
|
except OSError as ex:
|
|
msg = 'failed to load config: config.spec file not found'
|
|
_bootstrap_logger.error(msg)
|
|
_util.eprint(msg)
|
|
return False
|
|
|
|
|
|
# Hack the configobj module to alter the interpolation for validate.py:
|
|
configobj.DEFAULT_INTERPOLATION = 'template'
|
|
self.config_obj.filename = config_filepath
|
|
|
|
|
|
if self.configspec_filepath:
|
|
# Validate config.ini against config.spec
|
|
try:
|
|
_bootstrap_logger.info('validating config file against spec')
|
|
val = validate.Validator()
|
|
test = self.config_obj.validate(val, copy=True)
|
|
if test is not True:
|
|
_bootstrap_logger.critical('config file failed validation')
|
|
_bootstrap_logger.critical('config file errors: %s', test)
|
|
return False
|
|
except ValueError as ex:
|
|
_bootstrap_logger.error('failed validating configspec')
|
|
return False
|
|
|
|
# Create the config file if it doesn't exist
|
|
# if not _util.does_file_exist(config_filepath):
|
|
if True:
|
|
_bootstrap_logger.info('writing new config file: %s', config_filepath)
|
|
dirname = os.path.dirname(config_filepath)
|
|
_util.ensure_dir_exists(dirname)
|
|
self.config_obj.write()
|
|
|
|
_bootstrap_logger.info('done loading config file')
|
|
return True
|
|
|
|
def print_config(self):
|
|
"""
|
|
Print configuration to stdout.
|
|
"""
|
|
print('config:')
|
|
|
|
self.config_obj.walk(print)
|
|
for section in self.config_obj.sections:
|
|
print(section)
|
|
for key in self.config_obj[section]:
|
|
print(' ', self.config_obj[section][key])
|
|
|
|
class EnvironmentVariables:
|
|
def __init__(self):
|
|
raise NotImplementedError
|
|
|
|
class ConfigurationItemNotFoundError(Exception):
|
|
pass
|
|
|