OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 |
| 3 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. |
| 6 |
| 7 '''Print the dependency tree for a JavaScript module. |
| 8 |
| 9 Given one or more root directories, specified by -r options and one top-level |
| 10 file, walk the dependency tree and print all modules encountered. |
| 11 A module is only expanded once; on a second encounter, its dependencies |
| 12 are represented by a line containing the characters '[...]' as a short-hand. |
| 13 ''' |
| 14 |
| 15 import optparse |
| 16 import os |
| 17 import sys |
| 18 |
| 19 from jsbundler import ReadSources |
| 20 |
| 21 |
| 22 def Die(message): |
| 23 '''Prints an error message and exit the program.''' |
| 24 print >>sys.stderr, message |
| 25 sys.exit(1) |
| 26 |
| 27 |
| 28 def CreateOptionParser(): |
| 29 parser = optparse.OptionParser(description=__doc__) |
| 30 parser.usage = '%prog [options] <top_level_file>' |
| 31 parser.add_option('-r', '--root', dest='roots', action='append', default=[], |
| 32 metavar='ROOT', |
| 33 help='Roots of directory trees to scan for sources. ' |
| 34 'If none specified, all of ChromeVox and closure sources ' |
| 35 'are scanned.') |
| 36 return parser |
| 37 |
| 38 |
| 39 def DefaultRoots(): |
| 40 script_dir = os.path.dirname(os.path.abspath(__file__)) |
| 41 source_root_dir = os.path.join(script_dir, *[os.path.pardir] * 6) |
| 42 return [os.path.relpath(os.path.join(script_dir, os.path.pardir)), |
| 43 os.path.relpath( |
| 44 os.path.join(source_root_dir, 'chrome', 'third_party', |
| 45 'chromevox', 'third_party', |
| 46 'closure-library', 'closure'))] |
| 47 |
| 48 |
| 49 def WalkDeps(sources, start_source): |
| 50 def Walk(source, depth): |
| 51 indent = ' ' * depth |
| 52 if source.GetInPath() in expanded and len(source.requires) > 0: |
| 53 print '%s[...]' % indent |
| 54 return |
| 55 expanded.add(source.GetInPath()) |
| 56 for require in source.requires: |
| 57 if not require in providers: |
| 58 Die('%s not provided, required by %s' % (require, source.GetInPath())) |
| 59 require_source = providers[require] |
| 60 print '%s%s (%s)' % (indent, require, require_source.GetInPath()) |
| 61 Walk(require_source, depth + 1) |
| 62 |
| 63 # Create a map from provided module names to source objects. |
| 64 providers = {} |
| 65 expanded = set() |
| 66 for source in sources.values(): |
| 67 for provide in source.provides: |
| 68 if provide in providers: |
| 69 Die('%s provided multiple times' % provide) |
| 70 providers[provide] = source |
| 71 |
| 72 print '(%s)' % start_source.GetInPath() |
| 73 Walk(start_source, 1) |
| 74 |
| 75 |
| 76 def main(): |
| 77 parser = CreateOptionParser() |
| 78 options, args = parser.parse_args() |
| 79 if len(args) != 1: |
| 80 Die('Exactly one top-level source file must be specified.') |
| 81 start_path = args[0] |
| 82 roots = options.roots or DefaultRoots() |
| 83 sources = ReadSources(roots=roots, source_files=[start_path]) |
| 84 start_source = sources[start_path] |
| 85 WalkDeps(sources, start_source) |
| 86 |
| 87 |
| 88 if __name__ == '__main__': |
| 89 main() |
OLD | NEW |