Chromium Code Reviews| 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 hashlib | 5 import hashlib | 
| 6 import json | 6 import json | 
| 7 import logging | 7 import logging | 
| 8 import re | 8 import re | 
| 9 | 9 | 
| 10 import compiled_file_system as compiled_fs | 10 import compiled_file_system as compiled_fs | 
| 11 from file_system import FileNotFoundError | 11 from file_system import FileNotFoundError | 
| 12 from reference_resolver import ReferenceResolver | |
| 12 import third_party.json_schema_compiler.json_comment_eater as json_comment_eater | 13 import third_party.json_schema_compiler.json_comment_eater as json_comment_eater | 
| 13 import third_party.json_schema_compiler.model as model | 14 import third_party.json_schema_compiler.model as model | 
| 14 import url_constants | 15 import url_constants | 
| 15 | 16 | 
| 16 DEFAULT_ICON_PATH = '/images/sample-default-icon.png' | 17 DEFAULT_ICON_PATH = '/images/sample-default-icon.png' | 
| 17 | 18 | 
| 18 def _MakeAPILink(prefix, item, api_list): | |
| 19 item = item.replace('chrome.', '') | |
| 20 parts = item.split('.') | |
| 21 api_name = [] | |
| 22 for i in range(1, len(parts) + 1): | |
| 23 if '.'.join(parts[:i]) in api_list: | |
| 24 return '%s.html#%s-%s' % ('.'.join(parts[:i]), | |
| 25 prefix, | |
| 26 '.'.join(parts[i:])) | |
| 27 return None | |
| 28 | |
| 29 class SamplesDataSource(object): | 19 class SamplesDataSource(object): | 
| 30 """Constructs a list of samples and their respective files and api calls. | 20 """Constructs a list of samples and their respective files and api calls. | 
| 31 """ | 21 """ | 
| 32 | 22 | 
| 33 class Factory(object): | 23 class Factory(object): | 
| 34 """A factory to create SamplesDataSource instances bound to individual | 24 """A factory to create SamplesDataSource instances bound to individual | 
| 35 Requests. | 25 Requests. | 
| 36 """ | 26 """ | 
| 37 def __init__(self, | 27 def __init__(self, | 
| 38 channel, | 28 channel, | 
| 39 file_system, | 29 file_system, | 
| 40 github_file_system, | 30 github_file_system, | 
| 41 cache_factory, | 31 cache_factory, | 
| 42 github_cache_factory, | 32 github_cache_factory, | 
| 33 api_data_source_factory, | |
| 43 api_list_data_source_factory, | 34 api_list_data_source_factory, | 
| 44 samples_path): | 35 samples_path): | 
| 45 self._file_system = file_system | 36 self._file_system = file_system | 
| 46 self._github_file_system = github_file_system | 37 self._github_file_system = github_file_system | 
| 47 self._static_path = ((('/' + channel) if channel != 'local' else '') + | 38 self._static_path = ((('/' + channel) if channel != 'local' else '') + | 
| 48 '/static') | 39 '/static') | 
| 49 self._extensions_cache = cache_factory.Create(self._MakeSamplesList, | 40 self._extensions_cache = cache_factory.Create(self._MakeSamplesList, | 
| 50 compiled_fs.EXTENSIONS) | 41 compiled_fs.EXTENSIONS) | 
| 51 self._apps_cache = github_cache_factory.Create( | 42 self._apps_cache = github_cache_factory.Create( | 
| 52 lambda x: self._MakeSamplesList(x, is_apps=True), | 43 lambda x: self._MakeSamplesList(x, is_apps=True), | 
| 53 compiled_fs.APPS) | 44 compiled_fs.APPS) | 
| 54 self._api_list_data_source = api_list_data_source_factory.Create() | |
| 55 self._samples_path = samples_path | 45 self._samples_path = samples_path | 
| 46 self._reference_resolver = ReferenceResolver( | |
| 47 api_data_source_factory.Create(None, | |
| 48 self.Create(None), | |
| 49 resolve_refs=False), | |
| 50 api_list_data_source_factory.Create()) | |
| 
 
