Index: sdk/lib/_internal/pub/lib/src/command/deps.dart |
diff --git a/sdk/lib/_internal/pub/lib/src/command/deps.dart b/sdk/lib/_internal/pub/lib/src/command/deps.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a5e267bbd77a8f5b61202428e066ecae55262b4d |
--- /dev/null |
+++ b/sdk/lib/_internal/pub/lib/src/command/deps.dart |
@@ -0,0 +1,183 @@ |
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+library pub.command.list; |
+ |
+import 'dart:async'; |
+import 'dart:collection'; |
+ |
+import '../ascii_tree.dart' as tree; |
+import '../command.dart'; |
+import '../log.dart' as log; |
+import '../package.dart'; |
+import '../package_graph.dart'; |
+import '../utils.dart'; |
+ |
+/// Handles the `deps` pub command. |
+class DepsCommand extends PubCommand { |
+ String get description => "Print package dependencies."; |
+ List<String> get aliases => const ["dependencies", "tab"]; |
+ String get usage => "pub deps"; |
+ |
+ DepsCommand() { |
+ commandParser.addOption("style", abbr: "s", |
+ help: "How output should be displayed.", |
+ allowed: ["compact", "tree", "list"], |
+ defaultsTo: "tree"); |
+ } |
+ |
+ Future onRun() { |
+ return entrypoint.loadPackageGraph().then((graph) { |
+ var buffer = new StringBuffer(); |
+ |
+ buffer.writeln(_labelPackage(entrypoint.root)); |
+ |
+ switch (commandOptions["style"]) { |
+ case "compact": _outputCompact(graph, buffer); break; |
+ case "list": _outputList(graph, buffer); break; |
+ case "tree": _outputTree(graph, buffer); break; |
+ } |
+ |
+ log.message(buffer); |
+ }); |
+ } |
+ |
+ /// Outputs a list of all of the package's immediate, dev, override, and |
+ /// transitive dependencies. |
+ /// |
+ /// For each dependency listed, *that* package's immediate dependencies are |
+ /// shown. Unlike [_outputList], this prints all of these dependencies on one |
+ /// line. |
+ void _outputCompact(PackageGraph graph, StringBuffer buffer) { |
+ outputPackages(String section, Iterable<String> names) { |
+ if (names.isEmpty) return; |
+ |
+ buffer.writeln(); |
+ buffer.writeln("$section:"); |
+ for (var name in ordered(names)) { |
+ var package = graph.packages[name]; |
+ |
+ buffer.write("- ${_labelPackage(package)}"); |
+ if (package.dependencies.isEmpty) { |
+ buffer.writeln(); |
+ } else { |
+ var depNames = package.dependencies.map((dep) => dep.name); |
+ var depsList = "[${depNames.join(' ')}]"; |
+ buffer.writeln(" ${log.gray(depsList)}"); |
+ } |
+ } |
+ } |
+ |
+ var root = entrypoint.root; |
+ outputPackages("dependencies", root.dependencies.map((dep) => dep.name)); |
+ outputPackages("dev dependencies", |
+ root.devDependencies.map((dep) => dep.name)); |
+ outputPackages("dependency overrides", |
+ root.dependencyOverrides.map((dep) => dep.name)); |
+ |
+ var transitive = _getTransitiveDependencies(graph); |
+ outputPackages("transitive dependencies", transitive); |
+ } |
+ |
+ /// Outputs a list of all of the package's immediate, dev, override, and |
+ /// transitive dependencies. |
+ /// |
+ /// For each dependency listed, *that* package's immediate dependencies are |
+ /// shown. |
+ void _outputList(PackageGraph graph, StringBuffer buffer) { |
+ outputDeps(Iterable<PackageDep> deps) { |
+ for (var dep in deps) { |
+ buffer.writeln(" - ${log.bold(dep.name)} ${log.gray(dep.constraint)}"); |
+ } |
+ } |
+ |
+ outputPackages(Iterable<String> names) { |
+ for (var name in names) { |
+ var package = graph.packages[name]; |
+ buffer.writeln("- ${_labelPackage(package)}"); |
+ |
+ outputDeps(package.dependencies); |
+ } |
+ } |
+ |
+ outputSection(String name, Iterable<String> deps) { |
+ if (deps.isEmpty) return; |
+ |
+ buffer.writeln(); |
+ buffer.writeln("$name:"); |
+ outputPackages(deps); |
+ } |
+ |
+ var root = entrypoint.root; |
+ outputSection("dependencies", |
+ root.dependencies.map((dep) => dep.name)); |
+ outputSection("dev dependencies", |
+ root.devDependencies.map((dep) => dep.name)); |
+ outputSection("dependency overrides", |
+ root.dependencyOverrides.map((dep) => dep.name)); |
+ |
+ var transitive = _getTransitiveDependencies(graph); |
+ if (transitive.isEmpty) return; |
+ |
+ outputSection("transitive dependencies", ordered(transitive)); |
+ } |
+ |
+ /// Generates a dependency tree for the root package. |
+ /// |
+ /// If a package is encountered more than once (i.e. a shared or circular |
+ /// dependency), later ones are not traversed. This is done in breadth-first |
+ /// fashion so that a package will always be expanded at the shallowest |
+ /// depth that it appears at. |
+ void _outputTree(PackageGraph graph, StringBuffer buffer) { |
+ // The work list for the breadth-first traversal. It contains the package |
+ // being added to the tree, and the parent map that will receive that |
+ // package. |
+ var toWalk = new Queue<Pair<Package, Map>>(); |
+ var visited = new Set<String>(); |
+ |
+ // Start with the root dependencies. |
+ var packageTree = {}; |
+ for (var dep in entrypoint.root.immediateDependencies) { |
+ toWalk.add(new Pair(graph.packages[dep.name], packageTree)); |
+ } |
+ |
+ // Do a breadth-first walk to the dependency graph. |
+ while (toWalk.isNotEmpty) { |
+ var pair = toWalk.removeFirst(); |
+ var package = pair.first; |
+ var map = pair.last; |
+ |
+ if (visited.contains(package.name)) { |
+ map[log.gray('${package.name}...')] = {}; |
+ continue; |
+ } |
+ |
+ visited.add(package.name); |
+ |
+ // Populate the map with this package's dependencies. |
+ var childMap = {}; |
+ map[_labelPackage(package)] = childMap; |
+ |
+ for (var dep in package.dependencies) { |
+ toWalk.add(new Pair(graph.packages[dep.name], childMap)); |
+ } |
+ } |
+ |
+ buffer.write(tree.fromMap(packageTree, showAllChildren: true)); |
+ } |
+ |
+ String _labelPackage(Package package) => |
+ "${log.bold(package.name)} ${package.version}"; |
+ |
+ /// Gets the names of the non-immediate dependencies of the root package. |
+ Set<String> _getTransitiveDependencies(PackageGraph graph) { |
+ var transitive = graph.packages.keys.toSet(); |
+ var root = entrypoint.root; |
+ transitive.remove(root.name); |
+ transitive.removeAll(root.dependencies.map((dep) => dep.name)); |
+ transitive.removeAll(root.devDependencies.map((dep) => dep.name)); |
+ transitive.removeAll(root.dependencyOverrides.map((dep) => dep.name)); |
+ return transitive; |
+ } |
+} |