| 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 from compiled_file_system import CompiledFileSystem |
| 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 # See api_data_source.py for more info on _VERSION. | 18 # Increment this if the data model changes for SamplesDataSource. |
| 19 _VERSION = 3 | 19 _VERSION = 4 |
| 20 | 20 |
| 21 class SamplesDataSource(object): | 21 class SamplesDataSource(object): |
| 22 """Constructs a list of samples and their respective files and api calls. | 22 """Constructs a list of samples and their respective files and api calls. |
| 23 """ | 23 """ |
| 24 | |
| 25 class Factory(object): | 24 class Factory(object): |
| 26 """A factory to create SamplesDataSource instances bound to individual | 25 """A factory to create SamplesDataSource instances bound to individual |
| 27 Requests. | 26 Requests. |
| 28 """ | 27 """ |
| 29 def __init__(self, | 28 def __init__(self, |
| 30 channel, | 29 channel, |
| 31 file_system, | 30 extensions_file_system, |
| 32 github_file_system, | 31 apps_file_system, |
| 33 cache_factory, | |
| 34 github_cache_factory, | |
| 35 ref_resolver_factory, | 32 ref_resolver_factory, |
| 36 samples_path): | 33 extension_samples_path): |
| 37 self._file_system = file_system | 34 self._svn_file_system = extensions_file_system |
| 38 self._github_file_system = github_file_system | 35 self._github_file_system = apps_file_system |
| 39 self._static_path = '/%s/static' % channel | 36 self._static_path = '/%s/static' % channel |
| 40 self._extensions_cache = cache_factory.Create(self._MakeSamplesList, | |
| 41 compiled_fs.EXTENSIONS, | |
| 42 version=_VERSION) | |
| 43 self._apps_cache = github_cache_factory.Create( | |
| 44 lambda x, y: self._MakeSamplesList(x, y, is_apps=True), | |
| 45 compiled_fs.APPS, | |
| 46 version=_VERSION) | |
| 47 self._ref_resolver = ref_resolver_factory.Create() | 37 self._ref_resolver = ref_resolver_factory.Create() |
| 48 self._samples_path = samples_path | 38 self._extension_samples_path = extension_samples_path |
| 39 def create_compiled_fs(fs, fn, category): |
| 40 return CompiledFileSystem.Factory(fs).Create(fn, |
| 41 SamplesDataSource, |
| 42 category=category, |
| 43 version=_VERSION) |
| 44 self._extensions_cache = create_compiled_fs(extensions_file_system, |
| 45 self._MakeSamplesList, |
| 46 'extensions') |
| 47 self._apps_cache = create_compiled_fs(apps_file_system, |
| 48 lambda *args: self._MakeSamplesList( |
| 49 *args, is_apps=True), |
| 50 'apps') |
| 49 | 51 |
| 50 def Create(self, request): | 52 def Create(self, request): |
| 51 """Returns a new SamplesDataSource bound to |request|. | 53 """Returns a new SamplesDataSource bound to |request|. |
| 52 """ | 54 """ |
| 53 return SamplesDataSource(self._extensions_cache, | 55 return SamplesDataSource(self._extensions_cache, |
| 54 self._apps_cache, | 56 self._apps_cache, |
| 55 self._samples_path, | 57 self._extension_samples_path, |
| 56 request) | 58 request) |
| 57 | 59 |
| 58 def _GetAPIItems(self, js_file): | 60 def _GetAPIItems(self, js_file): |
| 59 chrome_regex = '(chrome\.[a-zA-Z0-9\.]+)' | 61 chrome_regex = '(chrome\.[a-zA-Z0-9\.]+)' |
| 60 calls = set(re.findall(chrome_regex, js_file)) | 62 calls = set(re.findall(chrome_regex, js_file)) |
| 61 # Find APIs that have been assigned into variables. | 63 # Find APIs that have been assigned into variables. |
| 62 assigned_vars = dict(re.findall('var\s*([^\s]+)\s*=\s*%s;' % chrome_regex, | 64 assigned_vars = dict(re.findall('var\s*([^\s]+)\s*=\s*%s;' % chrome_regex, |
| 63 js_file)) | 65 js_file)) |
| 64 # Replace the variable name with the full API name. | 66 # Replace the variable name with the full API name. |
| 65 for var_name, value in assigned_vars.iteritems(): | 67 for var_name, value in assigned_vars.iteritems(): |
| (...skipping 26 matching lines...) Expand all Loading... |
| 92 for locale_path, contents in | 94 for locale_path, contents in |
| 93 locales_files.iteritems()] | 95 locales_files.iteritems()] |
| 94 except ValueError as e: | 96 except ValueError as e: |
| 95 logging.error('Error parsing locales files for %s: %s' % (path, e)) | 97 logging.error('Error parsing locales files for %s: %s' % (path, e)) |
| 96 else: | 98 else: |
| 97 for path, json_ in locales_json: | 99 for path, json_ in locales_json: |
| 98 l10n_data['locales'][path[len(locales_path):].split('/')[0]] = json_ | 100 l10n_data['locales'][path[len(locales_path):].split('/')[0]] = json_ |
| 99 return l10n_data | 101 return l10n_data |
| 100 | 102 |
| 101 def _MakeSamplesList(self, base_dir, files, is_apps=False): | 103 def _MakeSamplesList(self, base_dir, files, is_apps=False): |
| 102 file_system = self._github_file_system if is_apps else self._file_system | 104 # HACK(kalman): The code here (for legacy reasons) assumes that |files| is |
| 105 # prefixed by |base_dir|, so make it true. |
| 106 files = ['%s%s' % (base_dir, f) for f in files] |
| 107 file_system = (self._github_file_system if is_apps else |
| 108 self._svn_file_system) |
| 103 samples_list = [] | 109 samples_list = [] |
| 104 for filename in sorted(files): | 110 for filename in sorted(files): |
| 105 if filename.rsplit('/')[-1] != 'manifest.json': | 111 if filename.rsplit('/')[-1] != 'manifest.json': |
| 106 continue | 112 continue |
| 107 # This is a little hacky, but it makes a sample page. | 113 # This is a little hacky, but it makes a sample page. |
| 108 sample_path = filename.rsplit('/', 1)[-2] | 114 sample_path = filename.rsplit('/', 1)[-2] |
| 109 sample_files = [path for path in files | 115 sample_files = [path for path in files |
| 110 if path.startswith(sample_path + '/')] | 116 if path.startswith(sample_path + '/')] |
| 111 js_files = [path for path in sample_files if path.endswith('.js')] | 117 js_files = [path for path in sample_files if path.endswith('.js')] |
| 112 try: | 118 try: |
| (...skipping 10 matching lines...) Expand all Loading... |
| 123 api_calls = [] | 129 api_calls = [] |
| 124 for item in sorted(api_items): | 130 for item in sorted(api_items): |
| 125 if len(item.split('.')) < 3: | 131 if len(item.split('.')) < 3: |
| 126 continue | 132 continue |
| 127 if item.endswith('.removeListener') or item.endswith('.hasListener'): | 133 if item.endswith('.removeListener') or item.endswith('.hasListener'): |
| 128 continue | 134 continue |
| 129 if item.endswith('.addListener'): | 135 if item.endswith('.addListener'): |
| 130 item = item[:-len('.addListener')] | 136 item = item[:-len('.addListener')] |
| 131 if item.startswith('chrome.'): | 137 if item.startswith('chrome.'): |
| 132 item = item[len('chrome.'):] | 138 item = item[len('chrome.'):] |
| 133 ref_data = self._ref_resolver.GetLink(item, 'samples') | 139 ref_data = self._ref_resolver.GetLink(item) |
| 134 if ref_data is None: | 140 if ref_data is None: |
| 135 continue | 141 continue |
| 136 api_calls.append({ | 142 api_calls.append({ |
| 137 'name': ref_data['text'], | 143 'name': ref_data['text'], |
| 138 'link': ref_data['href'] | 144 'link': ref_data['href'] |
| 139 }) | 145 }) |
| 140 try: | 146 try: |
| 141 manifest_data = self._GetDataFromManifest(sample_path, file_system) | 147 manifest_data = self._GetDataFromManifest(sample_path, file_system) |
| 142 except FileNotFoundError as e: | 148 except FileNotFoundError as e: |
| 143 logging.warning('Error getting data from samples manifest: %s. If ' | 149 logging.warning('Error getting data from samples manifest: %s. If ' |
| (...skipping 22 matching lines...) Expand all Loading... |
| 166 'id': hashlib.md5(url).hexdigest(), | 172 'id': hashlib.md5(url).hexdigest(), |
| 167 'download_url': download_url, | 173 'download_url': download_url, |
| 168 'url': url, | 174 'url': url, |
| 169 'files': [f.replace(sample_path + '/', '') for f in sample_files], | 175 'files': [f.replace(sample_path + '/', '') for f in sample_files], |
| 170 'api_calls': api_calls | 176 'api_calls': api_calls |
| 171 }) | 177 }) |
| 172 samples_list.append(manifest_data) | 178 samples_list.append(manifest_data) |
| 173 | 179 |
| 174 return samples_list | 180 return samples_list |
| 175 | 181 |
| 176 def __init__(self, extensions_cache, apps_cache, samples_path, request): | 182 def __init__(self, |
| 183 extensions_cache, |
| 184 apps_cache, |
| 185 extension_samples_path, |
| 186 request): |
| 177 self._extensions_cache = extensions_cache | 187 self._extensions_cache = extensions_cache |
| 178 self._apps_cache = apps_cache | 188 self._apps_cache = apps_cache |
| 179 self._samples_path = samples_path | 189 self._extension_samples_path = extension_samples_path |
| 180 self._request = request | 190 self._request = request |
| 181 | 191 |
| 182 def _GetAcceptedLanguages(self): | 192 def _GetAcceptedLanguages(self): |
| 183 accept_language = self._request.headers.get('Accept-Language', None) | 193 accept_language = self._request.headers.get('Accept-Language', None) |
| 184 if accept_language is None: | 194 if accept_language is None: |
| 185 return [] | 195 return [] |
| 186 return [lang_with_q.split(';')[0].strip() | 196 return [lang_with_q.split(';')[0].strip() |
| 187 for lang_with_q in accept_language.split(',')] | 197 for lang_with_q in accept_language.split(',')] |
| 188 | 198 |
| 189 def FilterSamples(self, key, api_name): | 199 def FilterSamples(self, key, api_name): |
| (...skipping 15 matching lines...) Expand all Loading... |
| 205 # If we're testing, the GithubFileSystem can't fetch samples. | 215 # If we're testing, the GithubFileSystem can't fetch samples. |
| 206 # Bug: http://crbug.com/141910 | 216 # Bug: http://crbug.com/141910 |
| 207 return [] | 217 return [] |
| 208 return samples_list | 218 return samples_list |
| 209 | 219 |
| 210 def _CreateSamplesDict(self, key): | 220 def _CreateSamplesDict(self, key): |
| 211 if key == 'apps': | 221 if key == 'apps': |
| 212 samples_list = self._apps_cache.GetFromFileListing('/') | 222 samples_list = self._apps_cache.GetFromFileListing('/') |
| 213 else: | 223 else: |
| 214 samples_list = self._extensions_cache.GetFromFileListing( | 224 samples_list = self._extensions_cache.GetFromFileListing( |
| 215 self._samples_path + '/') | 225 self._extension_samples_path + '/') |
| 216 return_list = [] | 226 return_list = [] |
| 217 for dict_ in samples_list: | 227 for dict_ in samples_list: |
| 218 name = dict_['name'] | 228 name = dict_['name'] |
| 219 description = dict_['description'] | 229 description = dict_['description'] |
| 220 if description is None: | 230 if description is None: |
| 221 description = '' | 231 description = '' |
| 222 if name.startswith('__MSG_') or description.startswith('__MSG_'): | 232 if name.startswith('__MSG_') or description.startswith('__MSG_'): |
| 223 try: | 233 try: |
| 224 # Copy the sample dict so we don't change the dict in the cache. | 234 # Copy the sample dict so we don't change the dict in the cache. |
| 225 sample_data = dict_.copy() | 235 sample_data = dict_.copy() |
| (...skipping 14 matching lines...) Expand all Loading... |
| 240 return_list.append(sample_data) | 250 return_list.append(sample_data) |
| 241 else: | 251 else: |
| 242 return_list.append(dict_) | 252 return_list.append(dict_) |
| 243 return return_list | 253 return return_list |
| 244 | 254 |
| 245 def get(self, key): | 255 def get(self, key): |
| 246 return { | 256 return { |
| 247 'apps': lambda: self._CreateSamplesDict('apps'), | 257 'apps': lambda: self._CreateSamplesDict('apps'), |
| 248 'extensions': lambda: self._CreateSamplesDict('extensions') | 258 'extensions': lambda: self._CreateSamplesDict('extensions') |
| 249 }.get(key, lambda: {})() | 259 }.get(key, lambda: {})() |
| OLD | NEW |