| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import os | 5 from object_store_creator import ObjectStoreCreator |
| 6 | |
| 7 import object_store | |
| 8 | |
| 9 APPS = 'Apps' | |
| 10 APPS_FS = 'AppsFileSystem' | |
| 11 CRON = 'Cron' | |
| 12 EXTENSIONS = 'Extensions' | |
| 13 EXTENSIONS_FS = 'ExtensionsFileSystem' | |
| 14 CRON_FILE_LISTING = 'Cron.FileListing' | |
| 15 CRON_GITHUB_INVALIDATION = 'Cron.GithubInvalidation' | |
| 16 CRON_INVALIDATION = 'Cron.Invalidation' | |
| 17 HANDLEBAR = 'Handlebar' | |
| 18 IDL = 'IDL' | |
| 19 IDL_NO_REFS = 'IDLNoRefs' | |
| 20 IDL_NAMES = 'IDLNames' | |
| 21 INTRO = 'Intro' | |
| 22 JSON = 'JSON' | |
| 23 JSON_NO_REFS = 'JSONNoRefs' | |
| 24 LIST = 'List' | |
| 25 NAMES = 'Names' | |
| 26 PERMS = 'Perms' | |
| 27 SIDENAV = 'Sidenav' | |
| 28 STATIC = 'Static' | |
| 29 ZIP = 'Zip' | |
| 30 | 6 |
| 31 class _CacheEntry(object): | 7 class _CacheEntry(object): |
| 32 def __init__(self, cache_data, version): | 8 def __init__(self, cache_data, version): |
| 33 self._cache_data = cache_data | 9 self._cache_data = cache_data |
| 34 self.version = version | 10 self.version = version |
| 35 | 11 |
| 36 class CompiledFileSystem(object): | 12 class CompiledFileSystem(object): |
| 37 """This class caches FileSystem data that has been processed. | 13 """This class caches FileSystem data that has been processed. |
| 38 """ | 14 """ |
| 39 class Factory(object): | 15 class Factory(object): |
| 40 """A class to build a CompiledFileSystem. | 16 """A class to build a CompiledFileSystem backed by |file_system|. |
| 17 Set an explicit |store_type| for tests. |
| 41 """ | 18 """ |
| 42 def __init__(self, file_system, object_store): | 19 def __init__(self, file_system, store_type=None): |
| 43 self._file_system = file_system | 20 self._file_system = file_system |
| 44 self._object_store = object_store | 21 self._store_type = store_type |
| 22 self._identity_instance = None |
| 45 | 23 |
| 46 def Create(self, populate_function, namespace, version=None): | 24 def Create(self, populate_function, cls, category=None, version=None): |
| 47 """Create a CompiledFileSystem that populates the cache by calling | 25 """Create a CompiledFileSystem that populates the cache by calling |
| 48 |populate_function| with (path, data), where |data| is the data that was | 26 |populate_function| with (path, data), where |data| is the data that was |
| 49 fetched from |path|. The keys to the cache are put in the namespace | 27 fetched from |path|. |
| 50 specified by |namespace|, and optionally adding |version|. """ | 28 The namespace for the file system is derived like ObjectStoreCreator: from |
| 51 return CompiledFileSystem(self._file_system, | 29 |cls| along with an optional |category| and |version|. |
| 52 populate_function, | 30 """ |
| 53 self._object_store, | 31 assert isinstance(cls, type) |
| 54 namespace, | 32 assert not cls.__name__[0].islower() # guard against non-class types |
| 55 version=version) | 33 full_name = cls.__name__ |
| 34 if category is not None: |
| 35 full_name = '%s/%s' % (full_name, category) |
| 36 return self._Create(populate_function, full_name, version=version) |
| 37 |
| 38 def GetOrCreateIdentity(self): |
| 39 '''Handy helper to get or create the identity compiled file system. |
| 40 GetFromFile will return the file's contents. |
| 41 GetFromFileListing will return the directory list. |
| 42 ''' |
| 43 if self._identity_instance is None: |
| 44 self._identity_instance = self._Create(lambda _, x: x, 'id') |
| 45 return self._identity_instance |
| 46 |
| 47 def _Create(self, populate_function, full_name, version=None): |
| 48 object_store_creator = ObjectStoreCreator(CompiledFileSystem, |
| 49 store_type=self._store_type) |
| 50 return CompiledFileSystem( |
| 51 self._file_system, |
| 52 populate_function, |
| 53 object_store_creator.Create(category='%s/file' % full_name, |
| 54 version=version), |
| 55 object_store_creator.Create(category='%s/list' % full_name, |
| 56 version=version)) |
| 56 | 57 |
| 57 def __init__(self, | 58 def __init__(self, |
| 58 file_system, | 59 file_system, |
| 59 populate_function, | 60 populate_function, |
| 60 object_store, | 61 file_object_store, |
| 61 namespace, | 62 list_object_store): |
| 62 version=None): | |
| 63 self._file_system = file_system | 63 self._file_system = file_system |
| 64 self._populate_function = populate_function | 64 self._populate_function = populate_function |
| 65 self._object_store = object_store | 65 self._file_object_store = file_object_store |
| 66 self._namespace = 'CompiledFileSystem.' + namespace | 66 self._list_object_store = list_object_store |
| 67 if version is not None: | |
| 68 self._namespace = '%s.%s' % (self._namespace, version) | |
| 69 | 67 |
| 70 def _MakeKey(self, key): | 68 def _RecursiveList(self, path): |
| 71 return self._namespace + '.' + key | 69 files = [] |
| 72 | 70 for filename in self._file_system.ReadSingle(path): |
| 73 def _RecursiveList(self, files): | |
| 74 all_files = files[:] | |
| 75 dirs = {} | |
| 76 for filename in files: | |
| 77 if filename.endswith('/'): | 71 if filename.endswith('/'): |
| 78 all_files.remove(filename) | 72 files.extend(['%s%s' % (filename, f) |
| 79 dirs.update(self._file_system.Read([filename]).Get()) | 73 for f in self._RecursiveList('%s%s' % (path, filename))]) |
| 80 for dir_, files in dirs.iteritems(): | 74 else: |
| 81 all_files.extend(self._RecursiveList([dir_ + f for f in files])) | 75 files.append(filename) |
| 82 return all_files | 76 return files |
| 83 | 77 |
| 84 def GetFromFile(self, path, binary=False): | 78 def GetFromFile(self, path, binary=False): |
| 85 """Calls |populate_function| on the contents of the file at |path|. If | 79 """Calls |populate_function| on the contents of the file at |path|. If |
| 86 |binary| is True then the file will be read as binary - but this will only | 80 |binary| is True then the file will be read as binary - but this will only |
| 87 apply for the first time the file is fetched; if already cached, |binary| | 81 apply for the first time the file is fetched; if already cached, |binary| |
| 88 will be ignored. | 82 will be ignored. |
| 89 """ | 83 """ |
| 90 version = self._file_system.Stat(path).version | 84 version = self._file_system.Stat(path).version |
| 91 cache_entry = self._object_store.Get(self._MakeKey(path), | 85 cache_entry = self._file_object_store.Get(path, time=0).Get() |
| 92 object_store.FILE_SYSTEM_CACHE, | |
| 93 time=0).Get() | |
| 94 if (cache_entry is not None) and (version == cache_entry.version): | 86 if (cache_entry is not None) and (version == cache_entry.version): |
| 95 return cache_entry._cache_data | 87 return cache_entry._cache_data |
| 96 cache_data = self._populate_function( | 88 cache_data = self._populate_function( |
| 97 path, | 89 path, |
| 98 self._file_system.ReadSingle(path, binary=binary)) | 90 self._file_system.ReadSingle(path, binary=binary)) |
| 99 self._object_store.Set(self._MakeKey(path), | 91 self._file_object_store.Set(path, _CacheEntry(cache_data, version), time=0) |
| 100 _CacheEntry(cache_data, version), | |
| 101 object_store.FILE_SYSTEM_CACHE, | |
| 102 time=0) | |
| 103 return cache_data | 92 return cache_data |
| 104 | 93 |
| 105 def GetFromFileListing(self, path): | 94 def GetFromFileListing(self, path): |
| 106 """Calls |populate_function| on the listing of the files at |path|. | 95 """Calls |populate_function| on the listing of the files at |path|. |
| 107 Assumes that the path given is to a directory. | 96 Assumes that the path given is to a directory. |
| 108 """ | 97 """ |
| 109 if not path.endswith('/'): | 98 if not path.endswith('/'): |
| 110 path += '/' | 99 path += '/' |
| 111 version = self._file_system.Stat(path).version | 100 version = self._file_system.Stat(path).version |
| 112 cache_entry = self._object_store.Get( | 101 cache_entry = self._list_object_store.Get(path, time=0).Get() |
| 113 self._MakeKey(path), | |
| 114 object_store.FILE_SYSTEM_CACHE_LISTING, | |
| 115 time=0).Get() | |
| 116 if (cache_entry is not None) and (version == cache_entry.version): | 102 if (cache_entry is not None) and (version == cache_entry.version): |
| 117 return cache_entry._cache_data | 103 return cache_entry._cache_data |
| 118 cache_data = self._populate_function( | 104 cache_data = self._populate_function(path, self._RecursiveList(path)) |
| 119 path, | 105 self._list_object_store.Set(path, _CacheEntry(cache_data, version), time=0) |
| 120 self._RecursiveList( | |
| 121 [path + f for f in self._file_system.ReadSingle(path)])) | |
| 122 self._object_store.Set(self._MakeKey(path), | |
| 123 _CacheEntry(cache_data, version), | |
| 124 object_store.FILE_SYSTEM_CACHE_LISTING, | |
| 125 time=0) | |
| 126 return cache_data | 106 return cache_data |
| OLD | NEW |