mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Add value in set_directive after a commented-out version
When setting a value using set_directive() look for a commented-out version of the directive and add the new value immediately after that to keep the proper context. Related: https://pagure.io/freeipa/issue/3757 Reviewed-By: Christian Heimes <cheimes@redhat.com> Reviewed-By: Stanislav Laznicka <slaznick@redhat.com> Reviewed-By: Rob Crittenden <rcritten@redhat.com>
This commit is contained in:
parent
5531c9f26b
commit
4d2c7a4a75
@ -447,10 +447,11 @@ class DirectiveSetter(object):
|
|||||||
with DirectiveSetter('/path/to/conf') as ds:
|
with DirectiveSetter('/path/to/conf') as ds:
|
||||||
ds.set(key, value)
|
ds.set(key, value)
|
||||||
"""
|
"""
|
||||||
def __init__(self, filename, quotes=True, separator=' '):
|
def __init__(self, filename, quotes=True, separator=' ', comment='#'):
|
||||||
self.filename = os.path.abspath(filename)
|
self.filename = os.path.abspath(filename)
|
||||||
self.quotes = quotes
|
self.quotes = quotes
|
||||||
self.separator = separator
|
self.separator = separator
|
||||||
|
self.comment = comment
|
||||||
self.lines = None
|
self.lines = None
|
||||||
self.stat = None
|
self.stat = None
|
||||||
|
|
||||||
@ -491,17 +492,20 @@ class DirectiveSetter(object):
|
|||||||
finally:
|
finally:
|
||||||
os.close(dirfd)
|
os.close(dirfd)
|
||||||
|
|
||||||
def set(self, directive, value, quotes=_SENTINEL, separator=_SENTINEL):
|
def set(self, directive, value, quotes=_SENTINEL, separator=_SENTINEL,
|
||||||
|
comment=_SENTINEL):
|
||||||
"""Set a single directive
|
"""Set a single directive
|
||||||
"""
|
"""
|
||||||
if quotes is _SENTINEL:
|
if quotes is _SENTINEL:
|
||||||
quotes = self.quotes
|
quotes = self.quotes
|
||||||
if separator is _SENTINEL:
|
if separator is _SENTINEL:
|
||||||
separator = self.separator
|
separator = self.separator
|
||||||
|
if comment is _SENTINEL:
|
||||||
|
comment = self.comment
|
||||||
# materialize lines
|
# materialize lines
|
||||||
# set_directive_lines() modify item, shrink or enlage line count
|
# set_directive_lines() modify item, shrink or enlage line count
|
||||||
self.lines = list(set_directive_lines(
|
self.lines = list(set_directive_lines(
|
||||||
quotes, separator, directive, value, self.lines
|
quotes, separator, directive, value, self.lines, comment
|
||||||
))
|
))
|
||||||
|
|
||||||
def setitems(self, items):
|
def setitems(self, items):
|
||||||
@ -514,7 +518,8 @@ class DirectiveSetter(object):
|
|||||||
self.set(k, v)
|
self.set(k, v)
|
||||||
|
|
||||||
|
|
||||||
def set_directive(filename, directive, value, quotes=True, separator=' '):
|
def set_directive(filename, directive, value, quotes=True, separator=' ',
|
||||||
|
comment='#'):
|
||||||
"""Set a name/value pair directive in a configuration file.
|
"""Set a name/value pair directive in a configuration file.
|
||||||
|
|
||||||
A value of None means to drop the directive.
|
A value of None means to drop the directive.
|
||||||
@ -529,13 +534,15 @@ def set_directive(filename, directive, value, quotes=True, separator=' '):
|
|||||||
unparseable directives.
|
unparseable directives.
|
||||||
:param separator: character serving as separator between directive and
|
:param separator: character serving as separator between directive and
|
||||||
value. Correct value required even when dropping a directive.
|
value. Correct value required even when dropping a directive.
|
||||||
|
:param comment: comment character for the file to keep new values near
|
||||||
|
their commented-out counterpart
|
||||||
"""
|
"""
|
||||||
st = os.stat(filename)
|
st = os.stat(filename)
|
||||||
with open(filename, 'r') as f:
|
with open(filename, 'r') as f:
|
||||||
lines = list(f) # read the whole file
|
lines = list(f) # read the whole file
|
||||||
# materialize new list
|
# materialize new list
|
||||||
new_lines = list(set_directive_lines(
|
new_lines = list(set_directive_lines(
|
||||||
quotes, separator, directive, value, lines
|
quotes, separator, directive, value, lines, comment
|
||||||
))
|
))
|
||||||
with open(filename, 'w') as f:
|
with open(filename, 'w') as f:
|
||||||
# don't construct the whole string; write line-wise
|
# don't construct the whole string; write line-wise
|
||||||
@ -544,7 +551,7 @@ def set_directive(filename, directive, value, quotes=True, separator=' '):
|
|||||||
os.chown(filename, st.st_uid, st.st_gid) # reset perms
|
os.chown(filename, st.st_uid, st.st_gid) # reset perms
|
||||||
|
|
||||||
|
|
||||||
def set_directive_lines(quotes, separator, k, v, lines):
|
def set_directive_lines(quotes, separator, k, v, lines, comment):
|
||||||
"""Set a name/value pair in a configuration (iterable of lines).
|
"""Set a name/value pair in a configuration (iterable of lines).
|
||||||
|
|
||||||
Replaces the value of the key if found, otherwise adds it at
|
Replaces the value of the key if found, otherwise adds it at
|
||||||
@ -560,12 +567,24 @@ def set_directive_lines(quotes, separator, k, v, lines):
|
|||||||
new_line = ''.join([k, separator, v_quoted, '\n'])
|
new_line = ''.join([k, separator, v_quoted, '\n'])
|
||||||
|
|
||||||
found = False
|
found = False
|
||||||
|
addnext = False # add on next line, found a comment
|
||||||
matcher = re.compile(r'\s*{}'.format(re.escape(k + separator)))
|
matcher = re.compile(r'\s*{}'.format(re.escape(k + separator)))
|
||||||
|
cmatcher = re.compile(r'\s*{}\s*{}'.format(comment,
|
||||||
|
re.escape(k + separator)))
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if matcher.match(line):
|
if matcher.match(line):
|
||||||
found = True
|
found = True
|
||||||
|
addnext = False
|
||||||
if v is not None:
|
if v is not None:
|
||||||
yield new_line
|
yield new_line
|
||||||
|
elif addnext:
|
||||||
|
found = True
|
||||||
|
addnext = False
|
||||||
|
yield new_line
|
||||||
|
yield line
|
||||||
|
elif cmatcher.match(line):
|
||||||
|
addnext = True
|
||||||
|
yield line
|
||||||
else:
|
else:
|
||||||
yield line
|
yield line
|
||||||
|
|
||||||
|
@ -30,17 +30,17 @@ def tempdir(request):
|
|||||||
class test_set_directive_lines(object):
|
class test_set_directive_lines(object):
|
||||||
def test_remove_directive(self):
|
def test_remove_directive(self):
|
||||||
lines = installutils.set_directive_lines(
|
lines = installutils.set_directive_lines(
|
||||||
False, '=', 'foo', None, EXAMPLE_CONFIG)
|
False, '=', 'foo', None, EXAMPLE_CONFIG, comment="#")
|
||||||
assert list(lines) == ['foobar=2\n']
|
assert list(lines) == ['foobar=2\n']
|
||||||
|
|
||||||
def test_add_directive(self):
|
def test_add_directive(self):
|
||||||
lines = installutils.set_directive_lines(
|
lines = installutils.set_directive_lines(
|
||||||
False, '=', 'baz', '4', EXAMPLE_CONFIG)
|
False, '=', 'baz', '4', EXAMPLE_CONFIG, comment="#")
|
||||||
assert list(lines) == ['foo=1\n', 'foobar=2\n', 'baz=4\n']
|
assert list(lines) == ['foo=1\n', 'foobar=2\n', 'baz=4\n']
|
||||||
|
|
||||||
def test_set_directive_does_not_clobber_suffix_key(self):
|
def test_set_directive_does_not_clobber_suffix_key(self):
|
||||||
lines = installutils.set_directive_lines(
|
lines = installutils.set_directive_lines(
|
||||||
False, '=', 'foo', '3', EXAMPLE_CONFIG)
|
False, '=', 'foo', '3', EXAMPLE_CONFIG, comment="#")
|
||||||
assert list(lines) == ['foo=3\n', 'foobar=2\n']
|
assert list(lines) == ['foo=3\n', 'foobar=2\n']
|
||||||
|
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ class test_set_directive(object):
|
|||||||
for line in EXAMPLE_CONFIG:
|
for line in EXAMPLE_CONFIG:
|
||||||
f.write(line)
|
f.write(line)
|
||||||
|
|
||||||
installutils.set_directive(filename, 'foo', '3', False, '=')
|
installutils.set_directive(filename, 'foo', '3', False, '=', "#")
|
||||||
|
|
||||||
stat_post = os.stat(filename)
|
stat_post = os.stat(filename)
|
||||||
with open(filename, 'r') as f:
|
with open(filename, 'r') as f:
|
||||||
|
Loading…
Reference in New Issue
Block a user