| 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 |