2013-08-21 02:27:32 +00:00
|
|
|
#!/usr/bin/python3
|
2014-06-08 21:23:06 +00:00
|
|
|
#
|
|
|
|
# This is a helper tool for editing configuration files during the setup
|
|
|
|
# process. The tool is given new values for settings as command-line
|
|
|
|
# arguments. It comments-out existing setting values in the configuration
|
|
|
|
# file and adds new values either after their former location or at the
|
|
|
|
# end.
|
|
|
|
#
|
|
|
|
# The configuration file has settings that look like:
|
|
|
|
#
|
|
|
|
# NAME=VALUE
|
|
|
|
#
|
|
|
|
# If the -s option is given, then space becomes the delimiter, i.e.:
|
|
|
|
#
|
|
|
|
# NAME VALUE
|
|
|
|
#
|
2022-01-09 15:32:36 +00:00
|
|
|
# If the -e option is given and VALUE is empty, the setting is removed
|
|
|
|
# from the configuration file if it is set (i.e. existing occurrences
|
|
|
|
# are commented out and no new setting is added).
|
|
|
|
#
|
2015-07-02 17:27:05 +00:00
|
|
|
# If the -c option is given, then the supplied character becomes the comment character
|
|
|
|
#
|
2014-06-08 21:23:06 +00:00
|
|
|
# If the -w option is given, then setting lines continue onto following
|
|
|
|
# lines while the lines start with whitespace, e.g.:
|
|
|
|
#
|
|
|
|
# NAME VAL
|
2023-12-22 15:22:21 +00:00
|
|
|
# UE
|
2013-08-21 02:27:32 +00:00
|
|
|
|
|
|
|
import sys, re
|
|
|
|
|
|
|
|
# sanity check
|
|
|
|
if len(sys.argv) < 3:
|
2024-03-23 16:59:39 +00:00
|
|
|
print("usage: python3 editconf.py /etc/file.conf [-e] [-s] [-w] [-c <CHARACTER>] [-t] NAME=VAL [NAME=VAL ...]")
|
2013-08-21 02:27:32 +00:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
# parse command line arguments
|
|
|
|
filename = sys.argv[1]
|
|
|
|
settings = sys.argv[2:]
|
|
|
|
|
2013-08-23 15:59:28 +00:00
|
|
|
delimiter = "="
|
|
|
|
delimiter_re = r"\s*=\s*"
|
2022-01-09 15:32:36 +00:00
|
|
|
erase_setting = False
|
2014-08-15 22:29:05 +00:00
|
|
|
comment_char = "#"
|
2014-06-08 21:23:06 +00:00
|
|
|
folded_lines = False
|
|
|
|
testing = False
|
|
|
|
while settings[0][0] == "-" and settings[0] != "--":
|
|
|
|
opt = settings.pop(0)
|
|
|
|
if opt == "-s":
|
|
|
|
# Space is the delimiter
|
|
|
|
delimiter = " "
|
|
|
|
delimiter_re = r"\s+"
|
2022-01-09 15:32:36 +00:00
|
|
|
elif opt == "-e":
|
|
|
|
# Erase settings that have empty values.
|
|
|
|
erase_setting = True
|
2014-06-08 21:23:06 +00:00
|
|
|
elif opt == "-w":
|
2014-08-15 22:29:05 +00:00
|
|
|
# Line folding is possible in this file.
|
2014-06-08 21:23:06 +00:00
|
|
|
folded_lines = True
|
2014-08-15 22:29:05 +00:00
|
|
|
elif opt == "-c":
|
|
|
|
# Specifies a different comment character.
|
|
|
|
comment_char = settings.pop(0)
|
2014-06-08 21:23:06 +00:00
|
|
|
elif opt == "-t":
|
|
|
|
testing = True
|
|
|
|
else:
|
|
|
|
print("Invalid option.")
|
|
|
|
sys.exit(1)
|
2013-08-23 15:59:28 +00:00
|
|
|
|
2015-04-11 19:25:11 +00:00
|
|
|
# sanity check command line
|
|
|
|
for setting in settings:
|
|
|
|
try:
|
|
|
|
name, value = setting.split("=", 1)
|
|
|
|
except:
|
|
|
|
import subprocess
|
|
|
|
print("Invalid command line: ", subprocess.list2cmdline(sys.argv))
|
|
|
|
|
2013-08-21 02:27:32 +00:00
|
|
|
# create the new config file in memory
|
2014-06-08 21:23:06 +00:00
|
|
|
|
2013-08-21 02:27:32 +00:00
|
|
|
found = set()
|
|
|
|
buf = ""
|
2023-12-23 13:07:25 +00:00
|
|
|
with open(filename, encoding="utf-8") as f:
|
2023-01-15 13:28:43 +00:00
|
|
|
input_lines = list(f)
|
2014-06-08 21:23:06 +00:00
|
|
|
|
|
|
|
while len(input_lines) > 0:
|
|
|
|
line = input_lines.pop(0)
|
|
|
|
|
|
|
|
# If this configuration file uses folded lines, append any folded lines
|
|
|
|
# into our input buffer.
|
2023-12-22 15:10:25 +00:00
|
|
|
if folded_lines and line[0] not in {comment_char, " ", ""}:
|
2014-06-08 21:23:06 +00:00
|
|
|
while len(input_lines) > 0 and input_lines[0][0] in " \t":
|
|
|
|
line += input_lines.pop(0)
|
|
|
|
|
|
|
|
# See if this line is for any settings passed on the command line.
|
2013-08-21 02:27:32 +00:00
|
|
|
for i in range(len(settings)):
|
2022-01-09 15:32:36 +00:00
|
|
|
# Check if this line contain this setting from the command-line arguments.
|
2013-08-21 02:27:32 +00:00
|
|
|
name, val = settings[i].split("=", 1)
|
2014-08-15 22:29:05 +00:00
|
|
|
m = re.match(
|
2023-12-22 15:19:40 +00:00
|
|
|
r"(\s*)"
|
2023-12-23 14:00:04 +00:00
|
|
|
"(" + re.escape(comment_char) + r"\s*)?"
|
2023-12-22 15:19:40 +00:00
|
|
|
+ re.escape(name) + delimiter_re + r"(.*?)\s*$",
|
2014-08-15 22:29:05 +00:00
|
|
|
line, re.S)
|
2014-06-08 21:23:06 +00:00
|
|
|
if not m: continue
|
2014-07-07 11:23:31 +00:00
|
|
|
indent, is_comment, existing_val = m.groups()
|
2014-06-08 21:23:06 +00:00
|
|
|
|
2022-01-09 15:32:36 +00:00
|
|
|
# If this is already the setting, keep it in the file, except:
|
|
|
|
# * If we've already seen it before, then remove this duplicate line.
|
|
|
|
# * If val is empty and erase_setting is on, then comment it out.
|
|
|
|
if is_comment is None and existing_val == val and not (not val and erase_setting):
|
2014-07-08 00:48:22 +00:00
|
|
|
# It may be that we've already inserted this setting higher
|
|
|
|
# in the file so check for that first.
|
|
|
|
if i in found: break
|
2014-06-08 21:23:06 +00:00
|
|
|
buf += line
|
2013-08-21 02:27:32 +00:00
|
|
|
found.add(i)
|
|
|
|
break
|
2023-12-22 15:12:50 +00:00
|
|
|
|
2014-06-08 21:23:06 +00:00
|
|
|
# comment-out the existing line (also comment any folded lines)
|
2014-07-07 11:23:31 +00:00
|
|
|
if is_comment is None:
|
2014-08-15 22:29:05 +00:00
|
|
|
buf += comment_char + line.rstrip().replace("\n", "\n" + comment_char) + "\n"
|
2014-07-07 11:23:31 +00:00
|
|
|
else:
|
|
|
|
# the line is already commented, pass it through
|
|
|
|
buf += line
|
2023-12-22 15:12:50 +00:00
|
|
|
|
2022-01-09 15:32:36 +00:00
|
|
|
# if this option already is set don't add the setting again,
|
|
|
|
# or if we're clearing the setting with -e, don't add it
|
|
|
|
if (i in found) or (not val and erase_setting):
|
2014-06-08 21:23:06 +00:00
|
|
|
break
|
2023-12-22 15:12:50 +00:00
|
|
|
|
2014-06-08 21:23:06 +00:00
|
|
|
# add the new setting
|
2014-07-07 11:23:31 +00:00
|
|
|
buf += indent + name + delimiter + val + "\n"
|
2023-12-22 15:12:50 +00:00
|
|
|
|
2014-06-08 21:23:06 +00:00
|
|
|
# note that we've applied this option
|
|
|
|
found.add(i)
|
2023-12-22 15:12:50 +00:00
|
|
|
|
2014-06-08 21:23:06 +00:00
|
|
|
break
|
2013-08-21 02:27:32 +00:00
|
|
|
else:
|
2013-08-21 13:37:33 +00:00
|
|
|
# If did not match any setting names, pass this line through.
|
2013-08-21 02:27:32 +00:00
|
|
|
buf += line
|
2023-12-22 15:12:50 +00:00
|
|
|
|
2022-01-09 15:32:36 +00:00
|
|
|
# Put any settings we didn't see at the end of the file,
|
|
|
|
# except settings being cleared.
|
2013-08-21 02:27:32 +00:00
|
|
|
for i in range(len(settings)):
|
2022-06-25 16:35:03 +00:00
|
|
|
if i not in found:
|
2013-08-23 15:59:28 +00:00
|
|
|
name, val = settings[i].split("=", 1)
|
2022-06-25 16:35:03 +00:00
|
|
|
if not (not val and erase_setting):
|
|
|
|
buf += name + delimiter + val + "\n"
|
2013-08-21 02:27:32 +00:00
|
|
|
|
2014-06-08 21:23:06 +00:00
|
|
|
if not testing:
|
|
|
|
# Write out the new file.
|
2023-12-23 13:07:25 +00:00
|
|
|
with open(filename, "w", encoding="utf-8") as f:
|
2014-06-08 21:23:06 +00:00
|
|
|
f.write(buf)
|
|
|
|
else:
|
|
|
|
# Just print the new file to stdout.
|
|
|
|
print(buf)
|