##// END OF EJS Templates
added latest changes
added latest changes

File last commit:

r5608:6d33e504 default
r5658:a109f5ac merge default
Show More
settings_maker.py
187 lines | 6.3 KiB | text/x-python | PythonLexer
core: updated copyright to 2024
r5608 # Copyright (C) 2010-2024 RhodeCode GmbH
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823 #
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import os
import textwrap
import string
import functools
import logging
import tempfile
import logging.config
chore(sync-up): synced libs/settings maker from vcsserver
r5337
configs: refactor and updated for python3 migrations
r5060 from rhodecode.lib.type_utils import str2bool, aslist
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823 log = logging.getLogger(__name__)
configs: refactor and updated for python3 migrations
r5060
env: small fixes to sync with vcsserver settings maker
r4826 # skip keys, that are set here, so we don't double process those
set_keys = {
'__file__': ''
}
env-config: use proper ALL keys reconfiguration based on env vars
r4825
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823
chore(sync-up): synced libs/settings maker from vcsserver
r5337 class SettingsMaker:
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823
def __init__(self, app_settings):
self.settings = app_settings
@classmethod
def _bool_func(cls, input_val):
chore(sync-up): synced libs/settings maker from vcsserver
r5337 if isinstance(input_val, bytes):
# decode to str
input_val = input_val.decode('utf8')
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823 return str2bool(input_val)
@classmethod
def _int_func(cls, input_val):
return int(input_val)
@classmethod
configs: refactor and updated for python3 migrations
r5060 def _float_func(cls, input_val):
return float(input_val)
@classmethod
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823 def _list_func(cls, input_val, sep=','):
return aslist(input_val, sep=sep)
@classmethod
def _string_func(cls, input_val, lower=True):
if lower:
input_val = input_val.lower()
return input_val
@classmethod
chore(sync-up): synced libs/settings maker from vcsserver
r5337 def _string_no_quote_func(cls, input_val, lower=True):
"""
Special case string function that detects if value is set to empty quote string
e.g.
core.binar_dir = ""
"""
input_val = cls._string_func(input_val, lower=lower)
if input_val in ['""', "''"]:
return ''
@classmethod
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823 def _dir_func(cls, input_val, ensure_dir=False, mode=0o755):
# ensure we have our dir created
if not os.path.isdir(input_val) and ensure_dir:
chore(sync-up): synced libs/settings maker from vcsserver
r5337 os.makedirs(input_val, mode=mode, exist_ok=True)
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823
if not os.path.isdir(input_val):
modernize: updates for python3
r5095 raise Exception(f'Dir at {input_val} does not exist')
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823 return input_val
@classmethod
def _file_path_func(cls, input_val, ensure_dir=False, mode=0o755):
dirname = os.path.dirname(input_val)
cls._dir_func(dirname, ensure_dir=ensure_dir)
return input_val
@classmethod
def _key_transformator(cls, key):
return "{}_{}".format('RC'.upper(), key.upper().replace('.', '_').replace('-', '_'))
env-config: use proper ALL keys reconfiguration based on env vars
r4825 def maybe_env_key(self, key):
# now maybe we have this KEY in env, search and use the value with higher priority.
transformed_key = self._key_transformator(key)
envvar_value = os.environ.get(transformed_key)
if envvar_value:
log.debug('using `%s` key instead of `%s` key for config', transformed_key, key)
return envvar_value
def env_expand(self):
fix(tests): explicitly disable env_expand for test suite to prevent problems with DB connections during tests
r5549 if self.settings.get('rhodecode.env_expand') == 'false':
return
env-config: use proper ALL keys reconfiguration based on env vars
r4825 replaced = {}
for k, v in self.settings.items():
if k not in set_keys:
envvar_value = self.maybe_env_key(k)
if envvar_value:
replaced[k] = envvar_value
set_keys[k] = envvar_value
# replace ALL keys updated
self.settings.update(replaced)
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823 def enable_logging(self, logging_conf=None, level='INFO', formatter='generic'):
"""
Helper to enable debug on running instance
:return:
"""
if not str2bool(self.settings.get('logging.autoconfigure')):
log.info('logging configuration based on main .ini file')
return
if logging_conf is None:
logging_conf = self.settings.get('logging.logging_conf_file') or ''
if not os.path.isfile(logging_conf):
env-config: use proper ALL keys reconfiguration based on env vars
r4825 log.error('Unable to setup logging based on %s, '
'file does not exist.... specify path using logging.logging_conf_file= config setting. ', logging_conf)
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823 return
configs: refactor and updated for python3 migrations
r5060 with open(logging_conf, 'rt') as f:
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823 ini_template = textwrap.dedent(f.read())
ini_template = string.Template(ini_template).safe_substitute(
RC_LOGGING_LEVEL=os.environ.get('RC_LOGGING_LEVEL', '') or level,
RC_LOGGING_FORMATTER=os.environ.get('RC_LOGGING_FORMATTER', '') or formatter
)
with tempfile.NamedTemporaryFile(prefix='rc_logging_', suffix='.ini', delete=False) as f:
log.info('Saved Temporary LOGGING config at %s', f.name)
f.write(ini_template)
logging.config.fileConfig(f.name)
os.remove(f.name)
def make_setting(self, key, default, lower=False, default_when_empty=False, parser=None):
input_val = self.settings.get(key, default)
if default_when_empty and not input_val:
# use default value when value is set in the config but it is empty
input_val = default
parser_func = {
'bool': self._bool_func,
'int': self._int_func,
configs: refactor and updated for python3 migrations
r5060 'float': self._float_func,
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823 'list': self._list_func,
'list:newline': functools.partial(self._list_func, sep='/n'),
'list:spacesep': functools.partial(self._list_func, sep=' '),
'string': functools.partial(self._string_func, lower=lower),
chore(sync-up): synced libs/settings maker from vcsserver
r5337 'string:noquote': functools.partial(self._string_no_quote_func, lower=lower),
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823 'dir': self._dir_func,
'dir:ensured': functools.partial(self._dir_func, ensure_dir=True),
'file': self._file_path_func,
'file:ensured': functools.partial(self._file_path_func, ensure_dir=True),
None: lambda i: i
}[parser]
env-config: use proper ALL keys reconfiguration based on env vars
r4825 envvar_value = self.maybe_env_key(key)
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823 if envvar_value:
input_val = envvar_value
env-config: use proper ALL keys reconfiguration based on env vars
r4825 set_keys[key] = input_val
config: major update for the code to make it be almost fully controllable via env for new docker based installer.
r4823 self.settings[key] = parser_func(input_val)
return self.settings[key]