| OLD | NEW | 
|    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 | 
|   11 # GNU General Public License for more details. |   11 # GNU General Public License for more details. | 
|   12 # |   12 # | 
|   13 # You should have received a copy of the GNU General Public License |   13 # You should have received a copy of the GNU General Public License | 
|   14 # along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. |   14 # along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
|   15  |   15  | 
|   16 import io |   16 import io | 
|   17 import collections |   17 import collections | 
|   18 import ConfigParser |   18 import ConfigParser | 
|   19 import json |   19 import json | 
|   20 import os |   20 import os | 
|   21 from StringIO import StringIO |   21 from StringIO import StringIO | 
|   22 import subprocess |   22 from random import randint | 
|   23 import urlparse |   23 import urlparse | 
|   24 import zipfile |  | 
|   25 import logging |   24 import logging | 
|   26  |   25  | 
|   27  |   26  | 
|   28 class Source: |   27 class Source: | 
|   29     def resolve_link(self, url, locale): |   28     def resolve_link(self, url, locale): | 
|   30         parsed = urlparse.urlparse(url) |   29         parsed = urlparse.urlparse(url) | 
|   31         page = parsed.path |   30         page = parsed.path | 
|   32         if parsed.scheme != '' or page.startswith('/') or page.startswith('.'): |   31         if parsed.scheme != '' or page.startswith('/') or page.startswith('.'): | 
|   33             # Not a page link |   32             # Not a page link | 
|   34             return None, None |   33             return None, None | 
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  214     def include_filename(include, format): |  213     def include_filename(include, format): | 
|  215         return 'includes/%s.%s' % (include, format) |  214         return 'includes/%s.%s' % (include, format) | 
|  216  |  215  | 
|  217     def has_include(self, include, format): |  216     def has_include(self, include, format): | 
|  218         return self.has_file(self.include_filename(include, format)) |  217         return self.has_file(self.include_filename(include, format)) | 
|  219  |  218  | 
|  220     def read_include(self, include, format): |  219     def read_include(self, include, format): | 
|  221         return self.read_file(self.include_filename(include, format)) |  220         return self.read_file(self.include_filename(include, format)) | 
|  222  |  221  | 
|  223  |  222  | 
|  224 class MercurialSource(Source): |  | 
|  225     def __init__(self, repo, revision): |  | 
|  226         command = ['hg', '-R', repo, 'archive', '-r', revision, |  | 
|  227                    '-t', 'uzip', '-p', 'root', '-'] |  | 
|  228         data = subprocess.check_output(command) |  | 
|  229         self._archive = zipfile.ZipFile(StringIO(data), mode='r') |  | 
|  230  |  | 
|  231         command = ['hg', '-R', repo, 'id', '-n', '-r', revision] |  | 
|  232         self.version = subprocess.check_output(command).strip() |  | 
|  233  |  | 
|  234         self._name = os.path.basename(repo.rstrip(os.path.sep)) |  | 
|  235  |  | 
|  236     def __enter__(self): |  | 
|  237         return self |  | 
|  238  |  | 
|  239     def __exit__(self, type, value, traceback): |  | 
|  240         self.close() |  | 
|  241         return False |  | 
|  242  |  | 
|  243     def close(self): |  | 
|  244         self._archive.close() |  | 
|  245  |  | 
|  246     def has_file(self, filename): |  | 
|  247         try: |  | 
|  248             self._archive.getinfo('root/' + filename) |  | 
|  249         except KeyError: |  | 
|  250             return False |  | 
|  251         return True |  | 
|  252  |  | 
|  253     def read_file(self, filename, binary=False): |  | 
|  254         data = self._archive.read('root/' + filename) |  | 
|  255         if not binary: |  | 
|  256             data = data.decode('utf-8') |  | 
|  257         return (data, '%s!%s' % (self._name, filename)) |  | 
|  258  |  | 
|  259     def list_files(self, subdir): |  | 
|  260         prefix = 'root/{}/'.format(subdir) |  | 
|  261         for filename in self._archive.namelist(): |  | 
|  262             if filename.startswith(prefix): |  | 
|  263                 yield filename[len(prefix):] |  | 
|  264  |  | 
|  265     if os.name == 'posix': |  | 
|  266         def get_cache_dir(self): |  | 
|  267             return '/var/cache/' + self._name |  | 
|  268  |  | 
|  269  |  | 
|  270 class FileSource(Source): |  223 class FileSource(Source): | 
|  271     def __init__(self, dir): |  224     def __init__(self, dir): | 
|  272         self._dir = dir |  225         self._dir = dir | 
|  273  |  226  | 
|  274     def __enter__(self): |  227     def __enter__(self): | 
|  275         return self |  228         return self | 
|  276  |  229  | 
|  277     def __exit__(self, type, value, traceback): |  230     def __exit__(self, type, value, traceback): | 
|  278         return False |  231         return False | 
|  279  |  232  | 
|  280     def close(self): |  233     def close(self): | 
|  281         pass |  234         pass | 
|  282  |  235  | 
 |  236     @property | 
 |  237     def version(self): | 
 |  238         return randint(1, 2 ** 32) | 
 |  239  | 
