forked from github/pelican
Override settings from the command line
Add a --setting-overrides KEY=VAL command line option to override default settings or those defined in settings files. This adds flexibility in running Pelican and helps reduce sprawl of settings files. Cast int and str setting overrides to their respective types. Support other setting types by treating them as JSON. Fall back to JSON when an override typecast errors. This should make it possible to set int values to None, resp. to JSON 'none'
This commit is contained in:
parent
f80bf187a9
commit
1c50a18d0a
3 changed files with 64 additions and 3 deletions
|
|
@ -23,7 +23,7 @@ from pelican.plugins import signals
|
|||
from pelican.plugins._utils import load_plugins
|
||||
from pelican.readers import Readers
|
||||
from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer
|
||||
from pelican.settings import read_settings
|
||||
from pelican.settings import coerce_overrides, read_settings
|
||||
from pelican.utils import (FileSystemWatcher, clean_output_dir, maybe_pluralize)
|
||||
from pelican.writers import Writer
|
||||
|
||||
|
|
@ -230,6 +230,18 @@ class PrintSettings(argparse.Action):
|
|||
parser.exit()
|
||||
|
||||
|
||||
class ParseDict(argparse.Action):
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
d = {}
|
||||
if values:
|
||||
for item in values:
|
||||
split_items = item.split("=", 1)
|
||||
key = split_items[0].strip()
|
||||
value = split_items[1].strip()
|
||||
d[key] = value
|
||||
setattr(namespace, self.dest, d)
|
||||
|
||||
|
||||
def parse_arguments(argv=None):
|
||||
parser = argparse.ArgumentParser(
|
||||
description='A tool to generate a static blog, '
|
||||
|
|
@ -323,6 +335,18 @@ def parse_arguments(argv=None):
|
|||
help='IP to bind to when serving files via HTTP '
|
||||
'(default: 127.0.0.1)')
|
||||
|
||||
parser.add_argument('-c', '--setting-overrides', dest='overrides',
|
||||
help='Specify one ore more SETTING=VALUE pairs '
|
||||
'(without spaces around =) to override '
|
||||
'settings files. If VALUE contains spaces, add quotes: '
|
||||
'SETTING="VALUE". '
|
||||
'Integers and strings are autoconverted, other values '
|
||||
'can be passed in in json notation, '
|
||||
'e.g. SETTING=none',
|
||||
nargs='*',
|
||||
action=ParseDict
|
||||
)
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
if args.port is not None and not args.listen:
|
||||
|
|
@ -358,6 +382,7 @@ def get_config(args):
|
|||
if args.bind is not None:
|
||||
config['BIND'] = args.bind
|
||||
config['DEBUG'] = args.verbosity == logging.DEBUG
|
||||
config.update(coerce_overrides(args.overrides))
|
||||
|
||||
return config
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import copy
|
||||
import importlib.util
|
||||
import inspect
|
||||
import json
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
|
|
@ -658,3 +659,23 @@ def configure_settings(settings):
|
|||
continue # setting not specified, nothing to do
|
||||
|
||||
return settings
|
||||
|
||||
|
||||
def coerce_overrides(overrides):
|
||||
coerced = {}
|
||||
types_to_cast = {int, str}
|
||||
for k, v in overrides.items():
|
||||
if k not in overrides:
|
||||
logger.warning('Override for unknown setting %s, ignoring', k)
|
||||
continue
|
||||
setting_type = type(DEFAULT_CONFIG[k])
|
||||
if setting_type not in types_to_cast:
|
||||
coerced[k] = json.loads(v)
|
||||
else:
|
||||
try:
|
||||
coerced[k] = setting_type(v)
|
||||
except ValueError:
|
||||
logger.debug('ValueError for %s override with %s, try to '
|
||||
'load as json', k, v)
|
||||
coerced[k] = json.loads(v)
|
||||
return coerced
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ from sys import platform
|
|||
|
||||
from pelican.settings import (DEFAULT_CONFIG, DEFAULT_THEME,
|
||||
_printf_s_to_format_field,
|
||||
configure_settings, handle_deprecated_settings,
|
||||
read_settings)
|
||||
coerce_overrides, configure_settings,
|
||||
handle_deprecated_settings, read_settings)
|
||||
from pelican.tests.support import unittest
|
||||
|
||||
|
||||
|
|
@ -304,3 +304,18 @@ class TestSettingsConfiguration(unittest.TestCase):
|
|||
[(r'C\+\+', 'cpp')] +
|
||||
self.settings['SLUG_REGEX_SUBSTITUTIONS'])
|
||||
self.assertNotIn('SLUG_SUBSTITUTIONS', settings)
|
||||
|
||||
def test_coerce_overrides(self):
|
||||
overrides = coerce_overrides({
|
||||
'ARTICLE_EXCLUDES': '["testexcl"]',
|
||||
'READERS': '{"foo": "bar"}',
|
||||
'STATIC_EXCLUDE_SOURCES': 'true',
|
||||
'THEME_STATIC_DIR': 'theme',
|
||||
})
|
||||
expected = {
|
||||
'ARTICLE_EXCLUDES': ["testexcl"],
|
||||
'READERS': {"foo": "bar"},
|
||||
'STATIC_EXCLUDE_SOURCES': True,
|
||||
'THEME_STATIC_DIR': 'theme',
|
||||
}
|
||||
self.assertDictEqual(overrides, expected)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue