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: Address comments on PS3 Created Sept. 29, 2017, 10:43 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cms/bin/test_server.py ('k') | tests/__init__.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 return any(base.has_file(filename) for base in self._bases)
336
337 def read_file(self, filename, binary=False):
338 for base in self._bases:
339 if base.has_file(filename):
340 return base.read_file(filename, binary)
341 raise KeyError('File not found {}'.format(filename))
342
343 def list_files(self, subdir):
344 return {f for base in self._bases for f in base.list_files(subdir)}
345
346
347 def _memoize(func):
348 """Cache results of functions calls."""
349 memoized = {}
350
351 def wrapper(*args):
352 try:
353 return memoized[args]
354 except KeyError:
355 return memoized.setdefault(args, func(*args))
356 wrapper.cache_clear = memoized.clear
357 return wrapper
358
359
360 def create_source(path, static=False, revision=None):
Sebastian Noack 2017/09/29 19:11:30 Does it still make sense to call that argument "st
Vasily Kuznetsov 2017/10/02 11:11:56 Yeah, you're right, now it would be more clear if
361 """Create a source from path and optional revision.
362
363 `static` flag indicates that the website source under `path` can be assumed
364 to not change after the source was created and any changes can be safely
365 ignored.
366 - If `static` is `True`, no interim changes are expected and caching will
367 be used to optimize performance.
368 - If `static` is `False`, changes on the filesystem are expected and will
369 be reflected in the outputs of the calls. This mode can be used for live
370 preview.
371
372 If `revision` option is provided, the `path` is assumed to be pointing to a
373 Mercurial repository. In this case the source will return the content of
374 selected revision (using `MercurialSource`) instead of the content of the
375 directory. Note that any local changes will be ignored in this case.
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 revision is not None:
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, ConfigParser.NoOptionError):
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
« no previous file with comments | « cms/bin/test_server.py ('k') | tests/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld