0001
0002
0003import sys
0004import os
0005import inspect
0006import copydir
0007import command
0008
0009from paste.util.template import paste_script_template_renderer
0010
0011class Template(object):
0012
0013
0014
0015
0016
0017
0018
0019 vars = []
0020
0021
0022 egg_plugins = []
0023
0024
0025 required_templates = []
0026
0027
0028 use_cheetah = False
0029
0030 read_vars_from_templates = False
0031
0032
0033
0034
0035
0036
0037 template_renderer = None
0038
0039 def __init__(self, name):
0040 self.name = name
0041 self._read_vars = None
0042
0043 def module_dir(self):
0044 """
0045 Returns the module directory of this template.
0046 """
0047 mod = sys.modules[self.__class__.__module__]
0048 return os.path.dirname(mod.__file__)
0049
0050 def template_dir(self):
0051 assert self._template_dir is not None, (
0052 "Template %r didn't set _template_dir" % self)
0053 return os.path.join(self.module_dir(), self._template_dir)
0054
0055 def run(self, command, output_dir, vars):
0056 self.pre(command, output_dir, vars)
0057 self.write_files(command, output_dir, vars)
0058 self.post(command, output_dir, vars)
0059
0060 def check_vars(self, vars, cmd):
0061 expect_vars = self.read_vars(cmd)
0062 if not expect_vars:
0063
0064 return vars
0065 converted_vars = {}
0066 unused_vars = vars.copy()
0067 errors = []
0068 for var in expect_vars:
0069 if var.name not in unused_vars:
0070 if cmd.interactive:
0071 prompt = 'Enter %s' % var.full_description()
0072 response = cmd.challenge(prompt, var.default, var.should_echo)
0073 converted_vars[var.name] = response
0074 elif var.default is command.NoDefault:
0075 errors.append('Required variable missing: %s'
0076 % var.full_description())
0077 else:
0078 converted_vars[var.name] = var.default
0079 else:
0080 converted_vars[var.name] = unused_vars.pop(var.name)
0081 if errors:
0082 raise command.BadCommand(
0083 'Errors in variables:\n%s' % '\n'.join(errors))
0084 converted_vars.update(unused_vars)
0085 vars.update(converted_vars)
0086 return converted_vars
0087
0088 def read_vars(self, command=None):
0089 if self._read_vars is not None:
0090 return self._read_vars
0091 assert (not self.read_vars_from_templates
0092 or self.use_cheetah), (
0093 "You can only read variables from templates if using Cheetah")
0094 if not self.read_vars_from_templates:
0095 self._read_vars = self.vars
0096 return self.vars
0097
0098 vars = self.vars[:]
0099 var_names = [var.name for var in self.vars]
0100 read_vars = find_args_in_dir(
0101 self.template_dir(),
0102 verbose=command and command.verbose > 1).items()
0103 read_vars.sort()
0104 for var_name, var in read_vars:
0105 if var_name not in var_names:
0106 vars.append(var)
0107 self._read_vars = vars
0108 return vars
0109
0110 def write_files(self, command, output_dir, vars):
0111 template_dir = self.template_dir()
0112 if not os.path.exists(output_dir):
0113 print "Creating directory %s" % output_dir
0114 if not command.simulate:
0115
0116
0117 os.makedirs(output_dir)
0118 copydir.copy_dir(template_dir, output_dir,
0119 vars,
0120 verbosity=command.verbose,
0121 simulate=command.options.simulate,
0122 interactive=command.interactive,
0123 overwrite=command.options.overwrite,
0124 indent=1,
0125 use_cheetah=self.use_cheetah,
0126 template_renderer=self.template_renderer)
0127
0128 def print_vars(self, indent=0):
0129 vars = self.read_vars()
0130 var.print_vars(vars)
0131
0132 def pre(self, command, output_dir, vars):
0133 """
0134 Called before template is applied.
0135 """
0136 pass
0137
0138 def post(self, command, output_dir, vars):
0139 """
0140 Called after template is applied.
0141 """
0142 pass
0143
0144NoDefault = command.NoDefault
0145
0146class var(object):
0147
0148 def __init__(self, name, description,
0149 default='', should_echo=True):
0150 self.name = name
0151 self.description = description
0152 self.default = default
0153 self.should_echo = should_echo
0154
0155 def __repr__(self):
0156 return '<%s %s default=%r should_echo=%s>' % (
0157 self.__class__.__name__,
0158 self.name, self.default, self.should_echo)
0159
0160 def full_description(self):
0161 if self.description:
0162 return '%s (%s)' % (self.name, self.description)
0163 else:
0164 return self.name
0165
0166 def print_vars(cls, vars, indent=0):
0167 max_name = max([len(v.name) for v in vars])
0168 for var in vars:
0169 if var.description:
0170 print '%s%s%s %s' % (
0171 ' '*indent,
0172 var.name,
0173 ' '*(max_name-len(var.name)),
0174 var.description)
0175 else:
0176 print ' %s' % var.name
0177 if var.default is not command.NoDefault:
0178 print ' default: %r' % var.default
0179 if var.should_echo is True:
0180 print ' should_echo: %s' % var.should_echo
0181 print
0182
0183 print_vars = classmethod(print_vars)
0184
0185class BasicPackage(Template):
0186
0187 _template_dir = 'templates/basic_package'
0188 summary = "A basic setuptools-enabled package"
0189 vars = [
0190 var('version', 'Version (like 0.1)'),
0191 var('description', 'One-line description of the package'),
0192 var('long_description', 'Multi-line description (in reST)'),
0193 var('keywords', 'Space-separated keywords/tags'),
0194 var('author', 'Author name'),
0195 var('author_email', 'Author email'),
0196 var('url', 'URL of homepage'),
0197 var('license_name', 'License name'),
0198 var('zip_safe', 'True/False: if the package can be distributed as a .zip file', default=False),
0199 ]
0200
0201 template_renderer = staticmethod(paste_script_template_renderer)
0202
0203_skip_variables = ['VFN', 'currentTime', 'self', 'VFFSL', 'dummyTrans',
0204 'getmtime', 'trans']
0205
0206def find_args_in_template(template):
0207 if isinstance(template, (str, unicode)):
0208
0209 import Cheetah.Template
0210 template = Cheetah.Template.Template(file=template)
0211 if not hasattr(template, 'body'):
0212
0213 return None
0214 method = template.body
0215 args, varargs, varkw, defaults = inspect.getargspec(method)
0216 defaults=list(defaults or [])
0217 vars = []
0218 while args:
0219 if len(args) == len(defaults):
0220 default = defaults.pop(0)
0221 else:
0222 default = command.NoDefault
0223 arg = args.pop(0)
0224 if arg in _skip_variables:
0225 continue
0226
0227 vars.append(
0228 var(arg, description=None,
0229 default=default))
0230 return vars
0231
0232def find_args_in_dir(dir, verbose=False):
0233 all_vars = {}
0234 for fn in os.listdir(dir):
0235 if fn.startswith('.') or fn == 'CVS' or fn == '_darcs':
0236 continue
0237 full = os.path.join(dir, fn)
0238 if os.path.isdir(full):
0239 inner_vars = find_args_in_dir(full)
0240 elif full.endswith('_tmpl'):
0241 inner_vars = {}
0242 found = find_args_in_template(full)
0243 if found is None:
0244
0245 if verbose:
0246 print 'Template %s has no parseable variables' % full
0247 continue
0248 for var in found:
0249 inner_vars[var.name] = var
0250 else:
0251
0252 continue
0253 if verbose:
0254 print 'Found variable(s) %s in Template %s' % (
0255 ', '.join(inner_vars.keys()), full)
0256 for var_name, var in inner_vars.items():
0257
0258 if var_name not in all_vars:
0259 all_vars[var_name] = var
0260 continue
0261
0262 cur_var = all_vars[var_name]
0263 if not cur_var.description:
0264 cur_var.description = var.description
0265 elif (cur_var.description and var.description
0266 and var.description != cur_var.description):
0267 print >> sys.stderr, (
0268 "Variable descriptions do not match: %s: %s and %s"
0269 % (var_name, cur_var.description, var.description))
0270 if (cur_var.default is not command.NoDefault
0271 and var.default is not command.NoDefault
0272 and cur_var.default != var.default):
0273 print >> sys.stderr, (
0274 "Variable defaults do not match: %s: %r and %r"
0275 % (var_name, cur_var.default, var.default))
0276 return all_vars