bin/expand-zone
branchdns-new
changeset 604 9a23fca9167a
parent 603 b58236f9ea7b
child 605 26a307558602
equal deleted inserted replaced
603:b58236f9ea7b 604:9a23fca9167a
     1 #!/usr/bin/env python
       
     2 # vim: set ft=python :
       
     3 
       
     4 """
       
     5     Process zonefiles with template expansions.
       
     6 """
       
     7 
       
     8 __version__ = '0.0.1-dev'
       
     9 
       
    10 import optparse
       
    11 import codecs
       
    12 import os.path
       
    13 from datetime import datetime
       
    14 import logging
       
    15 
       
    16 log = logging.getLogger()
       
    17 
       
    18 # command-line options, global state
       
    19 options = None
       
    20 
       
    21 def parse_options (argv) :
       
    22     """
       
    23         Parse command-line arguments.
       
    24     """
       
    25 
       
    26     parser = optparse.OptionParser(
       
    27             prog        = argv[0],
       
    28             usage       = '%prog: [options]',
       
    29             version     = __version__,
       
    30 
       
    31             # module docstring
       
    32             description = __doc__,
       
    33     )
       
    34 
       
    35     # logging
       
    36     general = optparse.OptionGroup(parser, "General Options")
       
    37 
       
    38     general.add_option('-q', '--quiet',     dest='loglevel', action='store_const', const=logging.ERROR, help="Less output")
       
    39     general.add_option('-v', '--verbose',   dest='loglevel', action='store_const', const=logging.INFO,  help="More output")
       
    40     general.add_option('-D', '--debug',     dest='loglevel', action='store_const', const=logging.DEBUG, help="Even more output")
       
    41 
       
    42     parser.add_option_group(general)
       
    43 
       
    44     parser.add_option('-c', '--input-charset',  metavar='CHARSET',  default='utf-8', 
       
    45             help="Encoding used for input files")
       
    46 
       
    47     parser.add_option('-o', '--output',         metavar='FILE',     default='-',
       
    48             help="Write to output file; default stdout")
       
    49 
       
    50     parser.add_option('--output-charset',       metavar='CHARSET',  default='utf-8', 
       
    51             help="Encoding used for output files")
       
    52 
       
    53     parser.add_option('--expand',               metavar='NAME=VALUE', action='append',
       
    54             help="Expand given template variable in zone")
       
    55 
       
    56     parser.add_option('--serial',               metavar='FILE',
       
    57             help="Read/expand serial from given .serial file")
       
    58 
       
    59     # defaults
       
    60     parser.set_defaults(
       
    61         loglevel            = logging.WARN,
       
    62         expand              = [],
       
    63     )
       
    64     
       
    65     # parse
       
    66     options, args = parser.parse_args(argv[1:])
       
    67 
       
    68     # configure
       
    69     logging.basicConfig(
       
    70         format  = '%(processName)s: %(name)s: %(levelname)s %(funcName)s : %(message)s',
       
    71         level   = options.loglevel,
       
    72     )
       
    73 
       
    74     return options, args
       
    75 
       
    76 def process_file (file, expansions) :
       
    77     """
       
    78         Process file, expanding lines.
       
    79     """
       
    80 
       
    81     for line in file :
       
    82         line = line.format(**expansions)
       
    83 
       
    84         yield line
       
    85 
       
    86 def write_lines (file, lines, suffix='\n') :
       
    87     for line in lines :
       
    88         file.write(line + suffix)
       
    89 
       
    90 def open_file (path, mode, charset) :
       
    91     """
       
    92         Open unicode-enabled file from path, with - using stdio.
       
    93     """
       
    94 
       
    95     if path == '-' :
       
    96         # use stdin/out based on mode
       
    97         stream, func = {
       
    98             'r':    (sys.stdin, codecs.getreader),
       
    99             'w':    (sys.stdout, codecs.getwriter),
       
   100         }[mode[0]]
       
   101 
       
   102         # wrap
       
   103         return func(charset)(stream)
       
   104 
       
   105     else :
       
   106         # open
       
   107         return codecs.open(path, mode, charset)
       
   108 
       
   109 def process_serial (path) :
       
   110     """
       
   111         Use serial number from given file.
       
   112 
       
   113         Returns the new serial as a string.
       
   114     """
       
   115 
       
   116     if not os.path.exists(path) :
       
   117         raise Exception("Given --serial does not exist: %s" % path)
       
   118 
       
   119     return open(path).read().strip()
       
   120 
       
   121 def parse_expand (expand) :
       
   122     """
       
   123         Parse an --expand foo=bar to (key, value)
       
   124     """
       
   125 
       
   126     key, value = expand.split('=', 1)
       
   127 
       
   128     return key, value
       
   129 
       
   130 def main (argv) :
       
   131     global options
       
   132     
       
   133     options, args = parse_options(argv)
       
   134 
       
   135     # expands
       
   136     expand = dict(parse_expand(expand) for expand in options.expand)
       
   137 
       
   138     # serial?
       
   139     if options.serial :
       
   140         serial = process_serial(options.serial)
       
   141 
       
   142         expand['serial'] = serial
       
   143 
       
   144     # input
       
   145     if args :
       
   146         # open files
       
   147         input_files = [open_file(path, 'r', options.input_charset) for path in args]
       
   148 
       
   149     else :
       
   150         # default to stdout
       
   151         input_files = [open_file('-', 'r', options.input_charset)]
       
   152    
       
   153     # process
       
   154     lines = []
       
   155 
       
   156     for file in input_files :
       
   157         log.info("Reading zone: %s", file)
       
   158 
       
   159         lines += list(process_file(file, expand))
       
   160 
       
   161     # output
       
   162     output = open_file(options.output, 'w', options.output_charset)
       
   163     write_lines(output, lines, suffix='')
       
   164 
       
   165     return 0
       
   166 
       
   167 if __name__ == '__main__':
       
   168     import sys
       
   169 
       
   170     sys.exit(main(sys.argv))