OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Class for parsing metadata about extension samples.""" | 6 """Class for parsing metadata about extension samples.""" |
7 | 7 |
8 import locale | 8 import locale |
9 import os | 9 import os |
10 import os.path | 10 import os.path |
11 import re | 11 import re |
12 import hashlib | 12 import hashlib |
13 import zipfile | 13 import zipfile |
14 import simplejson as json | 14 import simplejson as json |
15 import json_minify as minify | 15 import json_minify as minify |
16 | 16 |
17 # Make sure we get consistent string sorting behavior by explicitly using the | 17 # Make sure we get consistent string sorting behavior by explicitly using the |
18 # default C locale. | 18 # default C locale. |
19 locale.setlocale(locale.LC_ALL, 'C') | 19 locale.setlocale(locale.LC_ALL, 'C') |
20 | 20 |
| 21 import sys |
| 22 _script_path = os.path.realpath(__file__) |
| 23 _build_dir = os.path.dirname(_script_path) |
| 24 _base_dir = os.path.normpath(_build_dir + "/..") |
| 25 sys.path.insert(0, os.path.normpath(_base_dir + |
| 26 "/../../../../tools/json_schema_compiler")) |
| 27 import idl_schema |
| 28 |
21 def sorted_walk(path): | 29 def sorted_walk(path): |
22 """ A version of os.walk that yields results in order sorted by name. | 30 """ A version of os.walk that yields results in order sorted by name. |
23 | 31 |
24 This is to prevent spurious docs changes due to os.walk returning items in a | 32 This is to prevent spurious docs changes due to os.walk returning items in a |
25 filesystem dependent order (by inode creation time, etc). | 33 filesystem dependent order (by inode creation time, etc). |
26 """ | 34 """ |
27 for base, dirs, files in os.walk(path): | 35 for base, dirs, files in os.walk(path): |
28 dirs.sort() | 36 dirs.sort() |
29 files.sort() | 37 files.sort() |
30 yield base, dirs, files | 38 yield base, dirs, files |
(...skipping 20 matching lines...) Expand all Loading... |
51 try: | 59 try: |
52 json_str = json_file.read() | 60 json_str = json_file.read() |
53 json_obj = json.loads(minify.json_minify(json_str), encoding) | 61 json_obj = json.loads(minify.json_minify(json_str), encoding) |
54 except ValueError, msg: | 62 except ValueError, msg: |
55 raise Exception("Failed to parse JSON out of file %s: %s" % (path, msg)) | 63 raise Exception("Failed to parse JSON out of file %s: %s" % (path, msg)) |
56 finally: | 64 finally: |
57 json_file.close() | 65 json_file.close() |
58 | 66 |
59 return json_obj | 67 return json_obj |
60 | 68 |
| 69 def parse_idl_file(path): |
| 70 """ Load the specified file and parse it as IDL. |
| 71 |
| 72 Args: |
| 73 path: Path to a file containing JSON-encoded data. |
| 74 """ |
| 75 api_def = idl_schema.Load(path) |
| 76 return api_def |
| 77 |
| 78 def write_json_to_file(manifest, path): |
| 79 """ Writes the contents of this manifest file as a JSON-encoded text file. |
| 80 |
| 81 Args: |
| 82 manifest: The manifest structure to write. |
| 83 path: The path to write the manifest file to. |
| 84 |
| 85 Raises: |
| 86 Exception: If the file could not be written. |
| 87 """ |
| 88 manifest_text = json.dumps(manifest, indent=2, |
| 89 sort_keys=True, separators=(',', ': ')) |
| 90 output_path = os.path.realpath(path) |
| 91 try: |
| 92 output_file = open(output_path, 'w') |
| 93 except IOError, msg: |
| 94 raise Exception("Failed to write the samples manifest file." |
| 95 "The specific error was: %s." % msg) |
| 96 output_file.write(manifest_text) |
| 97 output_file.close() |
| 98 |
61 class ApiManifest(object): | 99 class ApiManifest(object): |
62 """ Represents the list of API methods contained in the extension API JSON """ | 100 """ Represents the list of API methods contained in the extension API JSON """ |
63 | 101 |
64 def __init__(self, manifest_paths): | 102 def __init__(self, json_paths, idl_paths): |
65 """ Read the supplied manifest file and parse its contents. | 103 """ Read the supplied json files and idl files and parse their contents. |
66 | 104 |
67 Args: | 105 Args: |
68 manifest_paths: Array of paths to API schemas. | 106 json_paths: Array of paths to .json API schemas. |
| 107 idl_paths: Array of paths to .idl API schemas. |
69 """ | 108 """ |
70 self._manifest = []; | 109 self._manifest = [] |
71 for path in manifest_paths: | 110 self._temporary_json_files = [] |
| 111 for path in json_paths: |
72 self._manifest.extend(parse_json_file(path)) | 112 self._manifest.extend(parse_json_file(path)) |
| 113 for path in idl_paths: |
| 114 module = parse_idl_file(path) |
| 115 json_path = os.path.realpath(path.replace('.idl', '.json')) |
| 116 self._temporary_json_files.append((module, json_path)) |
| 117 self._manifest.extend(module) |
73 | 118 |
74 def _parseModuleDocLinksByKeyTypes(self, module, key): | 119 def _parseModuleDocLinksByKeyTypes(self, module, key): |
75 """ | 120 """ |
76 Given a specific API module, returns a dict of methods mapped to | 121 Given a specific API module, returns a dict of methods mapped to |
77 documentation URLs. | 122 documentation URLs. |
78 | 123 |
79 Args: | 124 Args: |
80 module: The data in the extension API JSON for a single module. | 125 module: The data in the extension API JSON for a single module. |
81 key: A key belonging to _MODULE_DOC_KEYS to determine which set of | 126 key: A key belonging to _MODULE_DOC_KEYS to determine which set of |
82 methods to parse, and what kind of documentation URL to generate. | 127 methods to parse, and what kind of documentation URL to generate. |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 A dict of methods/events => partial doc links for every module. | 224 A dict of methods/events => partial doc links for every module. |
180 """ | 225 """ |
181 api_dict = {} | 226 api_dict = {} |
182 for module in self._manifest: | 227 for module in self._manifest: |
183 api_dict.update(self._parseModuleDocLinksByKey(module, 'functions')) | 228 api_dict.update(self._parseModuleDocLinksByKey(module, 'functions')) |
184 api_dict.update(self._parseModuleDocLinksByKeyTypes(module, 'functions')) | 229 api_dict.update(self._parseModuleDocLinksByKeyTypes(module, 'functions')) |
185 api_dict.update(self._parseModuleDocLinksByKey(module, 'events')) | 230 api_dict.update(self._parseModuleDocLinksByKey(module, 'events')) |
186 api_dict.update(self._parseModuleDocLinksByKeyTypes(module, 'events')) | 231 api_dict.update(self._parseModuleDocLinksByKeyTypes(module, 'events')) |
187 return api_dict | 232 return api_dict |
188 | 233 |
| 234 def generateJSONFromIDL(self): |
| 235 """ Writes temporary .json files for every .idl file we have read, for |
| 236 use by the documentation generator. |
| 237 """ |
| 238 for (module, json_path) in self._temporary_json_files: |
| 239 if os.path.exists(json_path): |
| 240 print ("WARNING: Overwriting existing file '%s'" |
| 241 " with generated content." % (json_path)) |
| 242 write_json_to_file(module, json_path) |
| 243 |
| 244 def cleanupGeneratedFiles(self): |
| 245 """ Removes the temporary .json files we generated from .idl before. |
| 246 """ |
| 247 for (module, json_path) in self._temporary_json_files: |
| 248 os.remove(json_path) |
| 249 |
189 class SamplesManifest(object): | 250 class SamplesManifest(object): |
190 """ Represents a manifest file containing information about the sample | 251 """ Represents a manifest file containing information about the sample |
191 extensions available in the codebase. """ | 252 extensions available in the codebase. """ |
192 | 253 |
193 def __init__(self, base_sample_path, base_dir, api_manifest): | 254 def __init__(self, base_sample_path, base_dir, api_manifest): |
194 """ Reads through the filesystem and obtains information about any Chrome | 255 """ Reads through the filesystem and obtains information about any Chrome |
195 extensions which exist underneath the specified folder. | 256 extensions which exist underneath the specified folder. |
196 | 257 |
197 Args: | 258 Args: |
198 base_sample_path: The directory under which to search for samples. | 259 base_sample_path: The directory under which to search for samples. |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 | 316 |
256 manifest_data = {'samples': samples, 'api': api_method_dict} | 317 manifest_data = {'samples': samples, 'api': api_method_dict} |
257 return manifest_data | 318 return manifest_data |
258 | 319 |
259 def writeToFile(self, path): | 320 def writeToFile(self, path): |
260 """ Writes the contents of this manifest file as a JSON-encoded text file. | 321 """ Writes the contents of this manifest file as a JSON-encoded text file. |
261 | 322 |
262 Args: | 323 Args: |
263 path: The path to write the samples manifest file to. | 324 path: The path to write the samples manifest file to. |
264 """ | 325 """ |
265 manifest_text = json.dumps(self._manifest_data, indent=2, | 326 write_json_to_file(self._manifest_data, path) |
266 sort_keys=True, separators=(',', ': ')) | |
267 output_path = os.path.realpath(path) | |
268 try: | |
269 output_file = open(output_path, 'w') | |
270 except IOError, msg: | |
271 raise Exception("Failed to write the samples manifest file." | |
272 "The specific error was: %s." % msg) | |
273 output_file.write(manifest_text) | |
274 output_file.close() | |
275 | 327 |
276 def writeZippedSamples(self): | 328 def writeZippedSamples(self): |
277 """ For each sample in the current manifest, create a zip file with the | 329 """ For each sample in the current manifest, create a zip file with the |
278 sample contents in the sample's parent directory if not zip exists, or | 330 sample contents in the sample's parent directory if not zip exists, or |
279 update the zip file if the sample has been updated. | 331 update the zip file if the sample has been updated. |
280 | 332 |
281 Returns: | 333 Returns: |
282 A set of paths representing zip files which have been modified. | 334 A set of paths representing zip files which have been modified. |
283 """ | 335 """ |
284 modified_paths = [] | 336 modified_paths = [] |
(...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
753 zip_file.write(abspath, relpath) | 805 zip_file.write(abspath, relpath) |
754 if file == 'manifest.json': | 806 if file == 'manifest.json': |
755 info = zip_file.getinfo(zip_manifest_path) | 807 info = zip_file.getinfo(zip_manifest_path) |
756 info.comment = self['source_hash'] | 808 info.comment = self['source_hash'] |
757 except RuntimeError, msg: | 809 except RuntimeError, msg: |
758 raise Exception("Could not write zip at %s: %s" % (zip_path, msg)) | 810 raise Exception("Could not write zip at %s: %s" % (zip_path, msg)) |
759 finally: | 811 finally: |
760 zip_file.close() | 812 zip_file.close() |
761 | 813 |
762 return self._get_relative_zip_path() | 814 return self._get_relative_zip_path() |
OLD | NEW |