Source code for zensols.grsync.config
"""Specialized application configuration.
"""
__author__ = 'Paul Landes'
from typing import List, Union
import logging
from pathlib import Path
import itertools as it
import re
from zensols.config import YamlConfig
logger = logging.getLogger(__name__)
[docs]
class AppConfig(YamlConfig):
"""Application specific configuration access and parsing.
Since much of the application centers around configuration of what to
persist, this class does more heavy lifting than most configuraetion like
classes.
"""
ROOT = 'discover'
OBJECTS_PATH = f'{ROOT}.objects'
PROFILES_PATH = f'{ROOT}.profiles'
EMPTY_DIR_PATH = f'{ROOT}.empty_dirs'
OBJECTS_PROFILE_PATH = f'{PROFILES_PATH}.{{}}.objects'
EMPTY_DIR_PROFILE_PATH = f'{PROFILES_PATH}.{{}}.empty_dirs'
[docs]
def __init__(self, config_file=None, default_vars=None):
super(AppConfig, self).__init__(
config_file, delimiter='^', default_vars=default_vars)
@property
def _find_profiles(self):
if not self.has_option(self.PROFILES_PATH):
opts = ()
else:
opts = self.get_options(self.PROFILES_PATH)
return opts
@property
def _default_profiles(self):
strlist = self.get_option(f'{self.ROOT}.default_profiles')
if strlist is not None:
return self.split_profiles(strlist)
[docs]
def get_profiles(self, profile_overide: Union[str, List[str]] = None):
if profile_overide is None:
profiles = self._default_profiles
else:
if isinstance(profile_overide, str):
profiles = self.split_profiles(profile_overide)
else:
profiles = profile_overide
if profiles is None:
profiles = self._find_profiles
profiles = list(profiles)
# protect user error
if 'default' not in profiles:
profiles = ['default'] + list(profiles)
if 'nodefault' in profiles:
profiles.pop(profiles.index('default'))
profiles.pop(profiles.index('nodefault'))
return profiles
def _iterate_objects(self, profile):
if profile == 'default':
path = self.OBJECTS_PATH
else:
path = self.OBJECTS_PROFILE_PATH.format(profile)
opts = self.get_options(path)
if opts is None and profile == 'default':
opts = ()
if opts is None:
logger.warning(
f'no such profile for objects: {profile} for path {path}' +
'--maybe entries exist in other profiles')
opts = ()
return map(lambda x: x.strip(), opts)
[docs]
def get_discoverable_objects(self, profiles):
return it.chain(*map(self._iterate_objects, profiles))
[docs]
def get_empty_dirs(self, profiles):
paths = []
for profile in profiles:
if profile == 'default':
path = self.EMPTY_DIR_PATH
else:
path = self.EMPTY_DIR_PROFILE_PATH.format(profile)
opts = self.get_options(path)
if opts is None:
## warnings for missing empty directory entries is worth it
# logger.warning(
# f'no such profile for objects: {profile} for path {path}' +
# '--maybe entries exist in other profiles')
pass
else:
paths.extend(opts)
return map(lambda x: Path(x).expanduser().absolute(), paths)
def _get_path(self, name):
path = self.get_option(name)
if path is None:
raise ValueError('no path defined for option: {name}')
return Path(path).expanduser().absolute()
@property
def dist_dir(self):
return self._get_path(f'{self.ROOT}.local.dist_dir')
@dist_dir.setter
def dist_dir(self, dist_dir):
if self.default_vars is None:
self.default_vars = {}
self.default_vars[f'{self.ROOT}.local.dist_dir'] = dist_dir
@property
def wheel_dir_name(self):
return self._get_path(f'{self.ROOT}.local.wheels_dir')
@property
def bootstrap_script_file(self):
return Path(self.dist_dir, 'bootstrap.sh')