Mercurial > hg > MakeItSo
view makeitso/template.py @ 96:cc17537254d2
add an install script template
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Tue, 11 Jan 2011 09:58:10 -0800 |
parents | 26b9c3bba04e |
children | d9c6e26a42ff |
line wrap: on
line source
""" basic API template class """ import os import sys from makeitso import ContentTemplate from makeitso import PolyTemplate class Undefined(object): """marker class for variables""" def __nonzero__(self): return False Undefined = Undefined() # singleton class Variable(object): """variable object for MakeItSo templates""" def __init__(self, name, description=None, default=Undefined, cast=None): self.name = name self.default = default self.description = description # TODO (maybe): get cast from default variable type if not None self.cast = cast self._set = False def copy(self): """returns a copy of the variable""" return Variable(self.name, self.description, self.default, self.cast) def set(self, value): if self.cast: self.value = self.cast(value) else: self.value = value self._set = True def read(self, fd=sys.stdout): """prompt and read the variable from stdin""" fd.write(self.display()) self.set(raw_input()) def display(self): description = self.description or self.name if self.default: return 'Enter %s [DEFAULT: %s]:' % (description, repr(self.default)) else: return 'Enter %s:' % description def __repr__(self): return "Variable(name='%s')" % self.name def assemble(*args): names = set() retval = [] for arg in args: if issubclass(arg, MakeItSoTemplate): arg = arg.vars for variable in arg: if variable.name in names: continue retval.append(variable.copy()) names.add(variable.name) return retval class MakeItSoTemplate(ContentTemplate): """API template for MakeItSo""" # name of the template name = '' # description of the template description = '' # templates to interpolate # paths are relative to __file__ unless absolute or URIs templates = [] # variables vars = [] # inspect the templates for more variables look = False def __init__(self, interactive=True, usedefaults=True, variables=None): """ - output : output file or directory - interactive : whether tointeractively get variables - usedefaults : try to use the default values if not specified """ # boilerplate variables = variables or {} if not self.description and hasattr(self, '__doc__'): self.description = self.__doc__ self.interactive = interactive _file = sys.modules[self.__class__.__module__].__file__ self.location = os.path.dirname(os.path.abspath(_file)) self.defaults = variables.copy() self.usedefaults = usedefaults # make a dictionary of the variables for lookup convenience self.vardict = {} for i in self.vars: self.vardict[i.name] = i # ensure all of these templates exist self._templates = [] for template in self.templates: if template.startswith('http://') or template.startswith('https://'): self._templates.append(template) continue if os.path.isabs(template): path = template else: path = os.path.join(self.location, template) assert os.path.exists(path), "%s does not exist" % path self._templates.append(path) def get_variables(self, **variables): # XXX could do this in the ctor vars = ContentTemplate.get_variables(self, **variables) if self.usedefaults: for variable in self.vars: if variable.name in vars: continue if variable.default is not Undefined: vars[variable.name] = variable.default return vars def missing(self, **variables): vars = self.get_variables(**variables) missing = set([]) # get known needed variables for var in self.vars: if var.name not in vars: missing.add(var) if self.look: # scan templates for other variables raise NotImplementedError return missing def pre(self, variables): """do stuff before interpolation""" def substitute(self, variables, output): """do the substitution""" vars = self.get_variables(**variables) self.pre(vars) self.check_missing(vars) # do the substitution template = PolyTemplate(self._templates, interactive=self.interactive, variables=vars) template.check_output(output) template.substitute({}, output) self.post(vars) def post(self, variables): """do stuff after interpolation""" def read_variables(self, variables): """read variables from stdin""" retval = {} for i in variables: if i in self.vardict: self.vardict[i].read() else: retval.update(ContentTemplate.read_variables(self, (i,))) return retval class PasteScriptTemplate(MakeItSoTemplate): """template for backwards compatability with PasteScript"""