SafeConfigParserWithIncludes: fixed read of included config-files (expands with localized version, so `inc.local` overwrites options of `inc.conf` for config-files included with before/after);

added new test to cover this case.
pull/2306/head
sebres 2018-12-11 14:48:48 +01:00
parent 555b29e8e6
commit 0245777c84
2 changed files with 62 additions and 1 deletions

View File

@ -73,6 +73,17 @@ else: # pragma: no cover
return self._cp_interpolate_some(option, accum, rest, section, map, *args, **kwargs) return self._cp_interpolate_some(option, accum, rest, section, map, *args, **kwargs)
SafeConfigParser._interpolate_some = _interpolate_some SafeConfigParser._interpolate_some = _interpolate_some
def _expandConfFilesWithLocal(filenames):
"""Expands config files with local extension.
"""
newFilenames = []
for filename in filenames:
newFilenames.append(filename)
localname = os.path.splitext(filename)[0] + '.local'
if localname not in filenames and os.path.isfile(localname):
newFilenames.append(localname)
return newFilenames
# Gets the instance of the logger. # Gets the instance of the logger.
logSys = getLogger(__name__) logSys = getLogger(__name__)
logLevel = 7 logLevel = 7
@ -245,6 +256,7 @@ after = 1.conf
def _getIncludes(self, filenames, seen=[]): def _getIncludes(self, filenames, seen=[]):
if not isinstance(filenames, list): if not isinstance(filenames, list):
filenames = [ filenames ] filenames = [ filenames ]
filenames = _expandConfFilesWithLocal(filenames)
# retrieve or cache include paths: # retrieve or cache include paths:
if self._cfg_share: if self._cfg_share:
# cache/share include list: # cache/share include list:

View File

@ -28,7 +28,8 @@ import re
import shutil import shutil
import tempfile import tempfile
import unittest import unittest
from ..client.configreader import ConfigReader, ConfigReaderUnshared, NoSectionError from ..client.configreader import ConfigReader, ConfigReaderUnshared, \
DefinitionInitConfigReader, NoSectionError
from ..client import configparserinc from ..client import configparserinc
from ..client.jailreader import JailReader, extractOptions from ..client.jailreader import JailReader, extractOptions
from ..client.filterreader import FilterReader from ..client.filterreader import FilterReader
@ -125,6 +126,54 @@ option = %s
self._remove("c.d/90.conf") self._remove("c.d/90.conf")
self.assertEqual(self._getoption(), 2) self.assertEqual(self._getoption(), 2)
def testLocalInIncludes(self):
self._write("c.conf", value=None, content="""
[INCLUDES]
before = ib.conf
after = ia.conf
[Definition]
test = %(default/test)s
""")
self._write("ib.conf", value=None, content="""
[DEFAULT]
test = A
[Definition]
option = 1
""")
self._write("ib.local", value=None, content="""
[DEFAULT]
test = B
[Definition]
option = 2
""")
self._write("ia.conf", value=None, content="""
[DEFAULT]
test = C
[Definition]
oafter = 3
""")
self._write("ia.local", value=None, content="""
[DEFAULT]
test = D
[Definition]
oafter = 4
""")
class TestDefConfReader(DefinitionInitConfigReader):
_configOpts = {
"option": ["int", None],
"oafter": ["int", None],
"test": ["string", None],
}
self.c = TestDefConfReader('c', 'option', {})
self.c.setBaseDir(self.d)
self.assertTrue(self.c.read())
self.c.getOptions({}, all=True)
o = self.c.getCombined()
# test local wins (overwrite all options):
self.assertEqual(o.get('option'), 2)
self.assertEqual(o.get('oafter'), 4)
self.assertEqual(o.get('test'), 'D')
def testInterpolations(self): def testInterpolations(self):
self.assertFalse(self.c.read('i')) # nothing is there yet self.assertFalse(self.c.read('i')) # nothing is there yet
self._write("i.conf", value=None, content=""" self._write("i.conf", value=None, content="""