#!/usr/bin/env python3 import sys import argparse import re def option_type(s, pat = re.compile(r'\w+=.*')): if not pat.match(s): raise argparse.ArgumentTypeError return s parser = argparse.ArgumentParser(description = 'Edit config file.') parser.add_argument('config', help = 'The configuration file to edit.') parser.add_argument('options', nargs = '*', type = option_type, metavar = '=', help = 'An option to set.') args = parser.parse_args() # Parse config lines and options lines = [] options = {} optRE = re.compile(r'(\w+)\s*=\s*([^#]+)(#.*)?') class Line: def __init__(self, text, name = None, value = None, comment = None): self.text = text self.name = name self.value = value self.comment = comment def __str__(self): if self.name is not None: if self.value.strip(): text = '%s=%s' % (self.name, self.value) if self.comment: text += ' # ' + self.comment text += '\n' return text else: return '' return self.text with open(args.config, 'r') as f: for line in f: m = optRE.match(line.strip()) if m: name, value, comment = m.groups() else: name, value, comment = None, None, None l = Line(line, name, value, comment) lines.append(l) if name is not None: options[name] = l # Save original config config = ''.join(map(str, lines)) # Set options first = True for opt in args.options: name, value = opt.split('=', 1) if name in options: options[name].value = value else: if first and len(lines) and str(lines[:-1]).strip() != '': first = False lines.append(Line('\n')) lines.append(Line(None, name, value, None)) # Assemble new config new_config = ''.join(map(str, lines)) if new_config != config: with open(args.config, 'w') as f: f.write(new_config)