bin/expand-zone
author Tero Marttila <terom@paivola.fi>
Fri, 23 Mar 2012 15:10:23 +0200
changeset 592 88a7683efc54
parent 528 1eb454630f47
permissions -rwxr-xr-x
update: list_files to copy all DHCP_CONFS..
#!/usr/bin/env python
# vim: set ft=python :

"""
    Process zonefiles with template expansions.
"""

__version__ = '0.0.1-dev'

import optparse
import codecs
import os.path
from datetime import datetime
import logging

log = logging.getLogger()

# command-line options, global state
options = None

def parse_options (argv) :
    """
        Parse command-line arguments.
    """

    parser = optparse.OptionParser(
            prog        = argv[0],
            usage       = '%prog: [options]',
            version     = __version__,

            # module docstring
            description = __doc__,
    )

    # logging
    general = optparse.OptionGroup(parser, "General Options")

    general.add_option('-q', '--quiet',     dest='loglevel', action='store_const', const=logging.ERROR, help="Less output")
    general.add_option('-v', '--verbose',   dest='loglevel', action='store_const', const=logging.INFO,  help="More output")
    general.add_option('-D', '--debug',     dest='loglevel', action='store_const', const=logging.DEBUG, help="Even more output")

    parser.add_option_group(general)

    parser.add_option('-c', '--input-charset',  metavar='CHARSET',  default='utf-8', 
            help="Encoding used for input files")

    parser.add_option('-o', '--output',         metavar='FILE',     default='-',
            help="Write to output file; default stdout")

    parser.add_option('--output-charset',       metavar='CHARSET',  default='utf-8', 
            help="Encoding used for output files")

    parser.add_option('--expand',               metavar='NAME=VALUE', action='append',
            help="Expand given template variable in zone")

    parser.add_option('--serial',               metavar='FILE',
            help="Read/expand serial from given .serial file")

    # defaults
    parser.set_defaults(
        loglevel            = logging.WARN,
        expand              = [],
    )
    
    # parse
    options, args = parser.parse_args(argv[1:])

    # configure
    logging.basicConfig(
        format  = '%(processName)s: %(name)s: %(levelname)s %(funcName)s : %(message)s',
        level   = options.loglevel,
    )

    return options, args

def process_file (file, expansions) :
    """
        Process file, expanding lines.
    """

    for line in file :
        line = line.format(**expansions)

        yield line

def write_lines (file, lines, suffix='\n') :
    for line in lines :
        file.write(line + suffix)

def open_file (path, mode, charset) :
    """
        Open unicode-enabled file from path, with - using stdio.
    """

    if path == '-' :
        # use stdin/out based on mode
        stream, func = {
            'r':    (sys.stdin, codecs.getreader),
            'w':    (sys.stdout, codecs.getwriter),
        }[mode[0]]

        # wrap
        return func(charset)(stream)

    else :
        # open
        return codecs.open(path, mode, charset)

def process_serial (path) :
    """
        Use serial number from given file.

        Returns the new serial as a string.
    """

    if not os.path.exists(path) :
        raise Exception("Given --serial does not exist: %s" % path)

    return open(path).read().strip()

def parse_expand (expand) :
    """
        Parse an --expand foo=bar to (key, value)
    """

    key, value = expand.split('=', 1)

    return key, value

def main (argv) :
    global options
    
    options, args = parse_options(argv)

    # expands
    expand = dict(parse_expand(expand) for expand in options.expand)

    # serial?
    if options.serial :
        serial = process_serial(options.serial)

        expand['serial'] = serial

    # input
    if args :
        # open files
        input_files = [open_file(path, 'r', options.input_charset) for path in args]

    else :
        # default to stdout
        input_files = [open_file('-', 'r', options.input_charset)]
   
    # process
    lines = []

    for file in input_files :
        log.info("Reading zone: %s", file)

        lines += list(process_file(file, expand))

    # output
    output = open_file(options.output, 'w', options.output_charset)
    write_lines(output, lines, suffix='')

    return 0

if __name__ == '__main__':
    import sys

    sys.exit(main(sys.argv))