OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2009 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2009 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 """Docbuilder for extension docs.""" | 6 """Docbuilder for extension docs.""" |
7 | 7 |
8 import os | 8 import os |
9 import os.path | 9 import os.path |
10 import shutil | 10 import shutil |
11 import sys | 11 import sys |
12 import time | 12 import time |
13 import urllib | 13 import urllib |
14 | 14 |
15 from subprocess import Popen, PIPE | 15 from subprocess import Popen, PIPE |
16 from optparse import OptionParser | 16 from optparse import OptionParser |
17 | 17 |
18 _script_path = os.path.realpath(__file__) | 18 _script_path = os.path.realpath(__file__) |
19 _build_dir = os.path.dirname(_script_path) | 19 _build_dir = os.path.dirname(_script_path) |
20 _base_dir = os.path.normpath(_build_dir + "/..") | 20 _base_dir = os.path.normpath(_build_dir + "/..") |
21 _static_dir = _base_dir + "/static" | 21 _static_dir = _base_dir + "/static" |
22 _js_dir = _base_dir + "/js" | 22 _js_dir = _base_dir + "/js" |
23 _template_dir = _base_dir + "/template" | 23 _template_dir = _base_dir + "/template" |
| 24 _samples_dir = _base_dir + "/examples" |
24 _extension_api_dir = os.path.normpath(_base_dir + "/../api") | 25 _extension_api_dir = os.path.normpath(_base_dir + "/../api") |
25 | 26 |
26 _extension_api_json = _extension_api_dir + "/extension_api.json" | 27 _extension_api_json = _extension_api_dir + "/extension_api.json" |
27 _api_template_html = _template_dir + "/api_template.html" | 28 _api_template_html = _template_dir + "/api_template.html" |
28 _page_shell_html = _template_dir + "/page_shell.html" | 29 _page_shell_html = _template_dir + "/page_shell.html" |
29 _generator_html = _build_dir + "/generator.html" | 30 _generator_html = _build_dir + "/generator.html" |
| 31 _samples_json = _base_dir + "/samples.json" |
30 | 32 |
31 _expected_output_preamble = "<!DOCTYPE html>" | 33 _expected_output_preamble = "<!DOCTYPE html>" |
32 _expected_output_postamble = "</body></html>" | 34 _expected_output_postamble = "</body></html>" |
33 | 35 |
34 # HACK! This is required because we can only depend on python 2.4 and | 36 # HACK! This is required because we can only depend on python 2.4 and |
35 # the calling environment may not be setup to set the PYTHONPATH | 37 # the calling environment may not be setup to set the PYTHONPATH |
36 sys.path.append(os.path.normpath(_base_dir + | 38 sys.path.append(os.path.normpath(_base_dir + |
37 "/../../../../third_party")) | 39 "/../../../../third_party")) |
38 import simplejson as json | 40 import simplejson as json |
| 41 from directory import Sample |
| 42 from directory import ApiManifest |
| 43 from directory import SamplesManifest |
39 | 44 |
40 def RenderPage(name, test_shell): | 45 def RenderPage(name, test_shell): |
41 """ | 46 """ |
42 Calls test_shell --layout-tests .../generator.html?<name> and writes the | 47 Calls test_shell --layout-tests .../generator.html?<name> and writes the |
43 result to .../docs/<name>.html | 48 result to .../docs/<name>.html |
44 """ | 49 """ |
45 if not name: | 50 if not name: |
46 raise Exception("RenderPage called with empty name") | 51 raise Exception("RenderPage called with empty name") |
47 | 52 |
48 generator_url = "file:" + urllib.pathname2url(_generator_html) + "?" + name | 53 generator_url = "file:" + urllib.pathname2url(_generator_html) + "?" + name |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 | 130 |
126 for loc in search_locations: | 131 for loc in search_locations: |
127 if os.path.isfile(loc): | 132 if os.path.isfile(loc): |
128 return loc | 133 return loc |
129 | 134 |
130 raise Exception ("Could not find test_shell executable\n" + | 135 raise Exception ("Could not find test_shell executable\n" + |
131 "**test_shell may need to be built**\n" + | 136 "**test_shell may need to be built**\n" + |
132 "Searched: \n" + "\n".join(search_locations) + "\n" + | 137 "Searched: \n" + "\n".join(search_locations) + "\n" + |
133 "To specify a path to test_shell use --test-shell-path") | 138 "To specify a path to test_shell use --test-shell-path") |
134 | 139 |
135 def GetAPIModuleNames(): | |
136 try: | |
137 contents = open(_extension_api_json, 'r').read() | |
138 except IOError, msg: | |
139 raise Exception("Failed to read the file that defines the extensions API. " | |
140 "The specific error was: %s." % msg) | |
141 | |
142 try: | |
143 extension_api = json.loads(contents, encoding="ASCII") | |
144 except ValueError, msg: | |
145 raise Exception("File %s has a syntax error: %s" % | |
146 (_extension_api_json, msg)) | |
147 # Exclude modules with a "nodoc" property. | |
148 return set(module['namespace'].encode() for module in extension_api | |
149 if "nodoc" not in module) | |
150 | |
151 def GetStaticFileNames(): | 140 def GetStaticFileNames(): |
152 static_files = os.listdir(_static_dir) | 141 static_files = os.listdir(_static_dir) |
153 return set(os.path.splitext(file_name)[0] | 142 return set(os.path.splitext(file_name)[0] |
154 for file_name in static_files | 143 for file_name in static_files |
155 if file_name.endswith(".html") and not file_name.startswith(".")) | 144 if file_name.endswith(".html") and not file_name.startswith(".")) |
156 | 145 |
157 def main(): | 146 def main(): |
158 # Prevent windows from using cygwin python. | 147 # Prevent windows from using cygwin python. |
159 if (sys.platform == "cygwin"): | 148 if (sys.platform == "cygwin"): |
160 raise Exception("Building docs not supported for cygwin python.\n" | 149 raise Exception("Building docs not supported for cygwin python.\n" |
161 "Please run the build.bat script.") | 150 "Please run the build.bat script.") |
162 | 151 |
163 parser = OptionParser() | 152 parser = OptionParser() |
164 parser.add_option("--test-shell-path", dest="test_shell_path") | 153 parser.add_option("--test-shell-path", dest="test_shell_path") |
| 154 parser.add_option("--page-name", dest="page_name") |
165 (options, args) = parser.parse_args() | 155 (options, args) = parser.parse_args() |
166 | 156 |
167 if (options.test_shell_path and os.path.isfile(options.test_shell_path)): | 157 if (options.test_shell_path and os.path.isfile(options.test_shell_path)): |
168 test_shell = options.test_shell_path | 158 test_shell = options.test_shell_path |
169 else: | 159 else: |
170 test_shell = FindTestShell() | 160 test_shell = FindTestShell() |
171 | 161 |
| 162 # Load the manifest of existing API Methods |
| 163 api_manifest = ApiManifest(_extension_api_json) |
| 164 |
172 # Read static file names | 165 # Read static file names |
173 static_names = GetStaticFileNames() | 166 static_names = GetStaticFileNames() |
174 | 167 |
175 # Read module names | 168 # Read module names |
176 module_names = GetAPIModuleNames() | 169 module_names = api_manifest.getModuleNames() |
177 | 170 |
178 # All pages to generate | 171 # All pages to generate |
179 page_names = static_names | module_names | 172 page_names = static_names | module_names |
180 | 173 |
| 174 # Allow the user to render a single page if they want |
| 175 if options.page_name: |
| 176 if options.page_name in page_names: |
| 177 page_names = [options.page_name] |
| 178 else: |
| 179 raise Exception("--page-name argument must be one of %s." % |
| 180 ', '.join(sorted(page_names))) |
| 181 |
| 182 # Render a manifest file containing metadata about all the extension samples |
| 183 samples_manifest = SamplesManifest(_samples_dir, _base_dir, api_manifest) |
| 184 samples_manifest.writeToFile(_samples_json) |
| 185 |
181 modified_files = [] | 186 modified_files = [] |
182 for page in page_names: | 187 for page in page_names: |
183 modified_file = RenderPage(page, test_shell) | 188 modified_file = RenderPage(page, test_shell) |
184 if (modified_file): | 189 if (modified_file): |
185 modified_files.append(modified_file) | 190 modified_files.append(modified_file) |
186 | 191 |
187 if (len(modified_files) == 0): | 192 if (len(modified_files) == 0): |
188 print "Output files match existing files. No changes made." | 193 print "Output files match existing files. No changes made." |
189 else: | 194 else: |
190 print ("ATTENTION: EXTENSION DOCS HAVE CHANGED\n" + | 195 print ("ATTENTION: EXTENSION DOCS HAVE CHANGED\n" + |
191 "The following files have been modified and should be checked\n" + | 196 "The following files have been modified and should be checked\n" + |
192 "into source control (ideally in the same changelist as the\n" + | 197 "into source control (ideally in the same changelist as the\n" + |
193 "underlying files that resulting in their changing).") | 198 "underlying files that resulting in their changing).") |
194 for f in modified_files: | 199 for f in modified_files: |
195 print f | 200 print f |
196 | 201 |
197 # Hack. Sleep here, otherwise windows doesn't properly close the debug.log | 202 # Hack. Sleep here, otherwise windows doesn't properly close the debug.log |
198 # and the os.remove will fail with a "Permission denied". | 203 # and the os.remove will fail with a "Permission denied". |
199 time.sleep(1) | 204 time.sleep(1) |
200 debug_log = os.path.normpath(_build_dir + "/" + "debug.log") | 205 debug_log = os.path.normpath(_build_dir + "/" + "debug.log") |
201 if (os.path.isfile(debug_log)): | 206 if (os.path.isfile(debug_log)): |
202 os.remove(debug_log) | 207 os.remove(debug_log) |
203 | 208 |
204 return os.EX_OK | 209 return os.EX_OK |
205 | 210 |
206 if __name__ == '__main__': | 211 if __name__ == '__main__': |
207 sys.exit(main()) | 212 sys.exit(main()) |
OLD | NEW |