Skip to content
Snippets Groups Projects
setconfig 3.26 KiB
#! /usr/bin/env python
'''\
Change configuration using command line

$Id$
'''

from __future__ import print_function

import argparse
import io
import re
import sys

from expconfig import ConfigObj

from expargparse import assigns_to_dicts, get_key_chain
from feedback import die
import package_info

#
# Main routine
#

# Check command line

command_line = argparse.ArgumentParser(description=__doc__.split('\n', 1)[0])
command_line.add_argument('config', nargs='?', default='-', 
                          help='original configuration file name [%(default)s]')
command_line.add_argument('assigns', metavar='key=value', nargs='*',
                           help='override configuration file settings')
command_line.add_argument('-V', '--version', action='version',
                          version=package_info.version)
command_line.add_argument('--delete', '-d', action='append', default=[],
                          help='remove given keys from configuration')
command_line.add_argument('--header', '-H', action='append', default=[],
                          help='append text to header (initial comment)')
command_line.add_argument('--add', '-a', action='append', default=[],
                          help='add settings from file')
command_line.add_argument('--inline-comments' , '-c', action='store_true',
                          help='compact white space before inline comments'
                               ' (BETA)')
command_line.add_argument('--trailing-space' , '-t', action='store_true',
                          help='remove white space at end of lines')
command_line.add_argument('--keep-section-quotes', action='store_true',
                          help='do not remove quotes from section names')

args = command_line.parse_args()

# File handling

try:
    config_file = args.config
    if config_file == '-':
        config_file = sys.stdin
    config_data = ConfigObj(config_file, file_error=True,
                            write_empty_values=True)
    # Add settings from other files
    for add_file in args.add:
        if add_file == '-':
            add_file = sys.stdin
        config_data.merge(ConfigObj(add_file, file_error=True))
except IOError as error:
    die(error.message)

# Remove keys from --delete command line option

for current in args.delete:
    config = config_data
    chain = get_key_chain(current)
    chain.reverse()
    key = chain.pop()
    for section in chain:
        config = config[section]
    del config[key]

# Merge key=value assignments from command line

if args.assigns:
    for d in assigns_to_dicts(args):
        config_data.merge(d)

# Add lines to header

back_plate = []
for line in reversed(config_data.initial_comment):
    if re.match(r'^[\s#]*$', line):
        back_plate.insert(0, config_data.initial_comment.pop())
    else:
        break

for line in args.header:
    config_data.initial_comment.append(line)

for line in back_plate:
    config_data.initial_comment.append(line)

# Ready to roll out

lines = io.BytesIO()
config_data.write(lines)

lines.seek(0)
for line in io.TextIOWrapper(lines):
    if args.inline_comments: line = re.sub(r' = (.*?)  #', r' = \1 #', line)
    if not args.keep_section_quotes: line = re.sub(r'\["(.*?)"\]', r'[\1]', line)
    if args.trailing_space:
        print(line.rstrip())
    else:
        print(line, end='')