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 """Docbuilder for extension docs.""" | 6 """Docbuilder for extension docs.""" |
7 | 7 |
8 import glob | 8 import glob |
9 import os | 9 import os |
10 import os.path | 10 import os.path |
(...skipping 30 matching lines...) Expand all Loading... |
41 # the calling environment may not be setup to set the PYTHONPATH | 41 # the calling environment may not be setup to set the PYTHONPATH |
42 # Insert at the front so that we pick up our simplejson even if there's a | 42 # Insert at the front so that we pick up our simplejson even if there's a |
43 # system simplejson installed, for predictable escaping. | 43 # system simplejson installed, for predictable escaping. |
44 sys.path.insert(0, os.path.normpath(_base_dir + | 44 sys.path.insert(0, os.path.normpath(_base_dir + |
45 "/../../../../third_party")) | 45 "/../../../../third_party")) |
46 import simplejson as json | 46 import simplejson as json |
47 from directory import Sample | 47 from directory import Sample |
48 from directory import ApiManifest | 48 from directory import ApiManifest |
49 from directory import SamplesManifest | 49 from directory import SamplesManifest |
50 | 50 |
51 def RenderPages(names, dump_render_tree): | 51 def RenderPages(family, dump_render_tree, single_page_name): |
52 """ | 52 output_dir = os.path.join(_base_dir, family) |
53 Calls DumpRenderTree .../generator.html?<names> and writes the | 53 names = set(os.path.splitext(name)[0] for name in os.listdir(output_dir) |
54 results to .../docs/<name>.html | 54 if not name.startswith(".") and name.endswith(".html")) |
55 """ | 55 |
56 if not names: | 56 # Allow the user to render a single page if they want |
57 raise Exception("RenderPage called with empty names param") | 57 if single_page_name: |
| 58 if single_page_name in names: |
| 59 names = [single_page_name] |
| 60 else: |
| 61 return [] |
58 | 62 |
59 generator_url = "file:" + urllib.pathname2url(_generator_html) | 63 generator_url = "file:" + urllib.pathname2url(_generator_html) |
60 generator_url += "?" + ",".join(names) | 64 generator_url += "?" + family + "|" + ",".join(names) |
61 | 65 |
62 # Start with a fresh copy of page shell for each file. | 66 # Start with a fresh copy of page shell for each file. |
63 # Save the current contents so that we can look for changes later. | 67 # Save the current contents so that we can look for changes later. |
64 originals = {} | 68 originals = {} |
65 for name in names: | 69 for name in names: |
66 input_file = _base_dir + "/" + name + ".html" | 70 output_file = os.path.join(output_dir, name + ".html") |
67 | 71 |
68 if (os.path.isfile(input_file)): | 72 if (os.path.isfile(output_file)): |
69 originals[name] = open(input_file, 'rb').read() | 73 originals[name] = open(output_file, 'rb').read() |
70 os.remove(input_file) | 74 os.remove(output_file) |
71 else: | 75 else: |
72 originals[name] = "" | 76 originals[name] = "" |
73 | 77 |
74 shutil.copy(_page_shell_html, input_file) | 78 shutil.copy(_page_shell_html, output_file) |
75 | 79 |
76 # Run DumpRenderTree and capture result | 80 # Run DumpRenderTree and capture result |
77 dump_render_tree_timeout = 1000 * 60 * 5 # five minutes | 81 dump_render_tree_timeout = 1000 * 60 * 5 # five minutes |
78 p = Popen( | 82 p = Popen( |
79 [dump_render_tree, "--test-shell", | 83 [dump_render_tree, "--test-shell", |
80 "%s %s" % (generator_url, dump_render_tree_timeout)], | 84 "%s %s" % (generator_url, dump_render_tree_timeout)], |
81 stdout=PIPE) | 85 stdout=PIPE) |
82 | 86 |
83 # The remaining output will be the content of the generated pages. | 87 # The remaining output will be the content of the generated pages. |
84 output = p.stdout.read() | 88 output = p.stdout.read() |
(...skipping 18 matching lines...) Expand all Loading... |
103 for name in names: | 107 for name in names: |
104 result = output_parsed[name].encode("utf8") + '\n' | 108 result = output_parsed[name].encode("utf8") + '\n' |
105 | 109 |
106 # Remove CRs that are appearing from captured DumpRenderTree output. | 110 # Remove CRs that are appearing from captured DumpRenderTree output. |
107 result = result.replace('\r', '') | 111 result = result.replace('\r', '') |
108 | 112 |
109 # Remove empty style attributes. | 113 # Remove empty style attributes. |
110 result = result.replace(' style=""', '') | 114 result = result.replace(' style=""', '') |
111 | 115 |
112 # Remove page_shell | 116 # Remove page_shell |
113 input_file = _base_dir + "/" + name + ".html" | 117 output_file = os.path.join(output_dir, name + ".html") |
114 os.remove(input_file) | 118 os.remove(output_file) |
115 | 119 |
116 # Write output | 120 # Write output |
117 open(input_file, 'wb').write(result) | 121 open(output_file, 'wb').write(result) |
118 if (originals[name] and result != originals[name]): | 122 if (originals[name] and result != originals[name]): |
119 changed_files.append(input_file) | 123 changed_files.append(output_file) |
120 | 124 |
121 return changed_files | 125 return changed_files |
122 | 126 |
123 | 127 |
124 def FindDumpRenderTree(): | 128 def FindDumpRenderTree(): |
125 # This is hacky. It is used to guess the location of the DumpRenderTree | 129 # This is hacky. It is used to guess the location of the DumpRenderTree |
126 chrome_dir = os.path.normpath(_base_dir + "/../../../") | 130 chrome_dir = os.path.normpath(_base_dir + "/../../../") |
127 src_dir = os.path.normpath(chrome_dir + "/../") | 131 src_dir = os.path.normpath(chrome_dir + "/../") |
128 | 132 |
129 search_locations = [] | 133 search_locations = [] |
(...skipping 28 matching lines...) Expand all Loading... |
158 for loc in search_locations: | 162 for loc in search_locations: |
159 if os.path.isfile(loc): | 163 if os.path.isfile(loc): |
160 return loc | 164 return loc |
161 | 165 |
162 raise Exception("Could not find DumpRenderTree executable\n" | 166 raise Exception("Could not find DumpRenderTree executable\n" |
163 "**DumpRenderTree may need to be built**\n" | 167 "**DumpRenderTree may need to be built**\n" |
164 "Searched: \n" + "\n".join(search_locations) + "\n" | 168 "Searched: \n" + "\n".join(search_locations) + "\n" |
165 "To specify a path to DumpRenderTree use " | 169 "To specify a path to DumpRenderTree use " |
166 "--dump-render-tree-path") | 170 "--dump-render-tree-path") |
167 | 171 |
168 def GetStaticFileNames(): | |
169 static_files = os.listdir(_static_dir) | |
170 return set(os.path.splitext(file_name)[0] | |
171 for file_name in static_files | |
172 if file_name.endswith(".html") and not file_name.startswith(".")) | |
173 | |
174 def main(): | 172 def main(): |
175 # Prevent windows from using cygwin python. | 173 # Prevent windows from using cygwin python. |
176 if (sys.platform == "cygwin"): | 174 if (sys.platform == "cygwin"): |
177 sys.exit("Building docs not supported for cygwin python. Please run the " | 175 sys.exit("Building docs not supported for cygwin python. Please run the " |
178 "build.sh script instead, which uses depot_tools python.") | 176 "build.sh script instead, which uses depot_tools python.") |
179 | 177 |
180 parser = OptionParser() | 178 parser = OptionParser() |
181 parser.add_option("--dump-render-tree-path", dest="dump_render_tree_path", | 179 parser.add_option("--dump-render-tree-path", dest="dump_render_tree_path", |
182 metavar="PATH", | 180 metavar="PATH", |
183 help="path to DumpRenderTree executable") | 181 help="path to DumpRenderTree executable") |
184 parser.add_option("--page-name", dest="page_name", metavar="PAGE", | 182 parser.add_option("--page-name", dest="page_name", metavar="PAGE", |
185 help="only generate docs for PAGE.html") | 183 help="only generate docs for PAGE.html") |
186 parser.add_option("--nozip", dest="zips", action="store_false", | 184 parser.add_option("--nozip", dest="zips", action="store_false", |
187 help="do not generate zip files for samples", | 185 help="do not generate zip files for samples", |
188 default=True) | 186 default=True) |
189 options, args = parser.parse_args() | 187 options, args = parser.parse_args() |
190 | 188 |
191 if (options.dump_render_tree_path and | 189 if (options.dump_render_tree_path and |
192 os.path.isfile(options.dump_render_tree_path)): | 190 os.path.isfile(options.dump_render_tree_path)): |
193 dump_render_tree = options.dump_render_tree_path | 191 dump_render_tree = options.dump_render_tree_path |
194 else: | 192 else: |
195 dump_render_tree = FindDumpRenderTree() | 193 dump_render_tree = FindDumpRenderTree() |
196 | 194 |
197 # Load the manifest of existing API Methods | 195 # Load the manifest of existing API Methods |
198 api_manifest = ApiManifest(_extension_api_json_schemas, | 196 api_manifest = ApiManifest(_extension_api_json_schemas, |
199 _extension_api_idl_schemas) | 197 _extension_api_idl_schemas) |
200 | 198 |
201 # Read static file names | |
202 static_names = GetStaticFileNames() | |
203 | |
204 # Read module names | |
205 module_names = api_manifest.getModuleNames() | |
206 | |
207 # All pages to generate | |
208 page_names = static_names | module_names | |
209 | |
210 # Allow the user to render a single page if they want | |
211 if options.page_name: | |
212 if options.page_name in page_names: | |
213 page_names = [options.page_name] | |
214 else: | |
215 raise Exception("--page-name argument must be one of %s." % | |
216 ', '.join(sorted(page_names))) | |
217 | |
218 # Write temporary JSON files based on the IDL inputs | 199 # Write temporary JSON files based on the IDL inputs |
219 api_manifest.generateJSONFromIDL() | 200 api_manifest.generateJSONFromIDL() |
220 | 201 |
221 # Render a manifest file containing metadata about all the extension samples | 202 # Render a manifest file containing metadata about all the extension samples |
222 samples_manifest = SamplesManifest(_samples_dir, _base_dir, api_manifest) | 203 samples_manifest = SamplesManifest(_samples_dir, _base_dir, api_manifest) |
223 samples_manifest.writeToFile(_samples_json) | 204 samples_manifest.writeToFile(_samples_json) |
224 | 205 |
225 # Write zipped versions of the samples listed in the manifest to the | 206 # Write zipped versions of the samples listed in the manifest to the |
226 # filesystem, unless the user has disabled it | 207 # filesystem, unless the user has disabled it |
| 208 modified_files = [] |
227 if options.zips: | 209 if options.zips: |
228 modified_zips = samples_manifest.writeZippedSamples() | 210 modified_files.extend(samples_manifest.writeZippedSamples()) |
229 else: | |
230 modified_zips = [] | |
231 | 211 |
232 modified_files = RenderPages(page_names, dump_render_tree) | 212 doc_families = ["extensions", "apps"] |
233 modified_files.extend(modified_zips) | 213 for family in doc_families: |
| 214 modified_files.extend( |
| 215 RenderPages(family, dump_render_tree, options.page_name)) |
234 | 216 |
235 if len(modified_files) == 0: | 217 if len(modified_files) == 0: |
236 print "Output files match existing files. No changes made." | 218 print "Output files match existing files. No changes made." |
237 else: | 219 else: |
238 print ("ATTENTION: EXTENSION DOCS HAVE CHANGED\n" + | 220 print ("ATTENTION: EXTENSION DOCS HAVE CHANGED\n" + |
239 "The following files have been modified and should be checked\n" + | 221 "The following files have been modified and should be checked\n" + |
240 "into source control (ideally in the same changelist as the\n" + | 222 "into source control (ideally in the same changelist as the\n" + |
241 "underlying files that resulting in their changing).") | 223 "underlying files that resulting in their changing).") |
242 for f in modified_files: | 224 for f in modified_files: |
243 print " * %s" % f | 225 print " * %s" % f |
244 | 226 |
245 # Hack. Sleep here, otherwise windows doesn't properly close the debug.log | 227 # Hack. Sleep here, otherwise windows doesn't properly close the debug.log |
246 # and the os.remove will fail with a "Permission denied". | 228 # and the os.remove will fail with a "Permission denied". |
247 time.sleep(1) | 229 time.sleep(1) |
248 debug_log = os.path.normpath(_build_dir + "/" + "debug.log") | 230 debug_log = os.path.normpath(_build_dir + "/" + "debug.log") |
249 if (os.path.isfile(debug_log)): | 231 if (os.path.isfile(debug_log)): |
250 os.remove(debug_log) | 232 os.remove(debug_log) |
251 | 233 |
252 # Cleanup our temporary IDL->JSON files | 234 # Cleanup our temporary IDL->JSON files |
253 api_manifest.cleanupGeneratedFiles() | 235 api_manifest.cleanupGeneratedFiles() |
254 | 236 |
255 if 'EX_OK' in dir(os): | 237 if 'EX_OK' in dir(os): |
256 return os.EX_OK | 238 return os.EX_OK |
257 else: | 239 else: |
258 return 0 | 240 return 0 |
259 | 241 |
260 if __name__ == '__main__': | 242 if __name__ == '__main__': |
261 sys.exit(main()) | 243 sys.exit(main()) |
OLD | NEW |