| 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 |