Package paste :: Package script :: Module templates
[hide private]

Source Code for Module paste.script.templates

  1  # (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) 
  2  # Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php 
  3  import sys 
  4  import os 
  5  import inspect 
  6  import copydir 
  7  import command 
  8   
  9  from paste.util.template import paste_script_template_renderer 
 10   
11 -class Template(object):
12 13 # Subclasses must define: 14 # _template_dir (or template_dir()) 15 # summary 16 17 # Variables this template uses (mostly for documentation now) 18 # a list of instances of var() 19 vars = [] 20 21 # Eggs that should be added as plugins: 22 egg_plugins = [] 23 24 # Templates that must be applied first: 25 required_templates = [] 26 27 # Use Cheetah for substituting templates: 28 use_cheetah = False 29 # If true, then read all the templates to find the variables: 30 read_vars_from_templates = False 31 32 # You can also give this function/method to use something other 33 # than Cheetah or string.Template. The function should be of the 34 # signature template_renderer(content, vars, filename=filename). 35 # Careful you don't turn this into a method by putting a function 36 # here (without staticmethod)! 37 template_renderer = None 38
39 - def __init__(self, name):
40 self.name = name 41 self._read_vars = None
42
43 - def module_dir(self):
44 """ 45 Returns the module directory of this template. 46 """ 47 mod = sys.modules[self.__class__.__module__] 48 return os.path.dirname(mod.__file__)
49
50 - def template_dir(self):
51 assert self._template_dir is not None, ( 52 "Template %r didn't set _template_dir" % self) 53 return os.path.join(self.module_dir(), self._template_dir)
54
55 - def run(self, command, output_dir, vars):
56 self.pre(command, output_dir, vars) 57 self.write_files(command, output_dir, vars) 58 self.post(command, output_dir, vars)
59
60 - def check_vars(self, vars, cmd):
61 expect_vars = self.read_vars(cmd) 62 if not expect_vars: 63 # Assume that variables aren't defined 64 return vars 65 converted_vars = {} 66 unused_vars = vars.copy() 67 errors = [] 68 for var in expect_vars: 69 if var.name not in unused_vars: 70 if cmd.interactive: 71 prompt = 'Enter %s' % var.full_description() 72 response = cmd.challenge(prompt, var.default, var.should_echo) 73 converted_vars[var.name] = response 74 elif var.default is command.NoDefault: 75 errors.append('Required variable missing: %s' 76 % var.full_description()) 77 else: 78 converted_vars[var.name] = var.default 79 else: 80 converted_vars[var.name] = unused_vars.pop(var.name) 81 if errors: 82 raise command.BadCommand( 83 'Errors in variables:\n%s' % '\n'.join(errors)) 84 converted_vars.update(unused_vars) 85 vars.update(converted_vars) 86 return converted_vars
87
88 - def read_vars(self, command=None):
89 if self._read_vars is not None: 90 return self._read_vars 91 assert (not self.read_vars_from_templates 92 or self.use_cheetah), ( 93 "You can only read variables from templates if using Cheetah") 94 if not self.read_vars_from_templates: 95 self._read_vars = self.vars 96 return self.vars 97 98 vars = self.vars[:] 99 var_names = [var.name for var in self.vars] 100 read_vars = find_args_in_dir( 101 self.template_dir(), 102 verbose=command and command.verbose > 1).items() 103 read_vars.sort() 104 for var_name, var in read_vars: 105 if var_name not in var_names: 106 vars.append(var) 107 self._read_vars = vars 108 return vars
109
110 - def write_files(self, command, output_dir, vars):
111 template_dir = self.template_dir() 112 if not os.path.exists(output_dir): 113 print "Creating directory %s" % output_dir 114 if not command.simulate: 115 # Don't let copydir create this top-level directory, 116 # since copydir will svn add it sometimes: 117 os.makedirs(output_dir) 118 copydir.copy_dir(template_dir, output_dir, 119 vars, 120 verbosity=command.verbose, 121 simulate=command.options.simulate, 122 interactive=command.interactive, 123 overwrite=command.options.overwrite, 124 indent=1, 125 use_cheetah=self.use_cheetah, 126 template_renderer=self.template_renderer)
127
128 - def print_vars(self, indent=0):
129 vars = self.read_vars() 130 var.print_vars(vars)
131
132 - def pre(self, command, output_dir, vars):
133 """ 134 Called before template is applied. 135 """ 136 pass
137
138 - def post(self, command, output_dir, vars):
139 """ 140 Called after template is applied. 141 """ 142 pass
143 144 NoDefault = command.NoDefault 145
146 -class var(object):
147
148 - def __init__(self, name, description, 149 default='', should_echo=True):
150 self.name = name 151 self.description = description 152 self.default = default 153 self.should_echo = should_echo
154
155 - def __repr__(self):
156 return '<%s %s default=%r should_echo=%s>' % ( 157 self.__class__.__name__, 158 self.name, self.default, self.should_echo)
159
160 - def full_description(self):
161 if self.description: 162 return '%s (%s)' % (self.name, self.description) 163 else: 164 return self.name
165
166 - def print_vars(cls, vars, indent=0):
167 max_name = max([len(v.name) for v in vars]) 168 for var in vars: 169 if var.description: 170 print '%s%s%s %s' % ( 171 ' '*indent, 172 var.name, 173 ' '*(max_name-len(var.name)), 174 var.description) 175 else: 176 print ' %s' % var.name 177 if var.default is not command.NoDefault: 178 print ' default: %r' % var.default 179 if var.should_echo is True: 180 print ' should_echo: %s' % var.should_echo 181 print
182 183 print_vars = classmethod(print_vars)
184
185 -class BasicPackage(Template):
186 187 _template_dir = 'templates_dir/basic_package' 188 summary = "A basic setuptools-enabled package" 189 vars = [ 190 var('version', 'Version (like 0.1)'), 191 var('description', 'One-line description of the package'), 192 var('long_description', 'Multi-line description (in reST)'), 193 var('keywords', 'Space-separated keywords/tags'), 194 var('author', 'Author name'), 195 var('author_email', 'Author email'), 196 var('url', 'URL of homepage'), 197 var('license_name', 'License name'), 198 var('zip_safe', 'True/False: if the package can be distributed as a .zip file', default=False), 199 ] 200 201 template_renderer = staticmethod(paste_script_template_renderer)
202 203 _skip_variables = ['VFN', 'currentTime', 'self', 'VFFSL', 'dummyTrans', 204 'getmtime', 'trans'] 205
206 -def find_args_in_template(template):
207 if isinstance(template, (str, unicode)): 208 # Treat as filename: 209 import Cheetah.Template 210 template = Cheetah.Template.Template(file=template) 211 if not hasattr(template, 'body'): 212 # Don't know... 213 return None 214 method = template.body 215 args, varargs, varkw, defaults = inspect.getargspec(method) 216 defaults=list(defaults or []) 217 vars = [] 218 while args: 219 if len(args) == len(defaults): 220 default = defaults.pop(0) 221 else: 222 default = command.NoDefault 223 arg = args.pop(0) 224 if arg in _skip_variables: 225 continue 226 # @@: No way to get description yet 227 vars.append( 228 var(arg, description=None, 229 default=default)) 230 return vars
231
232 -def find_args_in_dir(dir, verbose=False):
233 all_vars = {} 234 for fn in os.listdir(dir): 235 if fn.startswith('.') or fn == 'CVS' or fn == '_darcs': 236 continue 237 full = os.path.join(dir, fn) 238 if os.path.isdir(full): 239 inner_vars = find_args_in_dir(full) 240 elif full.endswith('_tmpl'): 241 inner_vars = {} 242 found = find_args_in_template(full) 243 if found is None: 244 # Couldn't read variables 245 if verbose: 246 print 'Template %s has no parseable variables' % full 247 continue 248 for var in found: 249 inner_vars[var.name] = var 250 else: 251 # Not a template, don't read it 252 continue 253 if verbose: 254 print 'Found variable(s) %s in Template %s' % ( 255 ', '.join(inner_vars.keys()), full) 256 for var_name, var in inner_vars.items(): 257 # Easy case: 258 if var_name not in all_vars: 259 all_vars[var_name] = var 260 continue 261 # Emit warnings if the variables don't match well: 262 cur_var = all_vars[var_name] 263 if not cur_var.description: 264 cur_var.description = var.description 265 elif (cur_var.description and var.description 266 and var.description != cur_var.description): 267 print >> sys.stderr, ( 268 "Variable descriptions do not match: %s: %s and %s" 269 % (var_name, cur_var.description, var.description)) 270 if (cur_var.default is not command.NoDefault 271 and var.default is not command.NoDefault 272 and cur_var.default != var.default): 273 print >> sys.stderr, ( 274 "Variable defaults do not match: %s: %r and %r" 275 % (var_name, cur_var.default, var.default)) 276 return all_vars
277