comparison makeitso/makeitso.py @ 159:cfd4f1e91090

wip
author Jeff Hammel <jhammel@mozilla.com>
date Tue, 30 Jul 2013 15:20:38 -0700
parents 169e02e190ef
children 668b01d04457
comparison
equal deleted inserted replaced
158:ff1f41a18da9 159:cfd4f1e91090
88 return os.path.basename(uri) 88 return os.path.basename(uri)
89 89
90 def include(uri): 90 def include(uri):
91 f, headers = urllib.urlretrieve(uri) # XXX -> urllib2 for timeout 91 f, headers = urllib.urlretrieve(uri) # XXX -> urllib2 for timeout
92 return file(f).read() 92 return file(f).read()
93
93 94
94 ### things that deal with variables 95 ### things that deal with variables
95 96
96 class MissingVariablesException(Exception): 97 class MissingVariablesException(Exception):
97 """exception for (non-interactive) missing variables""" 98 """exception for (non-interactive) missing variables"""
116 117
117 ### template classes 118 ### template classes
118 119
119 class ContentTemplate(tempita.Template): 120 class ContentTemplate(tempita.Template):
120 """MakeItSo's extension of tempita's Template class""" 121 """MakeItSo's extension of tempita's Template class"""
121 122
122 defaults = {'include': include} 123 defaults = {'include': include}
123 124
124 def __init__(self, content, name=None, interactive=True, variables=None): 125 def __init__(self, content, name=None, interactive=True, variables=None):
125 126
126 # default variables 127 # default variables
127 self.defaults = self.__class__.defaults.copy() 128 self.defaults = self.__class__.defaults.copy()
128 self.defaults.update(variables or {}) 129 self.defaults.update(variables or {})
129 130
130 # TODO: automagically tell if the program is interactive or not 131 # TODO: automagically tell if the program is interactive or not
131 self.interactive = interactive 132 self.interactive = interactive
132 133
133 tempita.Template.__init__(self, content, name=name) 134 tempita.Template.__init__(self, content, name=name)
134 135
135 def get_variables(self, **variables): 136 def get_variables(self, **variables):
136 """the template's augmented variable set""" 137 """the template's augmented variable set"""
137 vars = self.defaults.copy() 138 vars = self.defaults.copy()
161 if missing: 162 if missing:
162 if self.interactive: 163 if self.interactive:
163 vars.update(self.read_variables(missing)) 164 vars.update(self.read_variables(missing))
164 else: 165 else:
165 raise MissingVariablesException(missing) 166 raise MissingVariablesException(missing)
166 167
167 def variables(self): 168 def variables(self):
168 """return the variables needed for a template""" 169 """return the variables needed for a template"""
169 return self.missing() 170 return self.missing()
170 171
171 def substitute(self, **variables): 172 def substitute(self, **variables):
186 class URITemplate(ContentTemplate): 187 class URITemplate(ContentTemplate):
187 """template for a file or URL""" 188 """template for a file or URL"""
188 189
189 def __init__(self, uri, interactive=True, variables=None): 190 def __init__(self, uri, interactive=True, variables=None):
190 content = include(uri) 191 content = include(uri)
191 192
192 # remove makeitso shebang if it has one 193 # remove makeitso shebang if it has one
193 if shebang_re.match(content): 194 if shebang_re.match(content):
194 content = os.linesep.join(content.splitlines()[1:]) 195 content = os.linesep.join(content.splitlines()[1:])
195 196
196 variables = variables or {} 197 variables = variables or {}
197 if 'here' not in variables: 198 if 'here' not in variables:
198 variables['here'] = parent_uri(uri) 199 variables['here'] = parent_uri(uri)
199 # TODO: could add other metadata about the uri, 200 # TODO: could add other metadata about the uri,
200 # such as last modification time' 201 # such as last modification time'
201 202
202 ContentTemplate.__init__(self, content, name=uri, 203 ContentTemplate.__init__(self, content, name=uri,
203 interactive=interactive, 204 interactive=interactive,
204 variables=variables) 205 variables=variables)
205 206
206 def substitute(self, variables, output=None): 207 def substitute(self, variables, output=None):
226 print >> output, content 227 print >> output, content
227 228
228 229
229 class DirectoryTemplate(ContentTemplate): 230 class DirectoryTemplate(ContentTemplate):
230 """template for a directory structure""" 231 """template for a directory structure"""
231 232
232 def __init__(self, directory, interactive=True, variables=None): 233 def __init__(self, directory, interactive=True, variables=None):
233 """ 234 """
234 - output : output directory; if None will render in place 235 - output : output directory; if None will render in place
235 """ 236 """
236 assert os.path.isdir(directory) 237 assert os.path.isdir(directory)
244 checks output for validity 245 checks output for validity
245 """ 246 """
246 assert output # must provide output 247 assert output # must provide output
247 if os.path.exists(output): 248 if os.path.exists(output):
248 assert os.path.isdir(output), "%s: Must be a directory" % self.name 249 assert os.path.isdir(output), "%s: Must be a directory" % self.name
249 250
250 def missing(self, **variables): 251 def missing(self, **variables):
251 vars = self.defaults.copy() 252 vars = self.defaults.copy()
252 vars.update(variables) 253 vars.update(variables)
253 missing = set([]) 254 missing = set([])
254 for dirpath, dirnames, filenames in os.walk(self.name): 255 for dirpath, dirnames, filenames in os.walk(self.name):
262 # find variables from files 263 # find variables from files
263 for f in filenames: 264 for f in filenames:
264 missed = ContentTemplate(f).missing(**vars) 265 missed = ContentTemplate(f).missing(**vars)
265 missing.update(missed) 266 missing.update(missed)
266 variables.update(dict([(i, '') for i in missed])) 267 variables.update(dict([(i, '') for i in missed]))
267 268
268 path = os.path.join(dirpath, f) 269 path = os.path.join(dirpath, f)
269 template = URITemplate(path, interactive=self.interactive) 270 template = URITemplate(path, interactive=self.interactive)
270 missed = template.missing(**vars) 271 missed = template.missing(**vars)
271 missing.update(missed) 272 missing.update(missed)
272 variables.update(dict([(i, '') for i in missed])) 273 variables.update(dict([(i, '') for i in missed]))
282 # per-directory control may be asserted 283 # per-directory control may be asserted
283 284
284 # make output directory if necessary 285 # make output directory if necessary
285 if output and not os.path.exists(output): 286 if output and not os.path.exists(output):
286 os.makedirs(output) 287 os.makedirs(output)
287 288
288 for dirname, dirnames, filenames in os.walk(self.name): 289 for dirname, dirnames, filenames in os.walk(self.name):
289 290
290 # interpolate directory names 291 # interpolate directory names
291 for d in dirnames: 292 for d in dirnames:
292 path = os.path.join(dirname, d) 293 path = os.path.join(dirname, d)
293 interpolated = ContentTemplate(path).substitute(**vars) 294 interpolated = ContentTemplate(path).substitute(**vars)
294 target = os.path.join(output, interpolated.split(self.name, 1)[-1].strip(os.path.sep)) 295 target = os.path.join(output, interpolated.split(self.name, 1)[-1].strip(os.path.sep))
295 296
296 if os.path.exists(target): 297 if os.path.exists(target):
297 # ensure its a directory 298 # ensure its a directory
298 # TODO: check this first before interpolation is in progress 299 # TODO: check this first before interpolation is in progress
299 assert os.path.isdir(target), "Can't substitute a directory on top of the file" 300 assert os.path.isdir(target), "Can't substitute a directory on top of the file"
300 else: 301 else: