diff --git a/README.md b/README.md index e0e07d8a3..b2c26c1c3 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,8 @@ the notes of version [0.8.2](https://github.com/jrudolph/sbt-dependency-graph/tr * `dependencyTree`: Shows an ASCII tree representation of the project's dependencies * `dependencyBrowseGraph`: Opens a browser window with a visualization of the dependency graph (courtesy of graphlib-dot + dagre-d3). * `dependencyList`: Shows a flat list of all transitive dependencies on the sbt console (sorted by organization and name) - * `whatDependsOn `: Find out what depends on an artifact. Shows a reverse dependency - tree for the selected module. + * `whatDependsOn ?`: Find out what depends on an artifact. Shows a reverse dependency + tree for the selected module. The `` argument is optional. * `dependencyLicenseInfo`: show dependencies grouped by declared license * `dependencyStats`: Shows a table with each module a row with (transitive) Jar sizes and number of dependencies * `dependencyGraphMl`: Generates a `.graphml` file with the project's dependencies to `target/dependencies-.graphml`. diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index ef19a0a6d..fbc6ae440 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -93,7 +93,7 @@ trait DependencyGraphKeys { // internal private[graph] val moduleGraphStore = TaskKey[ModuleGraph]("module-graph-store", "The stored module-graph from the last run") - private[graph] val whatDependsOn = InputKey[Unit]("what-depends-on", "Shows information about what depends on the given module") + val whatDependsOn = InputKey[String]("what-depends-on", "Shows information about what depends on the given module") private[graph] val crossProjectId = SettingKey[ModuleID]("dependency-graph-cross-project-id") } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index 3a49fa5a6..02c7d3ad1 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -92,8 +92,22 @@ object DependencyGraphSettings { """%s
%s
%s""".format(organisation, name, version) }, whatDependsOn := { - val module = artifactIdParser.parsed - streams.value.log.info(rendering.AsciiTree.asciiTree(GraphTransformations.reverseGraphStartingAt(moduleGraph.value, module))) + val ArtifactPattern(org, name, versionFilter) = artifactPatternParser.parsed + val graph = moduleGraph.value + val modules = + versionFilter match { + case Some(version) ⇒ ModuleId(org, name, version) :: Nil + case None ⇒ graph.nodes.filter(m ⇒ m.id.organisation == org && m.id.name == name).map(_.id) + } + val output = + modules + .map { module ⇒ + rendering.AsciiTree.asciiTree(GraphTransformations.reverseGraphStartingAt(graph, module)) + } + .mkString("\n") + + streams.value.log.info(output) + output }, licenseInfo := showLicenseInfo(moduleGraph.value, streams.value)) ++ AsciiGraph.asciiGraphSetttings) @@ -159,20 +173,31 @@ object DependencyGraphSettings { (Space ~> token("--force")).?.map(_.isDefined) } - val artifactIdParser: Def.Initialize[State ⇒ Parser[ModuleId]] = + case class ArtifactPattern( + organisation: String, + name: String, + version: Option[String]) + + val artifactPatternParser: Def.Initialize[State ⇒ Parser[ArtifactPattern]] = resolvedScoped { ctx ⇒ (state: State) ⇒ val graph = loadFromContext(moduleGraphStore, ctx, state) getOrElse ModuleGraph(Nil, Nil) import sbt.complete.DefaultParsers._ - graph.nodes.map(_.id).map { - case id @ ModuleId(org, name, version) ⇒ - (Space ~ token(org) ~ token(Space ~ name) ~ token(Space ~ version)).map(_ ⇒ id) - }.reduceOption(_ | _).getOrElse { - (Space ~> token(StringBasic, "organization") ~ Space ~ token(StringBasic, "module") ~ Space ~ token(StringBasic, "version")).map { - case ((((org, _), mod), _), version) ⇒ - ModuleId(org, mod, version) + graph.nodes + .map(_.id) + .groupBy(m ⇒ (m.organisation, m.name)) + .map { + case ((org, name), modules) ⇒ + val versionParsers: Seq[Parser[Option[String]]] = + modules.map { id ⇒ + token(Space ~> id.version).? + } + + (Space ~> token(org) ~ token(Space ~> name) ~ oneOf(versionParsers)).map { + case ((org, name), version) ⇒ ArtifactPattern(org, name, version) + } } - } + .reduceOption(_ | _).getOrElse(failure("No dependencies found")) } // This is to support 0.13.8's InlineConfigurationWithExcludes while not forcing 0.13.8 diff --git a/src/sbt-test/sbt-dependency-graph/whatDependsOn/build.sbt b/src/sbt-test/sbt-dependency-graph/whatDependsOn/build.sbt new file mode 100644 index 000000000..19c9108a1 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/whatDependsOn/build.sbt @@ -0,0 +1,52 @@ +version := "0.1.0-SNAPSHOT" + +scalaVersion := "2.9.1" + +resolvers += "typesafe maven" at "https://repo.typesafe.com/typesafe/maven-releases/" + +libraryDependencies ++= Seq( + "com.codahale" % "jerkson_2.9.1" % "0.5.0", + "org.codehaus.jackson" % "jackson-mapper-asl" % "1.9.10" // as another version of asl +) + +val check = TaskKey[Unit]("check") + +check := { + def sanitize(str: String): String = str.split('\n').map(_.trim).mkString("\n") + def checkOutput(output: String, expected: String): Unit = + require(sanitize(expected) == sanitize(output), s"Tree should have been [\n${sanitize(expected)}\n] but was [\n${sanitize(output)}\n]") + + val withVersion = + (whatDependsOn in Compile) + .toTask(" org.codehaus.jackson jackson-core-asl 1.9.11") + .value + val expectedGraphWithVersion = + """org.codehaus.jackson:jackson-core-asl:1.9.11 + | +-com.codahale:jerkson_2.9.1:0.5.0 [S] + | | +-default:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] + | | + | +-org.codehaus.jackson:jackson-mapper-asl:1.9.11 + | +-com.codahale:jerkson_2.9.1:0.5.0 [S] + | | +-default:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] + | | + | +-default:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] + | """.stripMargin + + checkOutput(withVersion, expectedGraphWithVersion) + + val withoutVersion = + (whatDependsOn in Compile) + .toTask(" org.codehaus.jackson jackson-mapper-asl") + .value + val expectedGraphWithoutVersion = + """org.codehaus.jackson:jackson-mapper-asl:1.9.11 + | +-com.codahale:jerkson_2.9.1:0.5.0 [S] + | | +-default:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] + | | + | +-default:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] + | + |org.codehaus.jackson:jackson-mapper-asl:1.9.10 (evicted by: 1.9.11) + | +-default:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] + | """.stripMargin + checkOutput(withoutVersion, expectedGraphWithoutVersion) +} diff --git a/src/sbt-test/sbt-dependency-graph/whatDependsOn/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/whatDependsOn/project/plugins.sbt new file mode 100644 index 000000000..6fdebb6d6 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/whatDependsOn/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % sys.props("project.version")) diff --git a/src/sbt-test/sbt-dependency-graph/whatDependsOn/test b/src/sbt-test/sbt-dependency-graph/whatDependsOn/test new file mode 100644 index 000000000..961ba2cf3 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/whatDependsOn/test @@ -0,0 +1,3 @@ +# to initialize parser with deps +> compile:moduleGraph +> check \ No newline at end of file