| 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: Dictionary with input path names as keys and SourceWithPaths |
| 180 as values. |
| 181 Returns: |
| 182 SourceWithPath: The source file providing the goog namespace. |
| 183 ''' |
| 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 |
| 174 def CalcDeps(bundle, sources, top_level): | 191 def CalcDeps(bundle, sources, top_level): |
| 175 '''Calculates dependencies for a set of top-level files. | 192 '''Calculates dependencies for a set of top-level files. |
| 176 | 193 |
| 177 Args: | 194 Args: |
| 178 bundle: Bundle to add the sources to. | 195 bundle: Bundle to add the sources to. |
| 179 sources, dict: Mapping from input path to SourceWithPaths objects. | 196 sources, dict: Mapping from input path to SourceWithPaths objects. |
| 180 top_level, list: List of top-level input paths to calculate dependencies | 197 top_level, list: List of top-level input paths to calculate dependencies |
| 181 for. | 198 for. |
| 182 ''' | 199 ''' |
| 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] | 200 providers = [s for s in sources.itervalues() if len(s.provides) > 0] |
| 191 deps = depstree.DepsTree(providers) | 201 deps = depstree.DepsTree(providers) |
| 192 namespaces = [] | 202 namespaces = [] |
| 193 for path in top_level: | 203 for path in top_level: |
| 194 namespaces.extend(sources[path].requires) | 204 namespaces.extend(sources[path].requires) |
| 195 # base.js is an implicit dependency that always goes first. | 205 # base.js is an implicit dependency that always goes first. |
| 196 bundle.Add(GetBase(sources)) | 206 bundle.Add(_GetBase(sources)) |
| 197 bundle.Add(deps.GetDependencies(namespaces)) | 207 bundle.Add(deps.GetDependencies(namespaces)) |
| 198 | 208 |
| 199 | 209 |
| 210 def _MarkAsCompiled(sources): |
| 211 '''Sets COMPILED to true in the Closure base.js source. |
| 212 |
| 213 Args: |
| 214 sources: Dictionary with input paths names as keys and SourcWithPaths |
| 215 objects as values. |
| 216 ''' |
| 217 base = _GetBase(sources) |
| 218 new_content, count = re.subn('^var COMPILED = false;$', |
| 219 'var COMPILED = true;', |
| 220 base.GetSource(), |
| 221 count=1, |
| 222 flags=re.MULTILINE) |
| 223 if count != 1: |
| 224 Die('COMPILED var assignment not found in %s' % base.GetInPath()) |
| 225 sources[base.GetInPath()] = SourceWithPaths( |
| 226 new_content, |
| 227 base.GetInPath(), |
| 228 base.GetOutPath()) |
| 229 |
| 200 def LinkOrCopyFiles(sources, dest_dir): | 230 def LinkOrCopyFiles(sources, dest_dir): |
| 201 '''Copies a list of sources to a destination directory.''' | 231 '''Copies a list of sources to a destination directory.''' |
| 202 | 232 |
| 203 def LinkOrCopyOneFile(src, dst): | 233 def LinkOrCopyOneFile(src, dst): |
| 204 if not os.path.exists(os.path.dirname(dst)): | 234 if not os.path.exists(os.path.dirname(dst)): |
| 205 os.makedirs(os.path.dirname(dst)) | 235 os.makedirs(os.path.dirname(dst)) |
| 206 if os.path.exists(dst): | 236 if os.path.exists(dst): |
| 207 # Avoid clobbering the inode if source and destination refer to the | 237 # Avoid clobbering the inode if source and destination refer to the |
| 208 # same file already. | 238 # same file already. |
| 209 if os.path.samefile(src, dst): | 239 if os.path.samefile(src, dst): |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 default='list', metavar='MODE', | 301 default='list', metavar='MODE', |
| 272 help=("Otput mode. One of 'list', 'html', 'bundle', " + | 302 help=("Otput mode. One of 'list', 'html', 'bundle', " + |
| 273 "'compressed_bundle' or 'copy'.")) | 303 "'compressed_bundle' or 'copy'.")) |
| 274 return parser | 304 return parser |
| 275 | 305 |
| 276 | 306 |
| 277 def main(): | 307 def main(): |
| 278 options, args = CreateOptionParser().parse_args() | 308 options, args = CreateOptionParser().parse_args() |
| 279 if len(args) < 1: | 309 if len(args) < 1: |
| 280 Die('At least one top-level source file must be specified.') | 310 Die('At least one top-level source file must be specified.') |
| 311 will_output_source_text = options.mode in ('bundle', 'compressed_bundle') |
| 281 path_rewriter = PathRewriter(options.prefix_map) | 312 path_rewriter = PathRewriter(options.prefix_map) |
| 282 sources = ReadSources(options.roots, | 313 sources = ReadSources(options.roots, args, will_output_source_text, |
| 283 args, | |
| 284 options.mode in ('bundle', 'compressed_bundle'), | |
| 285 path_rewriter) | 314 path_rewriter) |
| 315 if will_output_source_text: |
| 316 _MarkAsCompiled(sources) |
| 286 bundle = Bundle() | 317 bundle = Bundle() |
| 287 if len(options.roots) > 0: | 318 if len(options.roots) > 0: |
| 288 CalcDeps(bundle, sources, args) | 319 CalcDeps(bundle, sources, args) |
| 289 bundle.Add((sources[name] for name in args)) | 320 bundle.Add((sources[name] for name in args)) |
| 290 if options.mode == 'copy': | 321 if options.mode == 'copy': |
| 291 if options.dest_dir is None: | 322 if options.dest_dir is None: |
| 292 Die('Must specify --dest_dir when copying.') | 323 Die('Must specify --dest_dir when copying.') |
| 293 LinkOrCopyFiles(bundle.GetSources(), options.dest_dir) | 324 LinkOrCopyFiles(bundle.GetSources(), options.dest_dir) |
| 294 else: | 325 else: |
| 295 if options.output_file: | 326 if options.output_file: |
| 296 out_file = open(options.output_file, 'w') | 327 out_file = open(options.output_file, 'w') |
| 297 else: | 328 else: |
| 298 out_file = sys.stdout | 329 out_file = sys.stdout |
| 299 try: | 330 try: |
| 300 WriteOutput(bundle, options.mode, out_file, options.dest_dir) | 331 WriteOutput(bundle, options.mode, out_file, options.dest_dir) |
| 301 finally: | 332 finally: |
| 302 if options.output_file: | 333 if options.output_file: |
| 303 out_file.close() | 334 out_file.close() |
| 304 | 335 |
| 305 | 336 |
| 306 if __name__ == '__main__': | 337 if __name__ == '__main__': |
| 307 main() | 338 main() |
| OLD | NEW |