view makeitso/makeitso.py @ 5:f064be514e53

choose a better filename and remove some stuff from shebang
author Jeff Hammel <jhammel@mozilla.com>
date Wed, 10 Nov 2010 18:01:07 -0800
parents
children ac78e26cd568
line wrap: on
line source

#!/usr/bin/env python
"""
filesystem template interpreter
"""

import os
import re
import subprocess
import sys

from optparse import OptionParser
from tempita import Template

shebang_re = '#!.*makeitso.*'
shebang_re = re.compile(shebang_re)

def call(command, *args, **kw):
    code = subprocess.call(command, *args, **kw)
    if code:
        if isinstance(command, basestring):
            cmdstr = command
        else:
            cmdstr = ' '.join(command)
        raise SystemExit("Command `%s` exited with code %d" % (cmdstr, code))

def get_missing(name_error):
    """
    This is a horrible hack because python doesn't do the proper thing
    via eval and return the name of the variable;  instead, it just gives
    you a message:
    >>> try:
    ...   eval('2*foo')
    ... except Exception, e:
    ...   pass
    """
    message = name_error.args[0]
    varname = message.split("'")[1]
    return varname

def missing_variables(template, variables):
    """return additional variables needed"""
    vars = variables.copy()
    missing = set([])
    while True:
        try:
            template.substitute(**vars)
            return missing
        except NameError, e:
            missed = get_missing(e)
            missing.add(missed)
            vars[missed] = ''
    return missing

def template_variables(template):
    """return the variables needed for a template"""
    return missing_variables(template, {})

def read_variables(variables):
    retval = {}
    for i in variables:
        print 'Enter %s: ' % i,
        retval[i] = raw_input()
    return retval
        
def substitute(content, fp=sys.stdout, variables=None):

    # remove makeitso shebang if it has one
    if shebang_re.match(content):
        content = os.linesep.join(content.splitlines()[1:])

    variables = variables or {}
    template = Template(content)
    missing = missing_variables(template, variables)
    if missing:
        # TODO: add a switch for interactive or not
        variables.update(read_variables(missing))
    print >> fp, template.substitute(**variables)


def main(args=sys.argv[1:]):

    # create option parser
    usage = '%prog [options]'
    parser = OptionParser(usage, description=__doc__)
    parser.add_option('--variables', dest='variables', action='store_true',
                      help='print the variables in a template')
    options, args = parser.parse_args(args)

    if options.variables:
        variables = template_variables() # TODO: pass template
        return

    # template variables
    variables = {}
    _vars = []
    _args = []
    for arg in args:
        if '=' in arg:
            key, value = arg.split('=')
            variables[key] = value
        else:
            _args.append(arg)
    args = _args

    # get the content
    if args:
        for arg in args:
            content = file(arg).read()
            substitute(content, variables=variables)
    else:
        content = sys.stdin.read()
        substitute(content, variables=variables)
        
if __name__ == '__main__':
    main()