OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library pub.command.list; | 5 library pub.command.list; |
6 | 6 |
7 import 'dart:async'; | |
8 import 'dart:collection'; | 7 import 'dart:collection'; |
9 | 8 |
10 import '../ascii_tree.dart' as tree; | 9 import '../ascii_tree.dart' as tree; |
11 import '../command.dart'; | 10 import '../command.dart'; |
12 import '../log.dart' as log; | 11 import '../log.dart' as log; |
13 import '../package.dart'; | 12 import '../package.dart'; |
14 import '../package_graph.dart'; | |
15 import '../utils.dart'; | 13 import '../utils.dart'; |
16 | 14 |
17 /// Handles the `deps` pub command. | 15 /// Handles the `deps` pub command. |
18 class DepsCommand extends PubCommand { | 16 class DepsCommand extends PubCommand { |
19 String get name => "deps"; | 17 String get name => "deps"; |
20 String get description => "Print package dependencies."; | 18 String get description => "Print package dependencies."; |
21 List<String> get aliases => const ["dependencies", "tab"]; | 19 List<String> get aliases => const ["dependencies", "tab"]; |
22 String get invocation => "pub deps"; | 20 String get invocation => "pub deps"; |
23 String get docUrl => "http://dartlang.org/tools/pub/cmd/pub-deps.html"; | 21 String get docUrl => "http://dartlang.org/tools/pub/cmd/pub-deps.html"; |
24 bool get takesArguments => false; | 22 bool get takesArguments => false; |
25 | 23 |
26 /// The loaded package graph. | |
27 PackageGraph _graph; | |
28 | |
29 /// The [StringBuffer] used to accumulate the output. | 24 /// The [StringBuffer] used to accumulate the output. |
30 StringBuffer _buffer; | 25 StringBuffer _buffer; |
31 | 26 |
32 DepsCommand() { | 27 DepsCommand() { |
33 argParser.addOption("style", abbr: "s", | 28 argParser.addOption("style", abbr: "s", |
34 help: "How output should be displayed.", | 29 help: "How output should be displayed.", |
35 allowed: ["compact", "tree", "list"], | 30 allowed: ["compact", "tree", "list"], |
36 defaultsTo: "tree"); | 31 defaultsTo: "tree"); |
37 } | 32 } |
38 | 33 |
39 Future run() { | 34 void run() { |
40 return entrypoint.loadPackageGraph().then((graph) { | 35 // Explicitly run this in case we don't access `entrypoint.packageGraph`. |
41 _graph = graph; | 36 entrypoint.assertUpToDate(); |
42 _buffer = new StringBuffer(); | |
43 | 37 |
44 _buffer.writeln(_labelPackage(entrypoint.root)); | 38 _buffer = new StringBuffer(); |
45 | 39 |
46 switch (argResults["style"]) { | 40 _buffer.writeln(_labelPackage(entrypoint.root)); |
47 case "compact": _outputCompact(); break; | |
48 case "list": _outputList(); break; | |
49 case "tree": _outputTree(); break; | |
50 } | |
51 | 41 |
52 log.message(_buffer); | 42 switch (argResults["style"]) { |
53 }); | 43 case "compact": _outputCompact(); break; |
| 44 case "list": _outputList(); break; |
| 45 case "tree": _outputTree(); break; |
| 46 } |
| 47 |
| 48 log.message(_buffer); |
54 } | 49 } |
55 | 50 |
56 /// Outputs a list of all of the package's immediate, dev, override, and | 51 /// Outputs a list of all of the package's immediate, dev, override, and |
57 /// transitive dependencies. | 52 /// transitive dependencies. |
58 /// | 53 /// |
59 /// For each dependency listed, *that* package's immediate dependencies are | 54 /// For each dependency listed, *that* package's immediate dependencies are |
60 /// shown. Unlike [_outputList], this prints all of these dependencies on one | 55 /// shown. Unlike [_outputList], this prints all of these dependencies on one |
61 /// line. | 56 /// line. |
62 void _outputCompact() { | 57 void _outputCompact() { |
63 var root = entrypoint.root; | 58 var root = entrypoint.root; |
64 _outputCompactPackages("dependencies", | 59 _outputCompactPackages("dependencies", |
65 root.dependencies.map((dep) => dep.name)); | 60 root.dependencies.map((dep) => dep.name)); |
66 _outputCompactPackages("dev dependencies", | 61 _outputCompactPackages("dev dependencies", |
67 root.devDependencies.map((dep) => dep.name)); | 62 root.devDependencies.map((dep) => dep.name)); |
68 _outputCompactPackages("dependency overrides", | 63 _outputCompactPackages("dependency overrides", |
69 root.dependencyOverrides.map((dep) => dep.name)); | 64 root.dependencyOverrides.map((dep) => dep.name)); |
70 | 65 |
71 var transitive = _getTransitiveDependencies(); | 66 var transitive = _getTransitiveDependencies(); |
72 _outputCompactPackages("transitive dependencies", transitive); | 67 _outputCompactPackages("transitive dependencies", transitive); |
73 } | 68 } |
74 | 69 |
75 /// Outputs one section of packages in the compact output. | 70 /// Outputs one section of packages in the compact output. |
76 _outputCompactPackages(String section, Iterable<String> names) { | 71 _outputCompactPackages(String section, Iterable<String> names) { |
77 if (names.isEmpty) return; | 72 if (names.isEmpty) return; |
78 | 73 |
79 _buffer.writeln(); | 74 _buffer.writeln(); |
80 _buffer.writeln("$section:"); | 75 _buffer.writeln("$section:"); |
81 for (var name in ordered(names)) { | 76 for (var name in ordered(names)) { |
82 var package = _graph.packages[name]; | 77 var package = entrypoint.packageGraph.packages[name]; |
83 | 78 |
84 _buffer.write("- ${_labelPackage(package)}"); | 79 _buffer.write("- ${_labelPackage(package)}"); |
85 if (package.dependencies.isEmpty) { | 80 if (package.dependencies.isEmpty) { |
86 _buffer.writeln(); | 81 _buffer.writeln(); |
87 } else { | 82 } else { |
88 var depNames = package.dependencies.map((dep) => dep.name); | 83 var depNames = package.dependencies.map((dep) => dep.name); |
89 var depsList = "[${depNames.join(' ')}]"; | 84 var depsList = "[${depNames.join(' ')}]"; |
90 _buffer.writeln(" ${log.gray(depsList)}"); | 85 _buffer.writeln(" ${log.gray(depsList)}"); |
91 } | 86 } |
92 } | 87 } |
(...skipping 20 matching lines...) Expand all Loading... |
113 } | 108 } |
114 | 109 |
115 /// Outputs one section of packages in the list output. | 110 /// Outputs one section of packages in the list output. |
116 _outputListSection(String name, Iterable<String> deps) { | 111 _outputListSection(String name, Iterable<String> deps) { |
117 if (deps.isEmpty) return; | 112 if (deps.isEmpty) return; |
118 | 113 |
119 _buffer.writeln(); | 114 _buffer.writeln(); |
120 _buffer.writeln("$name:"); | 115 _buffer.writeln("$name:"); |
121 | 116 |
122 for (var name in deps) { | 117 for (var name in deps) { |
123 var package = _graph.packages[name]; | 118 var package = entrypoint.packageGraph.packages[name]; |
124 _buffer.writeln("- ${_labelPackage(package)}"); | 119 _buffer.writeln("- ${_labelPackage(package)}"); |
125 | 120 |
126 for (var dep in package.dependencies) { | 121 for (var dep in package.dependencies) { |
127 _buffer.writeln( | 122 _buffer.writeln( |
128 " - ${log.bold(dep.name)} ${log.gray(dep.constraint)}"); | 123 " - ${log.bold(dep.name)} ${log.gray(dep.constraint)}"); |
129 } | 124 } |
130 } | 125 } |
131 } | 126 } |
132 | 127 |
133 /// Generates a dependency tree for the root package. | 128 /// Generates a dependency tree for the root package. |
134 /// | 129 /// |
135 /// If a package is encountered more than once (i.e. a shared or circular | 130 /// If a package is encountered more than once (i.e. a shared or circular |
136 /// dependency), later ones are not traversed. This is done in breadth-first | 131 /// dependency), later ones are not traversed. This is done in breadth-first |
137 /// fashion so that a package will always be expanded at the shallowest | 132 /// fashion so that a package will always be expanded at the shallowest |
138 /// depth that it appears at. | 133 /// depth that it appears at. |
139 void _outputTree() { | 134 void _outputTree() { |
140 // The work list for the breadth-first traversal. It contains the package | 135 // The work list for the breadth-first traversal. It contains the package |
141 // being added to the tree, and the parent map that will receive that | 136 // being added to the tree, and the parent map that will receive that |
142 // package. | 137 // package. |
143 var toWalk = new Queue<Pair<Package, Map>>(); | 138 var toWalk = new Queue<Pair<Package, Map>>(); |
144 var visited = new Set<String>(); | 139 var visited = new Set<String>(); |
145 | 140 |
146 // Start with the root dependencies. | 141 // Start with the root dependencies. |
147 var packageTree = {}; | 142 var packageTree = {}; |
148 for (var dep in entrypoint.root.immediateDependencies) { | 143 for (var dep in entrypoint.root.immediateDependencies) { |
149 toWalk.add(new Pair(_graph.packages[dep.name], packageTree)); | 144 toWalk.add( |
| 145 new Pair(entrypoint.packageGraph.packages[dep.name], packageTree)); |
150 } | 146 } |
151 | 147 |
152 // Do a breadth-first walk to the dependency graph. | 148 // Do a breadth-first walk to the dependency graph. |
153 while (toWalk.isNotEmpty) { | 149 while (toWalk.isNotEmpty) { |
154 var pair = toWalk.removeFirst(); | 150 var pair = toWalk.removeFirst(); |
155 var package = pair.first; | 151 var package = pair.first; |
156 var map = pair.last; | 152 var map = pair.last; |
157 | 153 |
158 if (visited.contains(package.name)) { | 154 if (visited.contains(package.name)) { |
159 map[log.gray('${package.name}...')] = {}; | 155 map[log.gray('${package.name}...')] = {}; |
160 continue; | 156 continue; |
161 } | 157 } |
162 | 158 |
163 visited.add(package.name); | 159 visited.add(package.name); |
164 | 160 |
165 // Populate the map with this package's dependencies. | 161 // Populate the map with this package's dependencies. |
166 var childMap = {}; | 162 var childMap = {}; |
167 map[_labelPackage(package)] = childMap; | 163 map[_labelPackage(package)] = childMap; |
168 | 164 |
169 for (var dep in package.dependencies) { | 165 for (var dep in package.dependencies) { |
170 toWalk.add(new Pair(_graph.packages[dep.name], childMap)); | 166 toWalk.add( |
| 167 new Pair(entrypoint.packageGraph.packages[dep.name], childMap)); |
171 } | 168 } |
172 } | 169 } |
173 | 170 |
174 _buffer.write(tree.fromMap(packageTree, showAllChildren: true)); | 171 _buffer.write(tree.fromMap(packageTree, showAllChildren: true)); |
175 } | 172 } |
176 | 173 |
177 String _labelPackage(Package package) => | 174 String _labelPackage(Package package) => |
178 "${log.bold(package.name)} ${package.version}"; | 175 "${log.bold(package.name)} ${package.version}"; |
179 | 176 |
180 /// Gets the names of the non-immediate dependencies of the root package. | 177 /// Gets the names of the non-immediate dependencies of the root package. |
181 Set<String> _getTransitiveDependencies() { | 178 Set<String> _getTransitiveDependencies() { |
182 var transitive = _graph.packages.keys.toSet(); | 179 var transitive = entrypoint.packageGraph.packages.keys.toSet(); |
183 var root = entrypoint.root; | 180 var root = entrypoint.root; |
184 transitive.remove(root.name); | 181 transitive.remove(root.name); |
185 transitive.removeAll(root.dependencies.map((dep) => dep.name)); | 182 transitive.removeAll(root.dependencies.map((dep) => dep.name)); |
186 transitive.removeAll(root.devDependencies.map((dep) => dep.name)); | 183 transitive.removeAll(root.devDependencies.map((dep) => dep.name)); |
187 transitive.removeAll(root.dependencyOverrides.map((dep) => dep.name)); | 184 transitive.removeAll(root.dependencyOverrides.map((dep) => dep.name)); |
188 return transitive; | 185 return transitive; |
189 } | 186 } |
190 } | 187 } |
OLD | NEW |