Add an "include" directive for the config files to read multiple config files.

This commit is contained in:
Kovid Goyal 2018-04-01 10:19:21 +05:30
parent 530fd61125
commit 1c78633d1a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 51 additions and 21 deletions

View File

@ -2,11 +2,12 @@
# vim:fileencoding=utf-8 # vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import os
import re import re
from collections import namedtuple from collections import namedtuple
from .utils import log_error
from .rgb import to_color as as_color from .rgb import to_color as as_color
from .utils import log_error
key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$') key_pat = re.compile(r'([a-zA-Z][a-zA-Z0-9_-]*)\s+(.+)$')
@ -31,33 +32,57 @@ def to_bool(x):
return x.lower() in 'y yes true'.split() return x.lower() in 'y yes true'.split()
def parse_config_base( def parse_line(line, type_map, special_handling, ans, all_keys, base_path_for_includes):
lines, defaults, type_map, special_handling, ans, check_keys=True
):
if check_keys:
all_keys = defaults._asdict()
for line in lines:
line = line.strip() line = line.strip()
if not line or line.startswith('#'): if not line or line.startswith('#'):
continue return
m = key_pat.match(line) m = key_pat.match(line)
if m is not None: if m is not None:
key, val = m.groups() key, val = m.groups()
if special_handling(key, val, ans): if special_handling(key, val, ans):
continue return
if check_keys: if key == 'include':
if key not in all_keys: val = val.strip()
if not os.path.isabs(val):
val = os.path.join(base_path_for_includes, val)
try:
with open(val, encoding='utf-8', errors='replace') as include:
_parse(include, type_map, special_handling, ans, all_keys)
except FileNotFoundError:
log_error('Could not find included config file: {}, ignoring'.format(val))
except EnvironmentError:
log_error('Could not read from included config file: {}, ignoring'.format(val))
return
if all_keys is not None and key not in all_keys:
log_error('Ignoring unknown config key: {}'.format(key)) log_error('Ignoring unknown config key: {}'.format(key))
continue return
tm = type_map.get(key) tm = type_map.get(key)
if tm is not None: if tm is not None:
val = tm(val) val = tm(val)
ans[key] = val ans[key] = val
def _parse(lines, type_map, special_handling, ans, all_keys):
name = getattr(lines, 'name', None)
if name:
base_path_for_includes = os.path.dirname(os.path.abspath(name))
else:
from .constants import config_dir
base_path_for_includes = config_dir
for line in lines:
parse_line(line, type_map, special_handling, ans, all_keys, base_path_for_includes)
def parse_config_base(
lines, defaults, type_map, special_handling, ans, check_keys=True
):
all_keys = defaults._asdict() if check_keys else None
_parse(lines, type_map, special_handling, ans, all_keys)
def init_config(defaults_path, parse_config): def init_config(defaults_path, parse_config):
with open(defaults_path, encoding='utf-8', errors='replace') as f: with open(defaults_path, encoding='utf-8', errors='replace') as f:
defaults = parse_config(f.read().splitlines(), check_keys=False) defaults = parse_config(f, check_keys=False)
Options = namedtuple('Defaults', ','.join(defaults.keys())) Options = namedtuple('Defaults', ','.join(defaults.keys()))
defaults = Options(**defaults) defaults = Options(**defaults)
return Options, defaults return Options, defaults

View File

@ -1,5 +1,10 @@
# vim:fileencoding=utf-8:ft=conf # vim:fileencoding=utf-8:ft=conf
# You can include secondary config files via the "include" directive.
# If you use a relative path for include, it is resolved with respect to the
# location od the current config file. For example:
# include other.conf
# Fonts {{{ # Fonts {{{
# Font family. You can also specify different fonts for the # Font family. You can also specify different fonts for the
# bold/italic/bold-italic variants. By default they are derived automatically, # bold/italic/bold-italic variants. By default they are derived automatically,