not at google - send to devlin
2012/11/02 17:26:48
A good clue for when you need to introduce a Facto
 
cduvall
2012/11/03 01:30:05
Cool, thanks for the architecture tips they're sup
 
 | |
| 56 | 51 | 
| 57 def Create(self, request): | 52 def Create(self, request): | 
| 58 """Returns a new SamplesDataSource bound to |request|. | 53 """Returns a new SamplesDataSource bound to |request|. | 
| 59 """ | 54 """ | 
| 60 return SamplesDataSource(self._extensions_cache, | 55 return SamplesDataSource(self._extensions_cache, | 
| 61 self._apps_cache, | 56 self._apps_cache, | 
| 62 self._samples_path, | 57 self._samples_path, | 
| 63 request) | 58 request) | 
| 64 | 59 | 
| 65 def _GetAllAPINames(self): | |
| 66 apis = [] | |
| 67 for k1 in ['apps', 'extensions']: | |
| 68 for k2 in ['chrome', 'experimental']: | |
| 69 apis.extend( | |
| 70 [api['name'] for api in self._api_list_data_source[k1][k2]]) | |
| 71 return apis | |
| 72 | |
| 73 def _GetAPIItems(self, js_file): | 60 def _GetAPIItems(self, js_file): | 
| 74 return set(re.findall('(chrome\.[a-zA-Z0-9\.]+)', js_file)) | 61 return set(re.findall('(chrome\.[a-zA-Z0-9\.]+)', js_file)) | 
| 75 | 62 | 
| 76 def _GetDataFromManifest(self, path, file_system): | 63 def _GetDataFromManifest(self, path, file_system): | 
| 77 manifest = file_system.ReadSingle(path + '/manifest.json') | 64 manifest = file_system.ReadSingle(path + '/manifest.json') | 
| 78 try: | 65 try: | 
| 79 manifest_json = json.loads(json_comment_eater.Nom(manifest)) | 66 manifest_json = json.loads(json_comment_eater.Nom(manifest)) | 
| 80 except ValueError as e: | 67 except ValueError as e: | 
| 81 logging.error('Error parsing manifest.json for %s: %s' % (path, e)) | 68 logging.error('Error parsing manifest.json for %s: %s' % (path, e)) | 
| 82 return None | 69 return None | 
| (...skipping 18 matching lines...) Expand all Loading... | |
| 101 except ValueError as e: | 88 except ValueError as e: | 
| 102 logging.error('Error parsing locales files for %s: %s' % (path, e)) | 89 logging.error('Error parsing locales files for %s: %s' % (path, e)) | 
| 103 else: | 90 else: | 
| 104 for path, json_ in locales_json: | 91 for path, json_ in locales_json: | 
| 105 l10n_data['locales'][path[len(locales_path):].split('/')[0]] = json_ | 92 l10n_data['locales'][path[len(locales_path):].split('/')[0]] = json_ | 
| 106 return l10n_data | 93 return l10n_data | 
| 107 | 94 | 
| 108 def _MakeSamplesList(self, files, is_apps=False): | 95 def _MakeSamplesList(self, files, is_apps=False): | 
| 109 file_system = self._github_file_system if is_apps else self._file_system | 96 file_system = self._github_file_system if is_apps else self._file_system | 
| 110 samples_list = [] | 97 samples_list = [] | 
| 111 api_list = self._GetAllAPINames() | |
| 112 for filename in sorted(files): | 98 for filename in sorted(files): | 
| 113 if filename.rsplit('/')[-1] != 'manifest.json': | 99 if filename.rsplit('/')[-1] != 'manifest.json': | 
| 114 continue | 100 continue | 
| 115 # This is a little hacky, but it makes a sample page. | 101 # This is a little hacky, but it makes a sample page. | 
| 116 sample_path = filename.rsplit('/', 1)[-2] | 102 sample_path = filename.rsplit('/', 1)[-2] | 
| 117 sample_files = [path for path in files | 103 sample_files = [path for path in files | 
| 118 if path.startswith(sample_path + '/')] | 104 if path.startswith(sample_path + '/')] | 
| 119 js_files = [path for path in sample_files if path.endswith('.js')] | 105 js_files = [path for path in sample_files if path.endswith('.js')] | 
| 120 try: | 106 try: | 
| 121 js_contents = file_system.Read(js_files).Get() | 107 js_contents = file_system.Read(js_files).Get() | 
| 122 except FileNotFoundError as e: | 108 except FileNotFoundError as e: | 
| 123 logging.warning('Error fetching samples files: %s. Was a file ' | 109 logging.warning('Error fetching samples files: %s. Was a file ' | 
| 124 'deleted from a sample? This warning should go away ' | 110 'deleted from a sample? This warning should go away ' | 
| 125 'in 5 minutes.' % e) | 111 'in 5 minutes.' % e) | 
| 126 continue | 112 continue | 
| 127 api_items = set() | 113 api_items = set() | 
| 128 for js in js_contents.values(): | 114 for js in js_contents.values(): | 
| 129 api_items.update(self._GetAPIItems(js)) | 115 api_items.update(self._GetAPIItems(js)) | 
| 130 | 116 | 
| 131 api_calls = [] | 117 api_calls = [] | 
| 132 for item in api_items: | 118 for item in api_items: | 
| 133 if len(item.split('.')) < 3: | 119 if len(item.split('.')) < 3: | 
| 134 continue | 120 continue | 
| 135 if item.endswith('.removeListener') or item.endswith('.hasListener'): | 121 if item.endswith('.removeListener') or item.endswith('.hasListener'): | 
| 136 continue | 122 continue | 
| 137 if item.endswith('.addListener'): | 123 if item.endswith('.addListener'): | 
| 138 item = item[:-len('.addListener')] | 124 item = item[:-len('.addListener')] | 
| 139 link = _MakeAPILink('event', item, api_list) | 125 if item.startswith('chrome.'): | 
| 140 if link is None: | 126 item = item[len('chrome.'):] | 
| 141 continue | 127 ref_data = self._reference_resolver.GetLinkToRefType('samples', item) | 
| 142 api_calls.append({ | 128 if ref_data is None: | 
| 143 'name': item, | 129 continue | 
| 144 'link': link | 130 api_calls.append({ | 
| 145 }) | 131 'name': ref_data['text'], | 
| 146 else: | 132 'link': ref_data['href'] | 
| 147 # TODO(cduvall): this might be a property or a type. | 133 }) | 
| 148 link = _MakeAPILink('method', item, api_list) | |
| 149 if link is None: | |
| 150 continue | |
| 151 api_calls.append({ | |
| 152 'name': item, | |
| 153 'link': link | |
| 154 }) | |
| 155 try: | 134 try: | 
| 156 manifest_data = self._GetDataFromManifest(sample_path, file_system) | 135 manifest_data = self._GetDataFromManifest(sample_path, file_system) | 
| 157 except FileNotFoundError as e: | 136 except FileNotFoundError as e: | 
| 158 logging.warning('Error getting data from samples manifest: %s. If ' | 137 logging.warning('Error getting data from samples manifest: %s. If ' | 
| 159 'this file was deleted from a sample this message ' | 138 'this file was deleted from a sample this message ' | 
| 160 'should go away in 5 minutes.' % e) | 139 'should go away in 5 minutes.' % e) | 
| 161 continue | 140 continue | 
| 162 if manifest_data is None: | 141 if manifest_data is None: | 
| 163 continue | 142 continue | 
| 164 | 143 | 
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 256 return return_list | 235 return return_list | 
| 257 | 236 | 
| 258 def __getitem__(self, key): | 237 def __getitem__(self, key): | 
| 259 return self.get(key) | 238 return self.get(key) | 
| 260 | 239 | 
| 261 def get(self, key): | 240 def get(self, key): | 
| 262 return { | 241 return { | 
| 263 'apps': lambda: self._CreateSamplesDict('apps'), | 242 'apps': lambda: self._CreateSamplesDict('apps'), | 
| 264 'extensions': lambda: self._CreateSamplesDict('extensions') | 243 'extensions': lambda: self._CreateSamplesDict('extensions') | 
| 265 }.get(key, lambda: {})() | 244 }.get(key, lambda: {})() | 
| OLD | NEW |