OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 | 2 |
3 # Copyright 2014 The Chromium Authors. All rights reserved. | 3 # Copyright 2014 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 '''Produces various output formats from a set of JavaScript files with | 7 '''Produces various output formats from a set of JavaScript files with |
8 closure style require/provide calls. | 8 closure style require/provide calls. |
9 | 9 |
10 Scans one or more directory trees for JavaScript files. Then, from a | 10 Scans one or more directory trees for JavaScript files. Then, from a |
(...skipping 14 matching lines...) Expand all Loading... | |
25 - compressed_bundle: A bundle where non-significant whitespace, including | 25 - compressed_bundle: A bundle where non-significant whitespace, including |
26 comments, has been stripped is output. | 26 comments, has been stripped is output. |
27 | 27 |
28 - copy: the files are copied, or hard linked if possible, to the destination | 28 - copy: the files are copied, or hard linked if possible, to the destination |
29 directory. In this case, no output is generated. | 29 directory. In this case, no output is generated. |
30 ''' | 30 ''' |
31 | 31 |
32 | 32 |
33 import optparse | 33 import optparse |
34 import os | 34 import os |
35 import re | |
35 import shutil | 36 import shutil |
36 import sys | 37 import sys |
37 | 38 |
38 _SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__)) | 39 _SCRIPT_DIR = os.path.realpath(os.path.dirname(__file__)) |
39 _CHROME_SOURCE = os.path.realpath( | 40 _CHROME_SOURCE = os.path.realpath( |
40 os.path.join(_SCRIPT_DIR, *[os.path.pardir] * 6)) | 41 os.path.join(_SCRIPT_DIR, *[os.path.pardir] * 6)) |
41 sys.path.insert(0, os.path.join( | 42 sys.path.insert(0, os.path.join( |
42 _CHROME_SOURCE, 'third_party/WebKit/Source/build/scripts')) | 43 _CHROME_SOURCE, 'third_party/WebKit/Source/build/scripts')) |
43 sys.path.insert(0, os.path.join( | 44 sys.path.insert(0, os.path.join( |
44 _CHROME_SOURCE, ('chrome/third_party/chromevox/third_party/' + | 45 _CHROME_SOURCE, ('chrome/third_party/chromevox/third_party/' + |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
164 for path in source_files: | 165 for path in source_files: |
165 if need_source_text: | 166 if need_source_text: |
166 EnsureSourceLoaded(path, sources) | 167 EnsureSourceLoaded(path, sources) |
167 else: | 168 else: |
168 # Just add an empty representation of the source. | 169 # Just add an empty representation of the source. |
169 sources[path] = SourceWithPaths( | 170 sources[path] = SourceWithPaths( |
170 '', path, path_rewriter.RewritePath(path)) | 171 '', path, path_rewriter.RewritePath(path)) |
171 return sources | 172 return sources |
172 | 173 |
173 | 174 |
175 def _GetBase(sources): | |
176 '''Gets the closure base.js file if present among the sources. | |
177 | |
178 Args: | |
179 sources, dict: Dictionary with SourceWithPath objects as values. | |
180 Returns: | |
David Tseng
2014/06/12 20:23:29
'sources, dict' looks like a pair so perhaps remov
| |
181 SourceWithPath: The source file providing the goog namespace. | |
182 ''' | |
183 for source in sources.itervalues(): | |
184 if (os.path.basename(source.GetInPath()) == 'base.js' and | |
185 'goog' in source.provides): | |
186 return source | |
187 Die('goog.base not provided by any file.') | |
188 | |
189 | |
174 def CalcDeps(bundle, sources, top_level): | 190 def CalcDeps(bundle, sources, top_level): |
175 '''Calculates dependencies for a set of top-level files. | 191 '''Calculates dependencies for a set of top-level files. |
176 | 192 |
177 Args: | 193 Args: |
178 bundle: Bundle to add the sources to. | 194 bundle: Bundle to add the sources to. |
179 sources, dict: Mapping from input path to SourceWithPaths objects. | 195 sources, dict: Mapping from input path to SourceWithPaths objects. |
180 top_level, list: List of top-level input paths to calculate dependencies | 196 top_level, list: List of top-level input paths to calculate dependencies |
181 for. | 197 for. |
182 ''' | 198 ''' |
183 def GetBase(sources): | |
184 for source in sources.itervalues(): | |
185 if (os.path.basename(source.GetInPath()) == 'base.js' and | |
186 'goog' in source.provides): | |
187 return source | |
188 Die('goog.base not provided by any file') | |
189 | |
190 providers = [s for s in sources.itervalues() if len(s.provides) > 0] | 199 providers = [s for s in sources.itervalues() if len(s.provides) > 0] |
191 deps = depstree.DepsTree(providers) | 200 deps = depstree.DepsTree(providers) |
192 namespaces = [] | 201 namespaces = [] |
193 for path in top_level: | 202 for path in top_level: |
194 namespaces.extend(sources[path].requires) | 203 namespaces.extend(sources[path].requires) |
195 # base.js is an implicit dependency that always goes first. | 204 # base.js is an implicit dependency that always goes first. |
196 bundle.Add(GetBase(sources)) | 205 bundle.Add(_GetBase(sources)) |
197 bundle.Add(deps.GetDependencies(namespaces)) | 206 bundle.Add(deps.GetDependencies(namespaces)) |
198 | 207 |
199 | 208 |
209 def _MarkAsCompiled(sources): | |
210 '''Sets COMPILED to true in the Closure base.js source.''' | |
David Tseng
2014/06/12 20:23:29
nit: Args?
| |
211 base = _GetBase(sources) | |
212 new_content, count = re.subn('^var COMPILED = false;$', | |
213 'var COMPILED = true;', | |
214 base.GetSource(), | |
215 count=1, | |
216 flags=re.MULTILINE) | |
217 if count != 1: | |
218 Die('COMPILED var assignment not found in %s' % base.GetInPath()) | |
David Tseng
2014/06/12 20:23:29
Print the count since technically it could be > 1
| |
219 sources[base.GetInPath()] = SourceWithPaths( | |
220 new_content, | |
221 base.GetInPath(), | |
222 base.GetOutPath()) | |
223 | |
200 def LinkOrCopyFiles(sources, dest_dir): | 224 def LinkOrCopyFiles(sources, dest_dir): |
201 '''Copies a list of sources to a destination directory.''' | 225 '''Copies a list of sources to a destination directory.''' |
202 | 226 |
203 def LinkOrCopyOneFile(src, dst): | 227 def LinkOrCopyOneFile(src, dst): |
204 if not os.path.exists(os.path.dirname(dst)): | 228 if not os.path.exists(os.path.dirname(dst)): |
205 os.makedirs(os.path.dirname(dst)) | 229 os.makedirs(os.path.dirname(dst)) |
206 if os.path.exists(dst): | 230 if os.path.exists(dst): |
207 # Avoid clobbering the inode if source and destination refer to the | 231 # Avoid clobbering the inode if source and destination refer to the |
208 # same file already. | 232 # same file already. |
209 if os.path.samefile(src, dst): | 233 if os.path.samefile(src, dst): |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
271 default='list', metavar='MODE', | 295 default='list', metavar='MODE', |
272 help=("Otput mode. One of 'list', 'html', 'bundle', " + | 296 help=("Otput mode. One of 'list', 'html', 'bundle', " + |
273 "'compressed_bundle' or 'copy'.")) | 297 "'compressed_bundle' or 'copy'.")) |
274 return parser | 298 return parser |
275 | 299 |
276 | 300 |
277 def main(): | 301 def main(): |
278 options, args = CreateOptionParser().parse_args() | 302 options, args = CreateOptionParser().parse_args() |
279 if len(args) < 1: | 303 if len(args) < 1: |
280 Die('At least one top-level source file must be specified.') | 304 Die('At least one top-level source file must be specified.') |
305 output_bundle = options.mode in ('bundle', 'compressed_bundle') | |
281 path_rewriter = PathRewriter(options.prefix_map) | 306 path_rewriter = PathRewriter(options.prefix_map) |
David Tseng
2014/06/12 20:23:29
Maybe call this need_source_text?
| |
282 sources = ReadSources(options.roots, | 307 sources = ReadSources(options.roots, args, output_bundle, path_rewriter) |
283 args, | 308 if output_bundle: |
284 options.mode in ('bundle', 'compressed_bundle'), | 309 _MarkAsCompiled(sources) |
285 path_rewriter) | |
286 bundle = Bundle() | 310 bundle = Bundle() |
287 if len(options.roots) > 0: | 311 if len(options.roots) > 0: |
288 CalcDeps(bundle, sources, args) | 312 CalcDeps(bundle, sources, args) |
289 bundle.Add((sources[name] for name in args)) | 313 bundle.Add((sources[name] for name in args)) |
290 if options.mode == 'copy': | 314 if options.mode == 'copy': |
291 if options.dest_dir is None: | 315 if options.dest_dir is None: |
292 Die('Must specify --dest_dir when copying.') | 316 Die('Must specify --dest_dir when copying.') |
293 LinkOrCopyFiles(bundle.GetSources(), options.dest_dir) | 317 LinkOrCopyFiles(bundle.GetSources(), options.dest_dir) |
294 else: | 318 else: |
295 if options.output_file: | 319 if options.output_file: |
296 out_file = open(options.output_file, 'w') | 320 out_file = open(options.output_file, 'w') |
297 else: | 321 else: |
298 out_file = sys.stdout | 322 out_file = sys.stdout |
299 try: | 323 try: |
300 WriteOutput(bundle, options.mode, out_file, options.dest_dir) | 324 WriteOutput(bundle, options.mode, out_file, options.dest_dir) |
301 finally: | 325 finally: |
302 if options.output_file: | 326 if options.output_file: |
303 out_file.close() | 327 out_file.close() |
304 | 328 |
305 | 329 |
306 if __name__ == '__main__': | 330 if __name__ == '__main__': |
307 main() | 331 main() |
OLD | NEW |