Merge pull request #2291 from dalf/settings2

[enh] user settings can relied on the default settings
This commit is contained in:
Alexandre Flament 2020-12-01 14:57:12 +01:00 committed by GitHub
commit a1e6bc4cee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 499 additions and 28 deletions

View file

@ -16,39 +16,15 @@ along with searx. If not, see < http://www.gnu.org/licenses/ >.
'''
import logging
import searx.settings_loader
from os import environ
from os.path import realpath, dirname, join, abspath, isfile
from io import open
from yaml import safe_load
searx_dir = abspath(dirname(__file__))
engine_dir = dirname(realpath(__file__))
static_path = abspath(join(dirname(__file__), 'static'))
def check_settings_yml(file_name):
if isfile(file_name):
return file_name
else:
return None
# find location of settings.yml
if 'SEARX_SETTINGS_PATH' in environ:
# if possible set path to settings using the
# enviroment variable SEARX_SETTINGS_PATH
settings_path = check_settings_yml(environ['SEARX_SETTINGS_PATH'])
else:
# if not, get it from searx code base or last solution from /etc/searx
settings_path = check_settings_yml(join(searx_dir, 'settings.yml')) or check_settings_yml('/etc/searx/settings.yml')
if not settings_path:
raise Exception('settings.yml not found')
# load settings
with open(settings_path, 'r', encoding='utf-8') as settings_yaml:
settings = safe_load(settings_yaml)
settings, settings_load_message = searx.settings_loader.load_settings()
if settings['ui']['static_path']:
static_path = settings['ui']['static_path']
@ -58,7 +34,6 @@ enable debug if
the environnement variable SEARX_DEBUG is 1 or true
(whatever the value in settings.yml)
or general.debug=True in settings.yml
disable debug if
the environnement variable SEARX_DEBUG is 0 or false
(whatever the value in settings.yml)
@ -78,7 +53,7 @@ else:
logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger('searx')
logger.debug('read configuration from %s', settings_path)
logger.info(settings_load_message)
logger.info('Initialisation done')
if 'SEARX_SECRET' in environ:

View file

@ -31,3 +31,11 @@ class SearxParameterException(SearxException):
self.message = message
self.parameter_name = name
self.parameter_value = value
class SearxSettingsException(SearxException):
def __init__(self, message, filename):
super().__init__(message)
self.message = message
self.filename = filename

129
searx/settings_loader.py Normal file
View file

@ -0,0 +1,129 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
from os import environ
from os.path import dirname, join, abspath, isfile
from collections.abc import Mapping
from itertools import filterfalse
import yaml
from searx.exceptions import SearxSettingsException
searx_dir = abspath(dirname(__file__))
def check_settings_yml(file_name):
if isfile(file_name):
return file_name
return None
def load_yaml(file_name):
try:
with open(file_name, 'r', encoding='utf-8') as settings_yaml:
return yaml.safe_load(settings_yaml)
except IOError as e:
raise SearxSettingsException(e, file_name)
except yaml.YAMLError as e:
raise SearxSettingsException(e, file_name)
def get_default_settings_path():
return check_settings_yml(join(searx_dir, 'settings.yml'))
def get_user_settings_path():
# find location of settings.yml
if 'SEARX_SETTINGS_PATH' in environ:
# if possible set path to settings using the
# enviroment variable SEARX_SETTINGS_PATH
return check_settings_yml(environ['SEARX_SETTINGS_PATH'])
# if not, get it from searx code base or last solution from /etc/searx
return check_settings_yml('/etc/searx/settings.yml')
def update_dict(default_dict, user_dict):
for k, v in user_dict.items():
if isinstance(v, Mapping):
default_dict[k] = update_dict(default_dict.get(k, {}), v)
else:
default_dict[k] = v
return default_dict
def update_settings(default_settings, user_settings):
# merge everything except the engines
for k, v in user_settings.items():
if k not in ('use_default_settings', 'engines'):
update_dict(default_settings[k], v)
# parse the engines
remove_engines = None
keep_only_engines = None
use_default_settings = user_settings.get('use_default_settings')
if isinstance(use_default_settings, dict):
remove_engines = use_default_settings.get('engines', {}).get('remove')
keep_only_engines = use_default_settings.get('engines', {}).get('keep_only')
if 'engines' in user_settings or remove_engines is not None or keep_only_engines is not None:
engines = default_settings['engines']
# parse "use_default_settings.engines.remove"
if remove_engines is not None:
engines = list(filterfalse(lambda engine: (engine.get('name')) in remove_engines, engines))
# parse "use_default_settings.engines.keep_only"
if keep_only_engines is not None:
engines = list(filter(lambda engine: (engine.get('name')) in keep_only_engines, engines))
# parse "engines"
user_engines = user_settings.get('engines')
if user_engines:
engines_dict = dict((definition['name'], definition) for definition in engines)
for user_engine in user_engines:
default_engine = engines_dict.get(user_engine['name'])
if default_engine:
update_dict(default_engine, user_engine)
else:
engines.append(user_engine)
# store the result
default_settings['engines'] = engines
return default_settings
def is_use_default_settings(user_settings):
use_default_settings = user_settings.get('use_default_settings')
if use_default_settings is True:
return True
if isinstance(use_default_settings, dict):
return True
if use_default_settings is False or use_default_settings is None:
return False
raise ValueError('Invalid value for use_default_settings')
def load_settings(load_user_setttings=True):
default_settings_path = get_default_settings_path()
user_settings_path = get_user_settings_path()
if user_settings_path is None or not load_user_setttings:
# no user settings
return (load_yaml(default_settings_path),
'load the default settings from {}'.format(default_settings_path))
# user settings
user_settings = load_yaml(user_settings_path)
if is_use_default_settings(user_settings):
# the user settings are merged with the default configuration
default_settings = load_yaml(default_settings_path)
update_settings(default_settings, user_settings)
return (default_settings,
'merge the default settings ( {} ) and the user setttings ( {} )'
.format(default_settings_path, user_settings_path))
# the user settings, fully replace the default configuration
return (user_settings,
'load the user settings from {}'.format(user_settings_path))