Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: cms/sources.py

Issue 29555839: Issue 5336 - Allow additional include, page, and template paths using CMS (Closed)
Patch Set: Created Sept. 25, 2017, 7:12 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 # This file is part of the Adblock Plus web scripts, 1 # This file is part of the Adblock Plus web scripts,
2 # Copyright (C) 2006-present eyeo GmbH 2 # Copyright (C) 2006-present eyeo GmbH
3 # 3 #
4 # Adblock Plus is free software: you can redistribute it and/or modify 4 # Adblock Plus is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License version 3 as 5 # it under the terms of the GNU General Public License version 3 as
6 # published by the Free Software Foundation. 6 # published by the Free Software Foundation.
7 # 7 #
8 # Adblock Plus is distributed in the hope that it will be useful, 8 # Adblock Plus is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 path = os.path.join(dir, filename) 296 path = os.path.join(dir, filename)
297 if os.path.isfile(path): 297 if os.path.isfile(path):
298 result.append(relpath + filename) 298 result.append(relpath + filename)
299 elif os.path.isdir(path): 299 elif os.path.isdir(path):
300 do_list(path, relpath + filename + '/') 300 do_list(path, relpath + filename + '/')
301 do_list(self.get_path(subdir), '') 301 do_list(self.get_path(subdir), '')
302 return result 302 return result
303 303
304 def get_cache_dir(self): 304 def get_cache_dir(self):
305 return os.path.join(self._dir, 'cache') 305 return os.path.join(self._dir, 'cache')
306
307
308 class MultiSource(Source):
309 """A source that combines the contents of multiple other sources."""
310
311 def __init__(self, base_sources):
312 self._bases = base_sources
313
314 @property
315 def version(self):
316 return self._bases[0].version
317
318 def get_cache_dir(self):
319 return self._bases[0].get_cache_dir()
320
321 def __enter__(self):
322 for base in self._bases:
323 base.__enter__()
324 return self
325
326 def __exit__(self, exc_type, exc_value, tb):
327 return any(base.__exit__(exc_type, exc_value, tb)
328 for base in self._bases)
329
330 def close(self):
331 for base in self._bases:
332 base.close()
333
334 def has_file(self, filename):
335 for base in self._bases:
Sebastian Noack 2017/09/27 02:47:53 Nit: You could use any() here as well: return a
Vasily Kuznetsov 2017/09/27 11:34:39 Done.
336 if base.has_file(filename):
337 return True
338 return False
339
340 def read_file(self, filename, binary=False):
341 for base in self._bases:
342 if base.has_file(filename):
343 return base.read_file(filename, binary)
344 raise KeyError('File not found {}'.format(filename))
345
346 def list_files(self, subdir):
347 files = set()
348 for base in self._bases:
349 files.update(base.list_files(subdir))
350 return sorted(files)
Sebastian Noack 2017/09/27 02:47:53 Nit: This could be written as a set literal one-li
Vasily Kuznetsov 2017/09/27 11:34:39 Done. Thanks for this suggestion. Having thought
Sebastian Noack 2017/09/27 15:55:22 The type returned here doesn't seem to be importan
Vasily Kuznetsov 2017/09/28 09:08:17 Fair enough. Done.
351
352
353 def _memoize(func):
354 """Cache results of functions calls."""
355 memoized = {}
356
357 def wrapper(*args):
358 try:
359 return memoized[args]
360 except KeyError:
361 return memoized.setdefault(args, func(*args))
362 wrapper.cache_clear = memoized.clear
363 return wrapper
364
365
366 def create_source(path, static=False, revision='default'):
Sebastian Noack 2017/09/27 02:47:53 I would rather implement this in Source.__new__, s
Vasily Kuznetsov 2017/09/27 11:34:38 Here I prefer my implementation for the following
367 """Create a source from path and optional revision.
368
369 `static` flag determines the type of the source that will be created and
370 its caching behavior:
371 - If `static` is `True`, we use version-control-aware `MercurialSource`,
372 pass the revision and cache the results of most used functions.
373 - If `static` is `False` (as is the case with the preview server), we use
374 simpler `FileSource` and don't cache anything to be able to respond to
375 changes on the filesystem.
376
377 If `settings.ini` in the source contains `[paths]` section with an
378 `additional-paths` key that contains the list of additional root folders,
379 `MultiSource` will be instantiated and its bases will be the original
380 source plus an additional source for each additional root folder.
381 `MultiSource` looks up files in its base sources in the order they are
382 provided, so the files in the additional folders will only be used if the
383 original source doesn't contain that file.
384 """
385 if static:
386 source = MercurialSource(path, revision)
387 else:
388 source = FileSource(path)
389
390 config = source.read_config()
391 try:
392 ap = config.get('paths', 'additional-paths').strip()
393 additional_paths = filter(None, ap.split())
394 except ConfigParser.NoSectionError:
395 additional_paths = []
396
397 if additional_paths:
398 additional_sources = [
399 create_source(os.path.join(path, p))
400 for p in additional_paths
401 ]
402 source = MultiSource([source] + additional_sources)
403
404 if static:
405 for fname in [
406 'resolve_link',
407 'read_config',
408 'read_template',
409 'read_locale',
410 'read_include',
411 'exec_file',
412 ]:
413 setattr(source, fname, _memoize(getattr(source, fname)))
414
415 return source
OLDNEW

Powered by Google App Engine
This is Rietveld