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 json | 5 import json |
| 6 import logging |
6 import re | 7 import re |
7 | 8 |
8 DEFAULT_ICON_PATH = '/static/images/sample-default-icon.png' | 9 DEFAULT_ICON_PATH = '/static/images/sample-default-icon.png' |
9 | 10 |
10 class SamplesDataSource(object): | 11 class SamplesDataSource(object): |
11 """Constructs a list of samples and their respective files and api calls. | 12 """Constructs a list of samples and their respective files and api calls. |
12 """ | 13 """ |
13 def __init__(self, fetcher, cache_builder, samples_path): | 14 |
14 self._fetcher = fetcher | 15 class Factory(object): |
15 self._cache = cache_builder.build(self._MakeSamplesList) | 16 """A factory to create SamplesDataSource instances bound to individual |
| 17 Requests. |
| 18 """ |
| 19 def __init__(self, file_system, cache_builder, samples_path): |
| 20 self._file_system = file_system |
| 21 self._cache = cache_builder.build(self._MakeSamplesList) |
| 22 self._samples_path = samples_path |
| 23 |
| 24 def Create(self, request): |
| 25 """Returns a new SamplesDataSource bound to |request|. |
| 26 """ |
| 27 return SamplesDataSource(self._cache, |
| 28 self._samples_path, |
| 29 request) |
| 30 |
| 31 def _GetApiItems(self, js_file): |
| 32 return set(re.findall('(chrome\.[a-zA-Z0-9\.]+)', js_file)) |
| 33 |
| 34 def _MakeApiLink(self, prefix, item): |
| 35 api, name = item.replace('chrome.', '').split('.', 1) |
| 36 return api + '.html#' + prefix + '-' + name |
| 37 |
| 38 def _GetDataFromManifest(self, path): |
| 39 manifest = self._file_system.ReadSingle(path + '/manifest.json') |
| 40 manifest_json = json.loads(manifest) |
| 41 l10n_data = { |
| 42 'name': manifest_json.get('name', ''), |
| 43 'description': manifest_json.get('description', ''), |
| 44 'icon': manifest_json.get('icons', {}).get('128', None), |
| 45 'default_locale': manifest_json.get('default_locale', None), |
| 46 'locales': {} |
| 47 } |
| 48 if not l10n_data['default_locale']: |
| 49 return l10n_data |
| 50 locales_path = path + '/_locales/' |
| 51 locales_dir = self._file_system.ReadSingle(locales_path) |
| 52 if locales_dir: |
| 53 locales_files = self._file_system.Read( |
| 54 [locales_path + f + 'messages.json' for f in locales_dir]).Get() |
| 55 locales_json = [(path, json.loads(contents)) |
| 56 for path, contents in locales_files.iteritems()] |
| 57 for path, json_ in locales_json: |
| 58 l10n_data['locales'][path[len(locales_path):].split('/')[0]] = json_ |
| 59 return l10n_data |
| 60 |
| 61 def _MakeSamplesList(self, files): |
| 62 samples_list = [] |
| 63 for filename in sorted(files): |
| 64 if filename.rsplit('/')[-1] != 'manifest.json': |
| 65 continue |
| 66 # This is a little hacky, but it makes a sample page. |
| 67 sample_path = filename.rsplit('/', 1)[-2] |
| 68 sample_files = [path for path in files |
| 69 if path.startswith(sample_path + '/')] |
| 70 js_files = [path for path in sample_files if path.endswith('.js')] |
| 71 js_contents = self._file_system.Read(js_files).Get() |
| 72 api_items = set() |
| 73 for js in js_contents.values(): |
| 74 api_items.update(self._GetApiItems(js)) |
| 75 |
| 76 api_calls = [] |
| 77 for item in api_items: |
| 78 if len(item.split('.')) < 3: |
| 79 continue |
| 80 if item.endswith('.addListener'): |
| 81 item = item.replace('.addListener', '') |
| 82 api_calls.append({ |
| 83 'name': item, |
| 84 'link': self._MakeApiLink('event', item) |
| 85 }) |
| 86 else: |
| 87 api_calls.append({ |
| 88 'name': item, |
| 89 'link': self._MakeApiLink('method', item) |
| 90 }) |
| 91 l10n_data = self._GetDataFromManifest(sample_path) |
| 92 sample_base_path = sample_path.split('/', 1)[1] |
| 93 if l10n_data['icon'] is None: |
| 94 icon_path = DEFAULT_ICON_PATH |
| 95 else: |
| 96 icon_path = sample_base_path + '/' + l10n_data['icon'] |
| 97 l10n_data.update({ |
| 98 'icon': icon_path, |
| 99 'path': sample_base_path, |
| 100 'files': [f.replace(sample_path + '/', '') for f in sample_files], |
| 101 'api_calls': api_calls |
| 102 }) |
| 103 samples_list.append(l10n_data) |
| 104 |
| 105 return samples_list |
| 106 |
| 107 def __init__(self, cache, samples_path, request): |
| 108 self._cache = cache |
16 self._samples_path = samples_path | 109 self._samples_path = samples_path |
| 110 self._request = request |
17 | 111 |
18 def _GetApiItems(self, js_file): | 112 def _GetAcceptedLanguages(self): |
19 return set(re.findall('(chrome\.[a-zA-Z0-9\.]+)', js_file)) | 113 accept_language = self._request.headers.get('Accept-Language', None) |
20 | 114 if accept_language is None: |
21 def _MakeApiLink(self, prefix, item): | 115 return [] |
22 api, name = item.replace('chrome.', '').split('.', 1) | 116 return [lang_with_q.split(';')[0].strip() |
23 return api + '.html#' + prefix + '-' + name | 117 for lang_with_q in accept_language.split(',')] |
24 | |
25 def _GetDataFromManifest(self, path): | |
26 manifest_path = path + '/manifest.json' | |
27 manifest = self._fetcher.Read([manifest_path]).Get()[manifest_path] | |
28 manifest_json = json.loads(manifest) | |
29 return { | |
30 'name': manifest_json.get('name'), | |
31 'description': manifest_json.get('description'), | |
32 'icon': manifest_json.get('icons', {}).get('128', None) | |
33 } | |
34 | |
35 def _MakeSamplesList(self, files): | |
36 samples_list = [] | |
37 for filename in sorted(files): | |
38 if filename.rsplit('/')[-1] != 'manifest.json': | |
39 continue | |
40 # This is a little hacky, but it makes a sample page. | |
41 sample_path = filename.rsplit('/', 1)[-2] | |
42 sample_files = filter(lambda x: x.startswith(sample_path + '/'), files) | |
43 js_files = filter(lambda x: x.endswith('.js'), sample_files) | |
44 js_contents = self._fetcher.Read(js_files).Get() | |
45 api_items = set() | |
46 for js in js_contents.values(): | |
47 api_items.update(self._GetApiItems(js)) | |
48 | |
49 api_calls = [] | |
50 for item in api_items: | |
51 if len(item.split('.')) < 3: | |
52 continue | |
53 if item.endswith('.addListener'): | |
54 item = item.replace('.addListener', '') | |
55 api_calls.append({ | |
56 'name': item, | |
57 'link': self._MakeApiLink('event', item) | |
58 }) | |
59 else: | |
60 api_calls.append({ | |
61 'name': item, | |
62 'link': self._MakeApiLink('method', item) | |
63 }) | |
64 samples_info = self._GetDataFromManifest(sample_path) | |
65 sample_base_path = sample_path.split('/', 1)[1] | |
66 if samples_info['icon'] is None: | |
67 icon_path = DEFAULT_ICON_PATH | |
68 else: | |
69 icon_path = sample_base_path + '/' + samples_info['icon'] | |
70 samples_info.update({ | |
71 'icon': icon_path, | |
72 'path': sample_base_path, | |
73 'files': [f.replace(sample_path + '/', '') for f in sample_files], | |
74 'api_calls': api_calls | |
75 }) | |
76 samples_list.append(samples_info) | |
77 return samples_list | |
78 | 118 |
79 def __getitem__(self, key): | 119 def __getitem__(self, key): |
80 return self.get(key) | 120 return self.get(key) |
81 | 121 |
82 def get(self, key): | 122 def get(self, key): |
83 return self._cache.GetFromFileListing(self._samples_path + '/') | 123 samples_list = self._cache.GetFromFileListing(self._samples_path + '/') |
| 124 return_list = [] |
| 125 for dict_ in samples_list: |
| 126 name = dict_['name'] |
| 127 description = dict_['description'] |
| 128 if name.startswith('__MSG_') or description.startswith('__MSG_'): |
| 129 try: |
| 130 # Copy the sample dict so we don't change the dict in the cache. |
| 131 sample_data = dict_.copy() |
| 132 name_key = name[len('__MSG_'):-len('__')] |
| 133 description_key = description[len('__MSG_'):-len('__')] |
| 134 locale = sample_data['default_locale'] |
| 135 for lang in self._GetAcceptedLanguages(): |
| 136 if lang in sample_data['locales']: |
| 137 locale = lang |
| 138 break |
| 139 locale_data = sample_data['locales'][locale] |
| 140 sample_data['name'] = locale_data[name_key]['message'] |
| 141 sample_data['description'] = locale_data[description_key]['message'] |
| 142 except Exception as e: |
| 143 logging.error(e) |
| 144 # Revert the sample to the original dict. |
| 145 sample_data = dict_ |
| 146 return_list.append(sample_data) |
| 147 else: |
| 148 return_list.append(dict_) |
| 149 return return_list |
OLD | NEW |