142 lines
4.7 KiB
Python
142 lines
4.7 KiB
Python
# Configuration Helper
|
|
#
|
|
# Copyright (C) 2020 Eric Callahan <arksine.code@gmail.com>
|
|
#
|
|
# This file may be distributed under the terms of the GNU GPLv3 license
|
|
import configparser
|
|
import os
|
|
import logging
|
|
|
|
class ConfigError(Exception):
|
|
pass
|
|
|
|
class Sentinel:
|
|
pass
|
|
|
|
class ConfigHelper:
|
|
error = ConfigError
|
|
def __init__(self, server, config, section, orig_sects, parsed={}):
|
|
self.server = server
|
|
self.config = config
|
|
self.section = section
|
|
self.orig_sections = orig_sects
|
|
self.parsed = parsed
|
|
if self.section not in self.parsed:
|
|
self.parsed[self.section] = {}
|
|
self.sections = config.sections
|
|
self.has_section = config.has_section
|
|
|
|
def get_server(self):
|
|
return self.server
|
|
|
|
def __getitem__(self, key):
|
|
return self.getsection(key)
|
|
|
|
def __contains__(self, key):
|
|
return key in self.config
|
|
|
|
def get_name(self):
|
|
return self.section
|
|
|
|
def get_options(self):
|
|
return dict(self.config[self.section])
|
|
|
|
def get_prefix_sections(self, prefix):
|
|
return [s for s in self.sections() if s.startswith(prefix)]
|
|
|
|
def getsection(self, section):
|
|
if section not in self.config:
|
|
raise ConfigError(f"No section [{section}] in config")
|
|
return ConfigHelper(self.server, self.config, section,
|
|
self.orig_sections, self.parsed)
|
|
|
|
def _get_option(self, func, option, default):
|
|
try:
|
|
val = func(option, default)
|
|
except Exception:
|
|
raise ConfigError(
|
|
f"Error parsing option ({option}) from "
|
|
f"section [{self.section}]")
|
|
if val == Sentinel:
|
|
raise ConfigError(
|
|
f"No option found ({option}) in section [{self.section}]")
|
|
if self.section in self.orig_sections:
|
|
# Only track sections included in the original config
|
|
self.parsed[self.section][option] = val
|
|
return val
|
|
|
|
def get(self, option, default=Sentinel):
|
|
return self._get_option(
|
|
self.config[self.section].get, option, default)
|
|
|
|
def getint(self, option, default=Sentinel):
|
|
return self._get_option(
|
|
self.config[self.section].getint, option, default)
|
|
|
|
def getboolean(self, option, default=Sentinel):
|
|
return self._get_option(
|
|
self.config[self.section].getboolean, option, default)
|
|
|
|
def getfloat(self, option, default=Sentinel):
|
|
return self._get_option(
|
|
self.config[self.section].getfloat, option, default)
|
|
|
|
def read_supplemental_config(self, file_name):
|
|
cfg_file_path = os.path.normpath(os.path.expanduser(file_name))
|
|
if not os.path.isfile(cfg_file_path):
|
|
raise ConfigError(
|
|
f"Configuration File Not Found: '{cfg_file_path}''")
|
|
try:
|
|
self.config.read(cfg_file_path)
|
|
except Exception:
|
|
raise ConfigError(f"Error Reading Config: '{cfg_file_path}'")
|
|
|
|
def write_config(self, file_obj):
|
|
self.config.write(file_obj)
|
|
|
|
def get_parsed_config(self):
|
|
return dict(self.parsed)
|
|
|
|
def validate_config(self):
|
|
for sect in self.orig_sections:
|
|
if sect not in self.parsed:
|
|
logging.warn(
|
|
f"Invalid config section [{sect}] detected. In "
|
|
"the future this will result in a startup error")
|
|
continue
|
|
parsed_opts = self.parsed[sect]
|
|
for opt, val in self.config.items(sect):
|
|
if opt not in parsed_opts:
|
|
logging.warn(
|
|
f"Invalid option '{opt}' detected in section "
|
|
f"[{sect}]. In the future this will result in a "
|
|
"startup error.")
|
|
|
|
def get_configuration(server, system_args):
|
|
cfg_file_path = os.path.normpath(os.path.expanduser(
|
|
system_args.configfile))
|
|
if not os.path.isfile(cfg_file_path):
|
|
raise ConfigError(f"Configuration File Not Found: '{cfg_file_path}''")
|
|
config = configparser.ConfigParser(interpolation=None)
|
|
try:
|
|
config.read(cfg_file_path)
|
|
except Exception:
|
|
raise ConfigError(f"Error Reading Config: '{cfg_file_path}'") from None
|
|
|
|
try:
|
|
server_cfg = config['server']
|
|
except KeyError:
|
|
raise ConfigError("No section [server] in config")
|
|
|
|
orig_sections = config.sections()
|
|
try:
|
|
orig_sections.remove("DEFAULT")
|
|
except Exception:
|
|
pass
|
|
|
|
config['system_args'] = {
|
|
'configfile': system_args.configfile,
|
|
'logfile': system_args.logfile,
|
|
'software_version': system_args.software_version}
|
|
return ConfigHelper(server, config, 'server', orig_sections)
|