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 |