| 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 import third_party.json_schema_compiler.json_comment_eater as json_comment_eater | 12 import third_party.json_schema_compiler.json_comment_eater as json_comment_eater |
| 13 import third_party.json_schema_compiler.model as model | 13 import third_party.json_schema_compiler.model as model |
| 14 import url_constants | 14 import url_constants |
| 15 | 15 |
| 16 DEFAULT_ICON_PATH = '/images/sample-default-icon.png' | 16 DEFAULT_ICON_PATH = '/images/sample-default-icon.png' |
| 17 | 17 |
| 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): | 18 class SamplesDataSource(object): |
| 30 """Constructs a list of samples and their respective files and api calls. | 19 """Constructs a list of samples and their respective files and api calls. |
| 31 """ | 20 """ |
| 32 | 21 |
| 33 class Factory(object): | 22 class Factory(object): |
| 34 """A factory to create SamplesDataSource instances bound to individual | 23 """A factory to create SamplesDataSource instances bound to individual |
| 35 Requests. | 24 Requests. |
| 36 """ | 25 """ |
| 37 def __init__(self, | 26 def __init__(self, |
| 38 channel, | 27 channel, |
| 39 file_system, | 28 file_system, |
| 40 github_file_system, | 29 github_file_system, |
| 41 cache_factory, | 30 cache_factory, |
| 42 github_cache_factory, | 31 github_cache_factory, |
| 43 api_list_data_source_factory, | 32 ref_resolver_factory, |
| 44 samples_path): | 33 samples_path): |
| 45 self._file_system = file_system | 34 self._file_system = file_system |
| 46 self._github_file_system = github_file_system | 35 self._github_file_system = github_file_system |
| 47 self._static_path = ((('/' + channel) if channel != 'local' else '') + | 36 self._static_path = ((('/' + channel) if channel != 'local' else '') + |
| 48 '/static') | 37 '/static') |
| 49 self._extensions_cache = cache_factory.Create(self._MakeSamplesList, | 38 self._extensions_cache = cache_factory.Create(self._MakeSamplesList, |
| 50 compiled_fs.EXTENSIONS) | 39 compiled_fs.EXTENSIONS) |
| 51 self._apps_cache = github_cache_factory.Create( | 40 self._apps_cache = github_cache_factory.Create( |
| 52 lambda x: self._MakeSamplesList(x, is_apps=True), | 41 lambda x: self._MakeSamplesList(x, is_apps=True), |
| 53 compiled_fs.APPS) | 42 compiled_fs.APPS) |
| 54 self._api_list_data_source = api_list_data_source_factory.Create() | 43 self._ref_resolver = ref_resolver_factory.Create() |
| 55 self._samples_path = samples_path | 44 self._samples_path = samples_path |
| 56 | 45 |
| 57 def Create(self, request): | 46 def Create(self, request): |
| 58 """Returns a new SamplesDataSource bound to |request|. | 47 """Returns a new SamplesDataSource bound to |request|. |
| 59 """ | 48 """ |
| 60 return SamplesDataSource(self._extensions_cache, | 49 return SamplesDataSource(self._extensions_cache, |
| 61 self._apps_cache, | 50 self._apps_cache, |
| 62 self._samples_path, | 51 self._samples_path, |
| 63 request) | 52 request) |
| 64 | 53 |
| 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): | 54 def _GetAPIItems(self, js_file): |
| 74 return set(re.findall('(chrome\.[a-zA-Z0-9\.]+)', js_file)) | 55 return set(re.findall('(chrome\.[a-zA-Z0-9\.]+)', js_file)) |
| 75 | 56 |
| 76 def _GetDataFromManifest(self, path, file_system): | 57 def _GetDataFromManifest(self, path, file_system): |
| 77 manifest = file_system.ReadSingle(path + '/manifest.json') | 58 manifest = file_system.ReadSingle(path + '/manifest.json') |
| 78 try: | 59 try: |
| 79 manifest_json = json.loads(json_comment_eater.Nom(manifest)) | 60 manifest_json = json.loads(json_comment_eater.Nom(manifest)) |
| 80 except ValueError as e: | 61 except ValueError as e: |
| 81 logging.error('Error parsing manifest.json for %s: %s' % (path, e)) | 62 logging.error('Error parsing manifest.json for %s: %s' % (path, e)) |
| 82 return None | 63 return None |
| (...skipping 18 matching lines...) Expand all Loading... |
| 101 except ValueError as e: | 82 except ValueError as e: |
| 102 logging.error('Error parsing locales files for %s: %s' % (path, e)) | 83 logging.error('Error parsing locales files for %s: %s' % (path, e)) |
| 103 else: | 84 else: |
| 104 for path, json_ in locales_json: | 85 for path, json_ in locales_json: |
| 105 l10n_data['locales'][path[len(locales_path):].split('/')[0]] = json_ | 86 l10n_data['locales'][path[len(locales_path):].split('/')[0]] = json_ |
| 106 return l10n_data | 87 return l10n_data |
| 107 | 88 |
| 108 def _MakeSamplesList(self, files, is_apps=False): | 89 def _MakeSamplesList(self, files, is_apps=False): |
| 109 file_system = self._github_file_system if is_apps else self._file_system | 90 file_system = self._github_file_system if is_apps else self._file_system |
| 110 samples_list = [] | 91 samples_list = [] |
| 111 api_list = self._GetAllAPINames() | |
| 112 for filename in sorted(files): | 92 for filename in sorted(files): |
| 113 if filename.rsplit('/')[-1] != 'manifest.json': | 93 if filename.rsplit('/')[-1] != 'manifest.json': |
| 114 continue | 94 continue |
| 115 # This is a little hacky, but it makes a sample page. | 95 # This is a little hacky, but it makes a sample page. |
| 116 sample_path = filename.rsplit('/', 1)[-2] | 96 sample_path = filename.rsplit('/', 1)[-2] |
| 117 sample_files = [path for path in files | 97 sample_files = [path for path in files |
| 118 if path.startswith(sample_path + '/')] | 98 if path.startswith(sample_path + '/')] |
| 119 js_files = [path for path in sample_files if path.endswith('.js')] | 99 js_files = [path for path in sample_files if path.endswith('.js')] |
| 120 try: | 100 try: |
| 121 js_contents = file_system.Read(js_files).Get() | 101 js_contents = file_system.Read(js_files).Get() |
| 122 except FileNotFoundError as e: | 102 except FileNotFoundError as e: |
| 123 logging.warning('Error fetching samples files: %s. Was a file ' | 103 logging.warning('Error fetching samples files: %s. Was a file ' |
| 124 'deleted from a sample? This warning should go away ' | 104 'deleted from a sample? This warning should go away ' |
| 125 'in 5 minutes.' % e) | 105 'in 5 minutes.' % e) |
| 126 continue | 106 continue |
| 127 api_items = set() | 107 api_items = set() |
| 128 for js in js_contents.values(): | 108 for js in js_contents.values(): |
| 129 api_items.update(self._GetAPIItems(js)) | 109 api_items.update(self._GetAPIItems(js)) |
| 130 | 110 |
| 131 api_calls = [] | 111 api_calls = [] |
| 132 for item in api_items: | 112 for item in api_items: |
| 133 if len(item.split('.')) < 3: | 113 if len(item.split('.')) < 3: |
| 134 continue | 114 continue |
| 135 if item.endswith('.removeListener') or item.endswith('.hasListener'): | 115 if item.endswith('.removeListener') or item.endswith('.hasListener'): |
| 136 continue | 116 continue |
| 137 if item.endswith('.addListener'): | 117 if item.endswith('.addListener'): |
| 138 item = item[:-len('.addListener')] | 118 item = item[:-len('.addListener')] |
| 139 link = _MakeAPILink('event', item, api_list) | 119 if item.startswith('chrome.'): |
| 140 if link is None: | 120 item = item[len('chrome.'):] |
| 141 continue | 121 ref_data = self._ref_resolver.GetLink('samples', item) |
| 142 api_calls.append({ | 122 if ref_data is None: |
| 143 'name': item, | 123 continue |
| 144 'link': link | 124 api_calls.append({ |
| 145 }) | 125 'name': ref_data['text'], |
| 146 else: | 126 'link': ref_data['href'] |
| 147 # TODO(cduvall): this might be a property or a type. | 127 }) |
| 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: | 128 try: |
| 156 manifest_data = self._GetDataFromManifest(sample_path, file_system) | 129 manifest_data = self._GetDataFromManifest(sample_path, file_system) |
| 157 except FileNotFoundError as e: | 130 except FileNotFoundError as e: |
| 158 logging.warning('Error getting data from samples manifest: %s. If ' | 131 logging.warning('Error getting data from samples manifest: %s. If ' |
| 159 'this file was deleted from a sample this message ' | 132 'this file was deleted from a sample this message ' |
| 160 'should go away in 5 minutes.' % e) | 133 'should go away in 5 minutes.' % e) |
| 161 continue | 134 continue |
| 162 if manifest_data is None: | 135 if manifest_data is None: |
| 163 continue | 136 continue |
| 164 | 137 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 sample_data['description'] = locale_data[description_key]['message'] | 221 sample_data['description'] = locale_data[description_key]['message'] |
| 249 except Exception as e: | 222 except Exception as e: |
| 250 logging.error(e) | 223 logging.error(e) |
| 251 # Revert the sample to the original dict. | 224 # Revert the sample to the original dict. |
| 252 sample_data = dict_ | 225 sample_data = dict_ |
| 253 return_list.append(sample_data) | 226 return_list.append(sample_data) |
| 254 else: | 227 else: |
| 255 return_list.append(dict_) | 228 return_list.append(dict_) |
| 256 return return_list | 229 return return_list |
| 257 | 230 |
| 258 def __getitem__(self, key): | |
| 259 return self.get(key) | |
| 260 | |
| 261 def get(self, key): | 231 def get(self, key): |
| 262 return { | 232 return { |
| 263 'apps': lambda: self._CreateSamplesDict('apps'), | 233 'apps': lambda: self._CreateSamplesDict('apps'), |
| 264 'extensions': lambda: self._CreateSamplesDict('extensions') | 234 'extensions': lambda: self._CreateSamplesDict('extensions') |
| 265 }.get(key, lambda: {})() | 235 }.get(key, lambda: {})() |
| OLD | NEW |