|  283     def get_path(self, filename): |  240     def get_path(self, filename): | 
|  284         return os.path.join(self._dir, *filename.split('/')) |  241         return os.path.join(self._dir, *filename.split('/')) | 
|  285  |  242  | 
|  286     def has_file(self, filename): |  243     def has_file(self, filename): | 
|  287         return os.path.isfile(self.get_path(filename)) |  244         return os.path.isfile(self.get_path(filename)) | 
|  288  |  245  | 
|  289     def read_file(self, filename, binary=False): |  246     def read_file(self, filename, binary=False): | 
|  290         path = self.get_path(filename) |  247         path = self.get_path(filename) | 
|  291  |  248  | 
|  292         if binary: |  249         if binary: | 
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  404  |  361  | 
|  405  |  362  | 
|  406 def create_source(path, cached=False, revision=None): |  363 def create_source(path, cached=False, revision=None): | 
|  407     """Create a source from path and optional revision. |  364     """Create a source from path and optional revision. | 
|  408  |  365  | 
|  409     `cached` flag activates caching. This can be used to optimize performance |  366     `cached` flag activates caching. This can be used to optimize performance | 
|  410     if no changes are expected on the filesystem after the source was created. |  367     if no changes are expected on the filesystem after the source was created. | 
|  411     This is usually the case with static generation (as opposed to dynamic |  368     This is usually the case with static generation (as opposed to dynamic | 
|  412     preview). |  369     preview). | 
|  413  |  370  | 
|  414     If `revision` option is provided, the `path` is assumed to be pointing to a |  | 
|  415     Mercurial repository. In this case the source will return the content of |  | 
|  416     selected revision (using `MercurialSource`) instead of the content of the |  | 
|  417     directory. Note that any local changes will be ignored in this case. |  | 
|  418  |  | 
|  419     If `settings.ini` in the source contains `[paths]` section with an |  371     If `settings.ini` in the source contains `[paths]` section with an | 
|  420     `additional-paths` key that contains the list of additional root folders, |  372     `additional-paths` key that contains the list of additional root folders, | 
|  421     `MultiSource` will be instantiated and its bases will be the original |  373     `MultiSource` will be instantiated and its bases will be the original | 
|  422     source plus an additional source for each additional root folder. |  374     source plus an additional source for each additional root folder. | 
|  423     `MultiSource` looks up files in its base sources in the order they are |  375     `MultiSource` looks up files in its base sources in the order they are | 
|  424     provided, so the files in the additional folders will only be used if the |  376     provided, so the files in the additional folders will only be used if the | 
|  425     original source doesn't contain that file. |  377     original source doesn't contain that file. | 
|  426     """ |  378     """ | 
|  427     if revision is not None: |  379     source = FileSource(path) | 
|  428         source = MercurialSource(path, revision) |  | 
|  429     else: |  | 
|  430         source = FileSource(path) |  | 
|  431  |  380  | 
|  432     config = source.read_config() |  381     config = source.read_config() | 
|  433     try: |  382     try: | 
|  434         ap = config.get('paths', 'additional-paths').strip() |  383         ap = config.get('paths', 'additional-paths').strip() | 
|  435         additional_paths = filter(None, ap.split()) |  384         additional_paths = filter(None, ap.split()) | 
|  436     except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): |  385     except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): | 
|  437         additional_paths = [] |  386         additional_paths = [] | 
|  438  |  387  | 
|  439     if additional_paths: |  388     if additional_paths: | 
|  440         additional_sources = [ |  389         additional_sources = [ | 
|  441             create_source(os.path.join(path, p)) |  390             create_source(os.path.join(path, p)) | 
|  442             for p in additional_paths |  391             for p in additional_paths | 
|  443         ] |  392         ] | 
|  444         source = MultiSource([source] + additional_sources) |  393         source = MultiSource([source] + additional_sources) | 
|  445  |  394  | 
|  446     if cached: |  395     if cached: | 
|  447         for fname in [ |  396         for fname in [ | 
|  448             'resolve_link', |  397             'resolve_link', | 
|  449             'read_config', |  398             'read_config', | 
|  450             'read_template', |  399             'read_template', | 
|  451             'read_locale', |  400             'read_locale', | 
|  452             'read_include', |  401             'read_include', | 
|  453             'exec_file', |  402             'exec_file', | 
|  454         ]: |  403         ]: | 
|  455             setattr(source, fname, _memoize(getattr(source, fname))) |  404             setattr(source, fname, _memoize(getattr(source, fname))) | 
|  456  |  405  | 
|  457     return source |  406     return source | 
| OLD | NEW |