Merge master and adapt solution

A new case class ArtifactPattern was created which models both searching with
and without version.
This commit is contained in:
Johannes Rudolph 2018-07-16 14:59:16 +02:00
commit 6dbcad89d6
No known key found for this signature in database
GPG Key ID: 4D293A24CCD39E19
56 changed files with 705 additions and 646 deletions

5
.travis.yml Normal file
View File

@ -0,0 +1,5 @@
sudo: false
language: scala
jdk: oraclejdk8
script:
- sbt ";^test ;^scripted"

130
CHANGELOG.md Normal file
View File

@ -0,0 +1,130 @@
# Changelog
## Version 0.9.0 (2017-10-25)
This version (finally!) adds support for sbt 1.0. *sbt-dependency-graph* depends on a lot of internals from sbt to do its
work which is why it was quite an effort to do the migration. Thanks [@MasseGuillaume](https://github.com/MasseGuillaume) from Scala Center,
[@2m](https://github.com/2m), and [@xuwei-k](https://github.com/xuwei-k) for helping out with the effort.
The plugin is cross-built for sbt 0.13 (and will continued to be for while). The `dependencyGraph` task is currently not
supported on sbt 1.0. Use `dependencyBrowseGraph`, instead.
## Version 0.8.2 (2016-02-01)
This is a maintenance release [fixing](https://github.com/jrudolph/sbt-dependency-graph/issues/89) `dependencyBrowseGraph`
in the latest Chrome versions. Thanks [@chtefi](https://github.com/chtefi)!
## Version 0.8.1 (2016-01-08)
This is a maintenance release fixing a regression in 0.8.0 and adding two small features.
All changes:
* [#84](https://github.com/jrudolph/sbt-dependency-graph/issues/84): Fix regression of DOT label rendering introduced in 0.8.0.
* [#83](https://github.com/jrudolph/sbt-dependency-graph/issues/83): Added new task `dependencyStats` which prints a
simple table of jar sizes for all your dependencies. Handy if you want to know why your assembled jar gets so big.
* [#85](https://github.com/jrudolph/sbt-dependency-graph/issues/85): Added new task `dependencyList` which prints a
flat, deduplicated list of all the transitive dependencies.
## Version 0.8.0 (2015-11-26)
sbt-dependency-graph is finally an AutoPlugin and can now show the dependency graph in the browser directly.
### New features
- (experimental) open dependency graph directly in the browser with `dependencyBrowseGraph` ([#29](https://github.com/jrudolph/sbt-dependency-graph/issues/29))
![dependencyBrowseGraph in action](https://gist.githubusercontent.com/jrudolph/941754bcf67a0fafe495/raw/7d80d766feb7af6ba2a69494e1f3ceb1fd40d4da/Screenshot%2520from%25202015-11-26%252014:18:19.png)
- this plugin is finally an sbt AutoPlugin and it is automatically enabled
([#51](https://github.com/jrudolph/sbt-dependency-graph/issues/51))
**Note: To update from 0.7.x remove the `net.virtualvoid.sbt.graph.Plugin.graphSettings` line from your configurations.**
### Other changes
- a new backend was implemented which accesses the in-memory dependency data structures of sbt directly. The plugin doesn't
require accessing the ivy report XML any more (the old backend can still be wired in for comparisons if needed) which
should have solved the race condition and the dreaded `FileNotFoundException` ([#39](https://github.com/jrudolph/sbt-dependency-graph/issues/39))
in multi-module projects. The new backend is only used for sbt >= 0.13.6.
- code was restructured which touched a lot of the classes but didn't change the function or syntax of settings and tasks.
- fixed [#77](https://github.com/jrudolph/sbt-dependency-graph/issues/77)
## Version 0.7.5 (2015-03-30)
This is a maintenance release adding support for sbt 0.13.8.
All changes:
* [#67](https://github.com/jrudolph/sbt-dependency-graph/issues/67): Added support for sbt 0.13.8. Thanks
[@eed3si9n](https://github.com/eed3si9n) for the fix.
* [#37](https://github.com/jrudolph/sbt-dependency-graph/issues/37): Don't fail with StringIndexOutOfBoundsException
for deep trees.
* [#44](https://github.com/jrudolph/sbt-dependency-graph/issues/44): Only match scala lib by org/name.
Thanks [@2beaucoup](https://github.com/2beaucoup) for the fix.
## Version 0.7.4 (2013-06-26)
This is a maintenance release fixing an exception when generating graphs without a terminal [#32](https://github.com/jrudolph/sbt-dependency-graph/issues/32).
## Version 0.7.3 (2013-04-28)
This is a maintenance release. Following issues have been fixed:
* [#27](https://github.com/jrudolph/sbt-dependency-graph/issues/27): A dependency configured with
a version range was not properly associated with its dependant.
* [#30](https://github.com/jrudolph/sbt-dependency-graph/issues/30) & [#31](https://github.com/jrudolph/sbt-dependency-graph/issues/31):
Make it work again with sbt 0.12.3. The path of the dependency resolution file changed in sbt 0.12.3.
Thanks [ebowman](https://github.com/ebowman) for the fix.
## Version 0.7.2 (2013-03-02)
This is a maintenance release. Following issues have been fixed:
* [#27](https://github.com/jrudolph/sbt-dependency-graph/issues/27): A dependency configured with
a version range was not properly associated with its dependant.
## Version 0.7.1
New features in this version:
* `dependency-license-info`: show dependencies grouped by declared license
* `dependency-dot`: create dot file from dependency graph. Contributed by
[berleon](https://github.com/berleon).
## Version 0.7.0 (2012-10-24)
New features in this version:
* `dependency-graph` now renders a real graph. Thanks go to [Matt Russell](https://github.com/mdr/) for
this added awesomeness.
* The tree output from previous versions is now available with `dependency-tree`.
* New task `what-depends-on` showing reverse dependency tree for a selected module (incl. tab-completion for modules)
* Don't fail in cases of a missing dependency. Show errors directly in the output.
* Show info about evicted versions.
* By default, exclude scala-library dependency and append `[S]` to the artifact name instead. Set
`filter-scala-library` to `false` to disable this feature.
* Works with sbt 0.12.1. The ivy report files were moved to a new location making an update necessary.
## Version 0.6.0 (2012-05-23)
New features in this version:
* `dependency-graph` task now prints the dependency graph to the console
(contributed by @gseitz)
* `dependency-graph-ml` contains now the old functionality of `dependency-graph`
which generates a `.graphml` file. Nodes now contain the dependency version as well (contributed by @gseitz).
* The output filename of `dependency-graph-ml` has been changed to include the configuration name. It is now
configurable using the `dependency-graph-ml-file` setting.
* The common `scalaVersion in update` idiom to support Scala 2.9.1 libraries in a
Scala 2.9.2 broke the plugin in 0.5.2, because it wouldn't find the ivy report xml file
any more. This was fixed.
* All tasks are scoped by configuration.
## Version 0.5.2 (2012-02-13)
## Version 0.5.1 (2011-11-18)
## Version 0.5 (2011-11-15)

View File

@ -1,46 +1,47 @@
# sbt-dependency-graph
[![Join the chat at https://gitter.im/jrudolph/sbt-dependency-graph](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jrudolph/sbt-dependency-graph?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Visualize your project's dependencies.
## Preliminaries
The plugin works best with sbt >= 0.13.6. See the [compatibility notes](#compatibility-notes) to use this plugin with an older version of sbt.
## Usage Instructions
Since sbt-dependency-graph is an informational tool rather than one that changes your build, you will more than likely wish to
sbt-dependency-graph is an informational tool rather than one that changes your build, so you will more than likely wish to
install it as a [global plugin] so that you can use it in any SBT project without the need to explicitly add it to each one. To do
this, add the plugin dependency to `~/.sbt/0.13/plugins/plugins.sbt`:
this, add the plugin dependency to `~/.sbt/0.13/plugins/plugins.sbt` for sbt 0.13 or `~/.sbt/1.0/plugins/plugins.sbt` for sbt 1.0:
```scala
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.2")
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.9.0")
```
To add the plugin only to a single project, put this line into `project/plugins.sbt` of your project, instead.
This plugin is an auto-plugin which will be automatically enabled starting from sbt 0.13.5.
The plugin currently supports sbt versions >= 0.13.10 and sbt 1.0.x. For versions supporting older versions of sbt see
the notes of version [0.8.2](https://github.com/jrudolph/sbt-dependency-graph/tree/v0.8.2#compatibility-notes).
## Main Tasks
* `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).
* `dependencyGraph`: Shows an ASCII graph of the project's dependencies on the sbt console
* `dependencyList`: Shows a flat list of all transitive dependencies on the sbt console (sorted by organization and name)
* `whatDependsOn <organization> <module> <revision>`: Find out what depends on an artifact. Shows a reverse dependency
tree for the selected module.
* `whatDependsOn <organization> <module> <revision>?`: Find out what depends on an artifact. Shows a reverse dependency
tree for the selected module. The `<revision>` 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-<config>.graphml`.
Use e.g. [yEd](http://www.yworks.com/en/products_yed_about.html) to format the graph to your needs.
* `dependencyDot`: Generates a .dot file with the project's dependencies to `target/dependencies-<config>.dot`.
Use [graphviz](http://www.graphviz.org/) to render it to your preferred graphic format.
* `ivyReport`: let's ivy generate the resolution report for you project. Use
* `dependencyGraph`: Shows an ASCII graph of the project's dependencies on the sbt console (only supported on sbt 0.13)
* `ivyReport`: Lets ivy generate the resolution report for you project. Use
`show ivyReport` for the filename of the generated report
All tasks can be scoped to a configuration to get the report for a specific configuration. `test:dependencyGraph`,
for example, prints the dependencies in the `test` configuration. If you don't specify any configuration, `compile` is
assumed as usual.
Note: If you want to run tasks with parameters from outside the sbt shell, make sure to put the whole task invocation in quotes, e.g. `sbt "whatDependsOn <org> <module> <version>"`.
## Configuration settings
* `filterScalaLibrary`: Defines if the scala library should be excluded from the output of the dependency-* functions.
@ -64,19 +65,6 @@ dependencyDotFile := file("dependencies.dot") //render dot file to `./dependenci
* [#19]: There's an unfixed bug with graph generation for particular layouts. Workaround:
Use `dependency-tree` instead of `dependency-graph`.
* [#39]: When using sbt-dependency-graph with sbt < 0.13.6.
## Compatibility notes
* sbt < 0.13.6: The plugin will fall back on the old ivy report XML backend which suffers from [#39].
* sbt < 0.13.5: Old versions of sbt have no `AutoPlugin` support, you need to add
```scala
net.virtualvoid.sbt.graph.DependencyGraphSettings.graphSettings
```
to your `build.sbt` or (`~/.sbt/0.13/user.sbt` for global configuration) to enable the plugin.
* sbt <= 0.12.x: Old versions of sbt are not actively supported any more. Please use the old version from the [0.7 branch](https://github.com/jrudolph/sbt-dependency-graph/tree/0.7).
## License
@ -85,4 +73,3 @@ Published under the [Apache License 2.0](http://en.wikipedia.org/wiki/Apache_lic
[global plugin]: http://www.scala-sbt.org/0.13/tutorial/Using-Plugins.html#Global+plugins
[global build configuration]: http://www.scala-sbt.org/0.13/docs/Global-Settings.html
[#19]: https://github.com/jrudolph/sbt-dependency-graph/issues/19
[#39]: https://github.com/jrudolph/sbt-dependency-graph/issues/39

View File

@ -1,28 +1,28 @@
crossBuildingSettings
scriptedLaunchOpts += s"-Dproject.version=${version.value}"
CrossBuilding.crossSbtVersions := Seq("0.13")
CrossBuilding.scriptedSettings
libraryDependencies += "com.github.mdr" %% "ascii-graphs" % "0.0.3"
libraryDependencies <++= scalaVersion { version =>
if (version startsWith "2.1") Seq("org.scala-lang" % "scala-reflect" % version % "provided")
else Nil
libraryDependencies ++= {
if ((sbtVersion in pluginCrossBuild).value startsWith "0.13")
Seq("com.github.mdr" %% "ascii-graphs" % "0.0.3")
else
Nil
}
libraryDependencies <+= scalaVersion { version =>
if (version startsWith "2.9") "org.specs2" % "specs2_2.9.3" % "1.12.4.1" % "test"
else "org.specs2" %% "specs2" % "2.3.11" % "test"
}
scalacOptions ++= Seq("-deprecation", "-unchecked")
libraryDependencies += "org.specs2" %% "specs2-core" % "3.10.0" % Test
sbt.CrossBuilding.latestCompatibleVersionMapper ~= {
original => {
case "0.13" => "0.13.6"
case x => original(x)
}
}
libraryDependencies += Defaults.sbtPluginExtra(
"com.dwijnand" % "sbt-compat" % "1.2.6",
(sbtBinaryVersion in pluginCrossBuild).value,
(scalaBinaryVersion in update).value
)
crossSbtVersions := Seq("1.1.6", "0.13.16")
scalacOptions ++= Seq(
"-deprecation",
"-encoding", "UTF-8",
"-feature",
"-unchecked"
)
ScalariformSupport.formatSettings

View File

@ -1,12 +0,0 @@
New features in this version:
* `dependency-graph` task now prints the dependency graph to the console
(contributed by @gseitz)
* `dependency-graph-ml` contains now the old functionality of `dependency-graph`
which generates a `.graphml` file. Nodes now contain the dependency version as well (contributed by @gseitz).
* The output filename of `dependency-graph-ml` has been changed to include the configuration name. It is now
configurable using the `dependency-graph-ml-file` setting.
* The common `scalaVersion in update` idiom to support Scala 2.9.1 libraries in a
Scala 2.9.2 broke the plugin in 0.5.2, because it wouldn't find the ivy report xml file
any more. This was fixed.
* All tasks are scoped by configuration.

View File

@ -1,12 +0,0 @@
New features in this version:
* `dependency-graph` now renders a real graph. Thanks go to [Matt Russell](https://github.com/mdr/) for
this added awesomeness.
* The tree output from previous versions is now available with `dependency-tree`.
* New task `what-depends-on` showing reverse dependency tree for a selected module (incl. tab-completion for modules)
* Don't fail in cases of a missing dependency. Show errors directly in the output.
* Show info about evicted versions.
* By default, exclude scala-library dependency and append `[S]` to the artifact name instead. Set
`filter-scala-library` to `false` to disable this feature.
* Works with sbt 0.12.1. The ivy report files were moved to a new location making an update necessary.

View File

@ -1,5 +0,0 @@
New features in this version:
* `dependency-license-info`: show dependencies grouped by declared license
* `dependency-dot`: create dot file from dependency graph. Contributed by
[berleon](https://github.com/berleon).

View File

@ -1,5 +0,0 @@
This is a maintenance release. Following issues have been fixed:
* [#27](https://github.com/jrudolph/sbt-dependency-graph/issues/27): A dependency configured with
a version range was not properly associated with its dependant.

View File

@ -1,7 +0,0 @@
This is a maintenance release. Following issues have been fixed:
* [#27](https://github.com/jrudolph/sbt-dependency-graph/issues/27): A dependency configured with
a version range was not properly associated with its dependant.
* [#30](https://github.com/jrudolph/sbt-dependency-graph/issues/30) & [#31](https://github.com/jrudolph/sbt-dependency-graph/issues/31):
Make it work again with sbt 0.12.3. The path of the dependency resolution file changed in sbt 0.12.3.
Thanks [ebowman](https://github.com/ebowman) for the fix.

View File

@ -1 +0,0 @@
This is a maintenance release fixing an exception when generating graphs without a terminal [#32](https://github.com/jrudolph/sbt-dependency-graph/issues/32).

View File

@ -1,10 +0,0 @@
This is a maintenance release adding support for sbt 0.13.8.
All changes:
* [#67](https://github.com/jrudolph/sbt-dependency-graph/issues/67): Added support for sbt 0.13.8. Thanks
[@eed3si9n](https://github.com/eed3si9n) for the fix.
* [#37](https://github.com/jrudolph/sbt-dependency-graph/issues/37): Don't fail with StringIndexOutOfBoundsException
for deep trees.
* [#44](https://github.com/jrudolph/sbt-dependency-graph/issues/44): Only match scala lib by org/name.
Thanks [@2beaucoup](https://github.com/2beaucoup) for the fix.

View File

@ -1,20 +0,0 @@
sbt-dependency-graph is finally an AutoPlugin and can now show the dependency graph in the browser directly.
## New features
- (experimental) open dependency graph directly in the browser with `dependencyBrowseGraph` ([#29](https://github.com/jrudolph/sbt-dependency-graph/issues/29))
![dependencyBrowseGraph in action](https://gist.githubusercontent.com/jrudolph/941754bcf67a0fafe495/raw/7d80d766feb7af6ba2a69494e1f3ceb1fd40d4da/Screenshot%2520from%25202015-11-26%252014:18:19.png)
- this plugin is finally an sbt AutoPlugin and it is automatically enabled
([#51](https://github.com/jrudolph/sbt-dependency-graph/issues/51))
**Note: To update from 0.7.x remove the `net.virtualvoid.sbt.graph.Plugin.graphSettings` line from your configurations.**
## Other changes
- a new backend was implemented which accesses the in-memory dependency data structures of sbt directly. The plugin doesn't
require accessing the ivy report XML any more (the old backend can still be wired in for comparisons if needed) which
should have solved the race condition and the dreaded `FileNotFoundException` ([#39](https://github.com/jrudolph/sbt-dependency-graph/issues/39))
in multi-module projects. The new backend is only used for sbt >= 0.13.6.
- code was restructured which touched a lot of the classes but didn't change the function or syntax of settings and tasks.
- fixed [#77](https://github.com/jrudolph/sbt-dependency-graph/issues/77)

View File

@ -1,9 +0,0 @@
This is a maintenance release fixing a regression in 0.8.0 and adding two small features.
All changes:
* [#84](https://github.com/jrudolph/sbt-dependency-graph/issues/84): Fix regression of DOT label rendering introduced in 0.8.0.
* [#83](https://github.com/jrudolph/sbt-dependency-graph/issues/83): Added new task `dependencyStats` which prints a
simple table of jar sizes for all your dependencies. Handy if you want to know why your assembled jar gets so big.
* [#85](https://github.com/jrudolph/sbt-dependency-graph/issues/85): Added new task `dependencyList` which prints a
flat, deduplicated list of all the transitive dependencies.

View File

@ -1,2 +0,0 @@
This is a maintenance release [fixing](https://github.com/jrudolph/sbt-dependency-graph/issues/89) `dependencyBrowseGraph`
in the latest Chrome versions. Thanks [@chtefi](https://github.com/chtefi)!

View File

@ -1 +0,0 @@
[sbt-dependency-graph](https://github.com/jrudolph/sbt-dependency-graph/) is an sbt plugin to visualize dependencies of your build.

View File

@ -4,8 +4,6 @@ name := "sbt-dependency-graph"
organization := "net.virtual-void"
version := "0.8.3-SNAPSHOT"
homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph"))
licenses in GlobalScope += "Apache License 2.0" -> url("https://github.com/jrudolph/sbt-dependency-graph/raw/master/LICENSE")

View File

@ -1,16 +0,0 @@
import java.net.URL
object Helpers {
def generatePomExtra(scmUrl: String, scmConnection: String,
developerId: String, developerName: String): xml.NodeSeq =
<scm>
<url>{ scmUrl }</url>
<connection>{ scmConnection }</connection>
</scm>
<developers>
<developer>
<id>{ developerId }</id>
<name>{ developerName }</name>
</developer>
</developers>
}

View File

@ -1 +1 @@
sbt.version=0.13.8
sbt.version=1.1.6

View File

@ -1 +1 @@
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.0")

View File

@ -1,3 +1,4 @@
addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.8.1")
libraryDependencies += "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value
addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.2.1")
addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.8.2")
addSbtPlugin("com.dwijnand" % "sbt-dynver" % "2.0.0")

View File

@ -1,7 +1,9 @@
publishTo <<= version { v: String =>
publishTo := {
val nexus = "https://oss.sonatype.org/"
if (v.trim.endsWith("SNAPSHOT")) Some("snapshots" at nexus + "content/repositories/snapshots")
else Some("releases" at nexus + "service/local/staging/deploy/maven2")
Some {
if (version.value.trim.contains("+")) "snapshots" at nexus + "content/repositories/snapshots"
else "releases" at nexus + "service/local/staging/deploy/maven2"
}
}
publishMavenStyle := true
@ -10,9 +12,20 @@ publishArtifact in Test := false
pomIncludeRepository := { _ => false }
pomExtra :=
Helpers.generatePomExtra("git@github.com:jrudolph/sbt-dependency-graph.git",
"scm:git:git@github.com:jrudolph/sbt-dependency-graph.git",
"jrudolph", "Johannes Rudolph")
scmInfo := Some(
ScmInfo(
browseUrl = url("https://github.com/jrudolph/sbt-dependency-graph"),
connection = "scm:git:git@github.com:jrudolph/sbt-dependency-graph.git"
)
)
developers := List(
Developer(
"jrudolph",
"Johannes Rudolph",
"johannes.rudolph@gmail.com",
url("https://virtual-void.net")
)
)
useGpg := true

View File

@ -1,18 +0,0 @@
{
"organization":"net.virtualvoid",
"name":"sbt-dependency-graph",
"version":"0.5.1",
"description":"An sbt plugin which allows to create a graphml file from the dependencies of the project.",
"site":"http://github.com/jrudolph/sbt-dependency-graph",
"tags":["dependency","graph","sbt-plugin","sbt"],
"docs":"http://github.com/jrudolph/sbt-dependency-graph",
"licenses": [{
"name": "Apache License 2.0",
"url": "https://github.com/jrudolph/sbt-dependency-graph/raw/master/LICENSE"
}],
"resolvers": ["http://scala-tools.org/repo-releases"],
"dependencies": [],
"scalas": ["2.9.1"],
"sbt": true
}

View File

@ -1,18 +0,0 @@
{
"organization":"net.virtual-void",
"name":"sbt-dependency-graph",
"version":"0.5.2",
"description":"An sbt plugin which allows to create a graphml file from the dependencies of the project.",
"site":"http://github.com/jrudolph/sbt-dependency-graph",
"tags":["dependency","graph","sbt-plugin","sbt"],
"docs":"http://github.com/jrudolph/sbt-dependency-graph",
"licenses": [{
"name": "Apache License 2.0",
"url": "https://github.com/jrudolph/sbt-dependency-graph/raw/master/LICENSE"
}],
"resolvers": ["http://scala-tools.org/repo-releases"],
"dependencies": [],
"scalas": ["2.9.1"],
"sbt": true
}

View File

@ -1,17 +0,0 @@
{
"organization":"net.virtual-void",
"name":"sbt-dependency-graph",
"version":"0.6.0",
"description":"An sbt plugin to visualize dependencies of your build.",
"site":"http://github.com/jrudolph/sbt-dependency-graph",
"tags":["dependency","graph","sbt-plugin","sbt"],
"docs":"http://github.com/jrudolph/sbt-dependency-graph",
"licenses": [{
"name": "Apache License 2.0",
"url": "https://github.com/jrudolph/sbt-dependency-graph/raw/master/LICENSE"
}],
"resolvers": ["https://oss.sonatype.org/content/repositories/releases"],
"dependencies": [],
"scalas": ["2.9.1"],
"sbt": true
}

View File

@ -1,29 +0,0 @@
{
"organization" : "net.virtual-void",
"name" : "sbt-dependency-graph",
"version" : "0.7.0",
"description" : "An sbt plugin to visualize dependencies of your build.",
"site" : "http://github.com/jrudolph/sbt-dependency-graph",
"tags" : [ "dependency", "graph", "sbt-plugin", "sbt" ],
"docs" : "http://github.com/jrudolph/sbt-dependency-graph",
"resolvers" : [ "https://oss.sonatype.org/content/repositories/releases" ],
"dependencies" : [ {
"organization" : "org.scala-sbt",
"name" : "scripted-sbt",
"version" : "0.12.0"
}, {
"organization" : "org.scala-sbt",
"name" : "sbt-launch",
"version" : "0.12.0"
}, {
"organization" : "com.github.mdr",
"name" : "ascii-graphs",
"version" : "0.0.2"
} ],
"scalas" : [ "2.9.2" ],
"licenses" : [ {
"name" : "Apache License 2.0",
"url" : "https://github.com/jrudolph/sbt-dependency-graph/raw/master/LICENSE"
} ],
"sbt" : true
}

View File

@ -1,29 +0,0 @@
{
"organization" : "net.virtual-void",
"name" : "sbt-dependency-graph",
"version" : "0.7.1",
"description" : "An sbt plugin to visualize dependencies of your build.",
"site" : "http://github.com/jrudolph/sbt-dependency-graph",
"tags" : [ "dependency", "graph", "sbt-plugin", "sbt" ],
"docs" : "http://github.com/jrudolph/sbt-dependency-graph",
"resolvers" : [ "https://oss.sonatype.org/content/repositories/releases" ],
"dependencies" : [ {
"organization" : "org.scala-sbt",
"name" : "scripted-sbt",
"version" : "0.12.0"
}, {
"organization" : "org.scala-sbt",
"name" : "sbt-launch",
"version" : "0.12.0"
}, {
"organization" : "com.github.mdr",
"name" : "ascii-graphs",
"version" : "0.0.2"
} ],
"scalas" : [ "2.9.2" ],
"licenses" : [ {
"name" : "Apache License 2.0",
"url" : "https://github.com/jrudolph/sbt-dependency-graph/raw/master/LICENSE"
} ],
"sbt" : true
}

View File

@ -1,29 +0,0 @@
{
"organization" : "net.virtual-void",
"name" : "sbt-dependency-graph",
"version" : "0.7.2",
"description" : "An sbt plugin to visualize dependencies of your build.",
"site" : "http://github.com/jrudolph/sbt-dependency-graph",
"tags" : [ "dependency", "graph", "sbt-plugin", "sbt" ],
"docs" : "http://github.com/jrudolph/sbt-dependency-graph",
"resolvers" : [ "https://oss.sonatype.org/content/repositories/releases" ],
"dependencies" : [ {
"organization" : "org.scala-sbt",
"name" : "scripted-sbt",
"version" : "0.12.1"
}, {
"organization" : "org.scala-sbt",
"name" : "sbt-launch",
"version" : "0.12.1"
}, {
"organization" : "com.github.mdr",
"name" : "ascii-graphs",
"version" : "0.0.2"
} ],
"scalas" : [ "2.9.2" ],
"licenses" : [ {
"name" : "Apache License 2.0",
"url" : "https://github.com/jrudolph/sbt-dependency-graph/raw/master/LICENSE"
} ],
"sbt" : true
}

View File

@ -1,29 +0,0 @@
{
"organization" : "net.virtual-void",
"name" : "sbt-dependency-graph",
"version" : "0.7.3",
"description" : "An sbt plugin to visualize dependencies of your build.",
"site" : "http://github.com/jrudolph/sbt-dependency-graph",
"tags" : [ "dependency", "graph", "sbt-plugin", "sbt" ],
"docs" : "http://github.com/jrudolph/sbt-dependency-graph",
"resolvers" : [ "https://oss.sonatype.org/content/repositories/releases" ],
"dependencies" : [ {
"organization" : "org.scala-sbt",
"name" : "scripted-sbt",
"version" : "0.12.1"
}, {
"organization" : "org.scala-sbt",
"name" : "sbt-launch",
"version" : "0.12.1"
}, {
"organization" : "com.github.mdr",
"name" : "ascii-graphs",
"version" : "0.0.2"
} ],
"scalas" : [ "2.9.2" ],
"licenses" : [ {
"name" : "Apache License 2.0",
"url" : "https://github.com/jrudolph/sbt-dependency-graph/raw/master/LICENSE"
} ],
"sbt" : true
}

View File

@ -1,29 +0,0 @@
{
"organization" : "net.virtual-void",
"name" : "sbt-dependency-graph",
"version" : "0.7.4",
"description" : "An sbt plugin to visualize dependencies of your build.",
"site" : "http://github.com/jrudolph/sbt-dependency-graph",
"tags" : [ "dependency", "graph", "sbt-plugin", "sbt" ],
"docs" : "http://github.com/jrudolph/sbt-dependency-graph",
"resolvers" : [ "https://oss.sonatype.org/content/repositories/releases" ],
"dependencies" : [ {
"organization" : "org.scala-sbt",
"name" : "scripted-sbt",
"version" : "0.12.1"
}, {
"organization" : "org.scala-sbt",
"name" : "sbt-launch",
"version" : "0.12.1"
}, {
"organization" : "com.github.mdr",
"name" : "ascii-graphs",
"version" : "0.0.2"
} ],
"scalas" : [ "2.9.2" ],
"licenses" : [ {
"name" : "Apache License 2.0",
"url" : "https://github.com/jrudolph/sbt-dependency-graph/raw/master/LICENSE"
} ],
"sbt" : true
}

View File

@ -0,0 +1,3 @@
package net.virtualvoid.sbt.graph
trait ModuleGraphProtocolCompat

View File

@ -18,6 +18,8 @@ package net.virtualvoid.sbt.graph
package rendering
import com.github.mdr.ascii.layout._
import net.virtualvoid.sbt.graph.DependencyGraphKeys._
import sbt.Keys._
object AsciiGraph {
def asciiGraph(graph: ModuleGraph): String =
@ -35,4 +37,23 @@ object AsciiGraph {
val edges = moduleGraph.edges.toList.map { case (from, to) (renderVertex(moduleGraph.module(from)), renderVertex(moduleGraph.module(to))) }
Graph(vertices, edges)
}
def asciiGraphSetttings = Seq[sbt.Def.Setting[_]](
DependencyGraphKeys.asciiGraph := asciiGraph(moduleGraph.value),
dependencyGraph := {
val force = DependencyGraphSettings.shouldForceParser.parsed
val log = streams.value.log
if (force || moduleGraph.value.nodes.size < 15) {
log.info(rendering.AsciiGraph.asciiGraph(moduleGraph.value))
log.info("\n\n")
log.info("Note: The old tree layout is still available by using `dependency-tree`")
}
log.info(rendering.AsciiTree.asciiTree(moduleGraph.value))
if (!force) {
log.info("\n")
log.info("Note: The graph was estimated to be too big to display (> 15 nodes). Use `sbt 'dependency-graph --force'` (with the single quotes) to force graph display.")
}
})
}

View File

@ -0,0 +1,81 @@
package sbt
package dependencygraph
import scala.language.implicitConversions
import java.util.concurrent.TimeUnit
import Keys._
import Def.Initialize
import CrossVersion._
import scala.concurrent.duration.FiniteDuration
object DependencyGraphSbtCompat {
object Implicits {
implicit def convertConfig(config: sbt.Configuration): String = config.toString
implicit class RichUpdateConfiguration(val updateConfig: UpdateConfiguration) extends AnyVal {
def withMissingOk(missingOk: Boolean): UpdateConfiguration =
updateConfig.copy(missingOk = missingOk)
}
}
/**
* This is copied directly from https://github.com/sbt/sbt/blob/2952a2b9b672c5402b824ad2d2076243eb643598/main/src/main/scala/sbt/Defaults.scala#L1471-L1523
* and then changed to update the UpdateConfiguration to ignore missing artifacts.
*/
def updateTask(task: TaskKey[_]): Initialize[Task[UpdateReport]] = Def.task {
val depsUpdated = transitiveUpdate.value.exists(!_.stats.cached)
val isRoot = executionRoots.value contains resolvedScoped.value
val forceUpdate = forceUpdatePeriod.value
val s = streams.value
val fullUpdateOutput = s.cacheDirectory / "out"
val forceUpdateByTime = forceUpdate match {
case None false
case Some(period)
val elapsedDuration = new FiniteDuration(System.currentTimeMillis() - fullUpdateOutput.lastModified(), TimeUnit.MILLISECONDS)
fullUpdateOutput.exists() && elapsedDuration > period
}
val scalaProvider = appConfiguration.value.provider.scalaProvider
// Only substitute unmanaged jars for managed jars when the major.minor parts of the versions the same for:
// the resolved Scala version and the scalaHome version: compatible (weakly- no qualifier checked)
// the resolved Scala version and the declared scalaVersion: assume the user intended scalaHome to override anything with scalaVersion
def subUnmanaged(subVersion: String, jars: Seq[File]) = (sv: String)
(partialVersion(sv), partialVersion(subVersion), partialVersion(scalaVersion.value)) match {
case (Some(res), Some(sh), _) if res == sh jars
case (Some(res), _, Some(decl)) if res == decl jars
case _ Nil
}
val subScalaJars: String Seq[File] = Defaults.unmanagedScalaInstanceOnly.value match {
case Some(si) subUnmanaged(si.version, si.jars)
case None sv if (scalaProvider.version == sv) scalaProvider.jars else Nil
}
val transform: UpdateReport UpdateReport = r sbt.Classpaths.substituteScalaFiles(scalaOrganization.value, r)(subScalaJars)
val uwConfig = (unresolvedWarningConfiguration in update).value
val show = Reference.display(thisProjectRef.value)
val st = state.value
val logicalClock = LogicalClock(st.hashCode)
val depDir = dependencyCacheDirectory.value
val uc0 = (updateConfiguration in task).value
val ms = publishMavenStyle.value
val cw = compatibilityWarningOptions.value
// Normally, log would capture log messages at all levels.
// Ivy logs are treated specially using sbt.UpdateConfiguration.logging.
// This code bumps up the sbt.UpdateConfiguration.logging to Full when logLevel is Debug.
import UpdateLogging.{ Full, DownloadOnly, Default }
val uc = (logLevel in update).?.value orElse st.get(logLevel.key) match {
case Some(Level.Debug) if uc0.logging == Default uc0.copy(logging = Full)
case Some(x) if uc0.logging == Default uc0.copy(logging = DownloadOnly)
case _ uc0
}
val ewo =
if (executionRoots.value exists { _.key == evicted.key }) EvictionWarningOptions.empty
else (evictionWarningOptions in update).value
sbt.Classpaths.cachedUpdate(s.cacheDirectory / updateCacheName.value, show, ivyModule.value, uc, transform,
skip = (skip in update).value, force = isRoot || forceUpdateByTime, depsUpdated = depsUpdated,
uwConfig = uwConfig, logicalClock = logicalClock, depDir = Some(depDir),
ewo = ewo, mavenStyle = ms, compatWarning = cw, log = s.log)
}
}

View File

@ -0,0 +1,25 @@
package net.virtualvoid.sbt.graph
import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, File }
import java.util.Base64
import sbinary.{ Format, JavaInput, JavaOutput }
import sjsonnew.{ Builder, Unbuilder }
trait ModuleGraphProtocolCompat {
implicit def sjsonNewAndShinyTransformAndTranspileAdapterFactoryModuleImplementation[T](implicit format: Format[T]): sjsonnew.JsonFormat[T] =
new sjsonnew.JsonFormat[T] {
// note, how this is simpler to write than to learn any sjonnew protocol syntax
def write[J](obj: T, builder: Builder[J]): Unit = {
val baos = new ByteArrayOutputStream()
format.writes(new JavaOutput(baos), obj)
val str = Base64.getEncoder.encodeToString(baos.toByteArray)
builder.writeString(str)
}
def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): T = {
val str = unbuilder.readString(jsOpt.get)
val bais = new ByteArrayInputStream(Base64.getDecoder.decode(str))
format.reads(new JavaInput(bais))
}
}
}

View File

@ -0,0 +1,22 @@
/*
* Copyright 2017 Johannes Rudolph
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.virtualvoid.sbt.graph
package rendering
object AsciiGraph {
def asciiGraphSetttings = Seq.empty[sbt.Def.Setting[_]]
}

View File

@ -0,0 +1,63 @@
package sbt
package dependencygraph
import Keys._
import Def.Initialize
import CrossVersion.partialVersion
import sbt.internal.LibraryManagement
object DependencyGraphSbtCompat {
object Implicits
// https://github.com/sbt/sbt/blob/4ce4fb72bde3b8acfaf526b79d32ca1463bc687b/main/src/main/scala/sbt/Defaults.scala#L2298 adapted
// to allow customization of UpdateConfiguration
def updateTask(task: TaskKey[_]): Initialize[Task[UpdateReport]] = Def.task {
val depsUpdated = transitiveUpdate.value.exists(!_.stats.cached)
val isRoot = executionRoots.value contains resolvedScoped.value
val s = streams.value
val scalaProvider = appConfiguration.value.provider.scalaProvider
// Only substitute unmanaged jars for managed jars when the major.minor parts of the versions the same for:
// the resolved Scala version and the scalaHome version: compatible (weakly- no qualifier checked)
// the resolved Scala version and the declared scalaVersion: assume the user intended scalaHome to override anything with scalaVersion
def subUnmanaged(subVersion: String, jars: Seq[File]) = (sv: String)
(partialVersion(sv), partialVersion(subVersion), partialVersion(scalaVersion.value)) match {
case (Some(res), Some(sh), _) if res == sh jars
case (Some(res), _, Some(decl)) if res == decl jars
case _ Nil
}
val subScalaJars: String Seq[File] = SbtAccess.unmanagedScalaInstanceOnly.value match {
case Some(si) subUnmanaged(si.version, si.allJars)
case None sv if (scalaProvider.version == sv) scalaProvider.jars else Nil
}
val transform: UpdateReport UpdateReport =
r Classpaths.substituteScalaFiles(scalaOrganization.value, r)(subScalaJars)
val evictionOptions = Def.taskDyn {
if (executionRoots.value.exists(_.key == evicted.key))
Def.task(EvictionWarningOptions.empty)
else Def.task((evictionWarningOptions in update).value)
}.value
LibraryManagement.cachedUpdate(
// LM API
lm = dependencyResolution.value,
// Ivy-free ModuleDescriptor
module = ivyModule.value,
s.cacheStoreFactory.sub(updateCacheName.value),
Reference.display(thisProjectRef.value),
(updateConfiguration in task).value,
transform = transform,
skip = (skip in update).value,
force = isRoot,
depsUpdated = transitiveUpdate.value.exists(!_.stats.cached),
uwConfig = (unresolvedWarningConfiguration in update).value,
ewo = evictionOptions,
mavenStyle = publishMavenStyle.value,
compatWarning = compatibilityWarningOptions.value,
log = s.log)
}
}

View File

@ -19,53 +19,76 @@ package net.virtualvoid.sbt.graph
import sbt._
trait DependencyGraphKeys {
val dependencyGraphMLFile = SettingKey[File]("dependency-graph-ml-file",
val dependencyGraphMLFile = SettingKey[File](
"dependency-graph-ml-file",
"The location the graphml file should be generated at")
val dependencyGraphML = TaskKey[File]("dependency-graph-ml",
val dependencyGraphML = TaskKey[File](
"dependency-graph-ml",
"Creates a graphml file containing the dependency-graph for a project")
val dependencyDotFile = SettingKey[File]("dependency-dot-file",
val dependencyDotFile = SettingKey[File](
"dependency-dot-file",
"The location the dot file should be generated at")
val dependencyDotNodeLabel = SettingKey[(String, String, String) String]("dependency-dot-node-label",
val dependencyDotNodeLabel = SettingKey[(String, String, String) String](
"dependency-dot-node-label",
"Returns a formated string of a dependency. Takes organisation, name and version as parameters")
val dependencyDotHeader = SettingKey[String]("dependency-dot-header",
val dependencyDotHeader = SettingKey[String](
"dependency-dot-header",
"The header of the dot file. (e.g. to set your preferred node shapes)")
val dependencyDot = TaskKey[File]("dependency-dot",
val dependencyDot = TaskKey[File](
"dependency-dot",
"Creates a dot file containing the dependency-graph for a project")
val dependencyDotString = TaskKey[String]("dependency-dot-string",
val dependencyDotString = TaskKey[String](
"dependency-dot-string",
"Creates a String containing the dependency-graph for a project in dot format")
val dependencyBrowseGraphTarget = SettingKey[File]("dependency-browse-graph-target",
val dependencyBrowseGraphTarget = SettingKey[File](
"dependency-browse-graph-target",
"The location dependency browse graph files should be put.")
val dependencyBrowseGraphHTML = TaskKey[URI]("dependency-browse-graph-html",
val dependencyBrowseGraphHTML = TaskKey[URI](
"dependency-browse-graph-html",
"Creates an HTML page that can be used to view the graph.")
val dependencyBrowseGraph = TaskKey[URI]("dependency-browse-graph",
val dependencyBrowseGraph = TaskKey[URI](
"dependency-browse-graph",
"Opens an HTML page that can be used to view the graph.")
val moduleGraph = TaskKey[ModuleGraph]("module-graph",
val moduleGraph = TaskKey[ModuleGraph](
"module-graph",
"The dependency graph for a project")
val moduleGraphIvyReport = TaskKey[ModuleGraph]("module-graph-ivy-report",
val moduleGraphIvyReport = TaskKey[ModuleGraph](
"module-graph-ivy-report",
"The dependency graph for a project as generated from an Ivy Report XML")
val moduleGraphSbt = TaskKey[ModuleGraph]("module-graph-sbt",
val moduleGraphSbt = TaskKey[ModuleGraph](
"module-graph-sbt",
"The dependency graph for a project as generated from SBT data structures.")
val asciiGraph = TaskKey[String]("dependency-graph-string",
val asciiGraph = TaskKey[String](
"dependency-graph-string",
"Returns a string containing the ascii representation of the dependency graph for a project")
val dependencyGraph = InputKey[Unit]("dependency-graph",
val dependencyGraph = InputKey[Unit](
"dependency-graph",
"Prints the ascii graph to the console")
val asciiTree = TaskKey[String]("dependency-tree-string",
val asciiTree = TaskKey[String](
"dependency-tree-string",
"Returns a string containing an ascii tree representation of the dependency graph for a project")
val dependencyTree = TaskKey[Unit]("dependency-tree",
val dependencyTree = TaskKey[Unit](
"dependency-tree",
"Prints an ascii tree of all the dependencies to the console")
val dependencyList = TaskKey[Unit]("dependency-list",
val dependencyList = TaskKey[Unit](
"dependency-list",
"Prints a list of all dependencies to the console")
val dependencyStats = TaskKey[Unit]("dependency-stats",
val dependencyStats = TaskKey[Unit](
"dependency-stats",
"Prints statistics for all dependencies to the console")
val ivyReportFunction = TaskKey[String File]("ivy-report-function",
val ivyReportFunction = TaskKey[String File](
"ivy-report-function",
"A function which returns the file containing the ivy report from the ivy cache for a given configuration")
val ivyReport = TaskKey[File]("ivy-report",
val ivyReport = TaskKey[File](
"ivy-report",
"A task which returns the location of the ivy report file for a given configuration (default `compile`).")
val ignoreMissingUpdate = Keys.update in ivyReport
val filterScalaLibrary = SettingKey[Boolean]("filter-scala-library",
val filterScalaLibrary = SettingKey[Boolean](
"filter-scala-library",
"Specifies if scala dependency should be filtered in dependency-* output")
val licenseInfo = TaskKey[Unit]("dependency-license-info",
val licenseInfo = TaskKey[Unit](
"dependency-license-info",
"Aggregates and shows information about the licenses of dependencies")
// internal

View File

@ -16,157 +16,142 @@
package net.virtualvoid.sbt.graph
import scala.language.reflectiveCalls
import sbt._
import Keys._
import CrossVersion._
import sbt.complete.Parser
import org.apache.ivy.core.resolve.ResolveOptions
import net.virtualvoid.sbt.graph.backend.{ IvyReport, SbtUpdateReport }
import net.virtualvoid.sbt.graph.rendering.DagreHTML
import net.virtualvoid.sbt.graph.rendering.{ AsciiGraph, DagreHTML }
import net.virtualvoid.sbt.graph.util.IOUtil
import internal.librarymanagement._
import librarymanagement._
import sbt.dependencygraph.DependencyGraphSbtCompat
import sbt.dependencygraph.DependencyGraphSbtCompat.Implicits._
object DependencyGraphSettings {
import DependencyGraphKeys._
import ModuleGraphProtocol._
def graphSettings = Seq(
ivyReportFunction <<= ivyReportFunctionTask,
updateConfiguration in ignoreMissingUpdate <<= updateConfiguration(config new UpdateConfiguration(config.retrieve, true, config.logging)),
ignoreMissingUpdateT,
filterScalaLibrary in Global := true) ++ Seq(Compile, Test, IntegrationTest, Runtime, Provided, Optional).flatMap(ivyReportForConfig)
def graphSettings = baseSettings ++ reportSettings
def baseSettings = Seq(
ivyReportFunction := ivyReportFunctionTask.value,
updateConfiguration in ignoreMissingUpdate := updateConfiguration.value.withMissingOk(true),
ignoreMissingUpdate := DependencyGraphSbtCompat.updateTask(ignoreMissingUpdate).value,
filterScalaLibrary in Global := true)
def reportSettings =
Seq(Compile, Test, IntegrationTest, Runtime, Provided, Optional).flatMap(ivyReportForConfig)
def ivyReportForConfig(config: Configuration) = inConfig(config)(Seq(
ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn (ignoreMissingUpdate),
crossProjectId <<= (scalaVersion, scalaBinaryVersion, projectID)((sV, sBV, id) CrossVersion(sV, sBV)(id)),
moduleGraphSbt <<= moduleGraphSbtTask,
moduleGraphIvyReport <<= moduleGraphIvyReportTask,
moduleGraph <<= (sbtVersion, moduleGraphSbt, moduleGraphIvyReport) { (version, graphSbt, graphIvy)
version match {
case Version(0, 13, x, _) if x >= 6 graphSbt
case _ graphIvy
ivyReport := { Def.task { ivyReportFunction.value.apply(config.toString) } dependsOn (ignoreMissingUpdate) }.value,
crossProjectId := sbt.CrossVersion(scalaVersion.value, scalaBinaryVersion.value)(projectID.value),
moduleGraphSbt :=
ignoreMissingUpdate.value.configuration(configuration.value).map(report SbtUpdateReport.fromConfigurationReport(report, crossProjectId.value)).getOrElse(ModuleGraph.empty),
moduleGraphIvyReport := IvyReport.fromReportFile(absoluteReportPath(ivyReport.value)),
moduleGraph := {
sbtVersion.value match {
case Version(0, 13, x, _) if x >= 6 moduleGraphSbt.value
case Version(1, _, _, _) moduleGraphSbt.value
}
},
moduleGraph <<= (scalaVersion, moduleGraph, filterScalaLibrary) map { (scalaV, graph, filter)
if (filter) GraphTransformations.ignoreScalaLibrary(scalaV, graph)
else graph
},
moduleGraphStore <<= moduleGraph storeAs moduleGraphStore triggeredBy moduleGraph,
asciiGraph <<= moduleGraph map rendering.AsciiGraph.asciiGraph,
dependencyGraph <<= InputTask(shouldForceParser) { force
(force, moduleGraph, streams) map { (force, graph, streams)
if (force || graph.nodes.size < 15) {
streams.log.info(rendering.AsciiGraph.asciiGraph(graph))
streams.log.info("\n\n")
streams.log.info("Note: The old tree layout is still available by using `dependency-tree`")
} else {
streams.log.info(rendering.AsciiTree.asciiTree(graph))
moduleGraph := {
// FIXME: remove busywork
val scalaVersion = Keys.scalaVersion.value
val moduleGraph = DependencyGraphKeys.moduleGraph.value
if (!force) {
streams.log.info("\n")
streams.log.info("Note: The graph was estimated to be too big to display (> 15 nodes). Use `sbt 'dependency-graph --force'` (with the single quotes) to force graph display.")
}
}
}
if (filterScalaLibrary.value) GraphTransformations.ignoreScalaLibrary(scalaVersion, moduleGraph)
else moduleGraph
},
asciiTree <<= moduleGraph map rendering.AsciiTree.asciiTree,
dependencyTree <<= print(asciiTree),
dependencyGraphMLFile <<= target / "dependencies-%s.graphml".format(config.toString),
dependencyGraphML <<= dependencyGraphMLTask,
dependencyDotFile <<= target / "dependencies-%s.dot".format(config.toString),
dependencyDotString <<= dependencyDotStringTask,
dependencyDot <<= writeToFile(dependencyDotString, dependencyDotFile),
dependencyBrowseGraphTarget <<= target / "browse-dependency-graph",
dependencyBrowseGraphHTML <<= browseGraphHTMLTask,
dependencyBrowseGraph <<= (dependencyBrowseGraphHTML, streams).map { (uri, streams)
streams.log.info("Opening in browser...")
moduleGraphStore := (moduleGraph storeAs moduleGraphStore triggeredBy moduleGraph).value,
asciiTree := rendering.AsciiTree.asciiTree(moduleGraph.value),
dependencyTree := print(asciiTree).value,
dependencyGraphMLFile := { target.value / "dependencies-%s.graphml".format(config.toString) },
dependencyGraphML := dependencyGraphMLTask.value,
dependencyDotFile := { target.value / "dependencies-%s.dot".format(config.toString) },
dependencyDotString := rendering.DOT.dotGraph(moduleGraph.value, dependencyDotHeader.value, dependencyDotNodeLabel.value, rendering.DOT.AngleBrackets),
dependencyDot := writeToFile(dependencyDotString, dependencyDotFile).value,
dependencyBrowseGraphTarget := { target.value / "browse-dependency-graph" },
dependencyBrowseGraphHTML := browseGraphHTMLTask.value,
dependencyBrowseGraph := {
val uri = dependencyBrowseGraphHTML.value
streams.value.log.info("Opening in browser...")
java.awt.Desktop.getDesktop.browse(uri)
uri
},
dependencyList <<= printFromGraph(rendering.FlatList.render(_, _.id.idString)),
dependencyStats <<= printFromGraph(rendering.Statistics.renderModuleStatsList),
dependencyDotHeader := """digraph "dependency-graph" {
| graph[rankdir="LR"]
| edge [
| arrowtail="none"
| ]""".stripMargin,
dependencyList := printFromGraph(rendering.FlatList.render(_, _.id.idString)).value,
dependencyStats := printFromGraph(rendering.Statistics.renderModuleStatsList).value,
dependencyDotHeader :=
"""|digraph "dependency-graph" {
| graph[rankdir="LR"]
| edge [
| arrowtail="none"
| ]""".stripMargin,
dependencyDotNodeLabel := { (organisation: String, name: String, version: String)
"""%s<BR/><B>%s</B><BR/>%s""".format(organisation, name, version)
},
whatDependsOn <<= InputTask(artifactIdParser) { module
(module, streams, moduleGraph) map { (module, streams, graph)
if (module.version.isEmpty) {
val modules = graph.reverseDependencyMap.filter(m m._1.copy(version = "") == module).keys
modules.foreach(m streams.log.info(rendering.AsciiTree.asciiTree(GraphTransformations.reverseGraphStartingAt(graph, m))))
} else streams.log.info(rendering.AsciiTree.asciiTree(GraphTransformations.reverseGraphStartingAt(graph, module)))
}
whatDependsOn := {
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)
}
modules
.foreach { module
streams.value.log.info(rendering.AsciiTree.asciiTree(GraphTransformations.reverseGraphStartingAt(graph, module)))
}
},
licenseInfo <<= (moduleGraph, streams) map showLicenseInfo))
licenseInfo := showLicenseInfo(moduleGraph.value, streams.value)) ++ AsciiGraph.asciiGraphSetttings)
def ivyReportFunctionTask =
(sbtVersion, target, projectID, ivyModule, appConfiguration, streams) map { (sbtV, target, projectID, ivyModule, config, streams)
sbtV match {
case Version(0, min, fix, _) if min > 12 || (min == 12 && fix >= 3)
(c: String) file("%s/resolution-cache/reports/%s-%s-%s.xml".format(target, projectID.organization, crossName(ivyModule), c))
case Version(0, min, fix, _) if min == 12 && fix >= 1 && fix < 3
ivyModule.withModule(streams.log) { (i, moduleDesc, _)
val id = ResolveOptions.getDefaultResolveId(moduleDesc)
(c: String) file("%s/resolution-cache/reports/%s/%s-resolved.xml" format (target, id, c))
}
case _
val home = config.provider.scalaProvider.launcher.ivyHome
(c: String) file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c))
}
def ivyReportFunctionTask = Def.task {
val crossTarget = Keys.crossTarget.value
val projectID = Keys.projectID.value
val ivyModule = Keys.ivyModule.value
(config: String) {
val org = projectID.organization
val name = crossName(ivyModule)
file(s"${crossTarget}/resolution-cache/reports/$org-$name-$config.xml")
}
def moduleGraphIvyReportTask = ivyReport map (absoluteReportPath.andThen(IvyReport.fromReportFile))
def moduleGraphSbtTask =
(ignoreMissingUpdate, crossProjectId, configuration) map { (update, root, config)
update.configuration(config.name).map(report SbtUpdateReport.fromConfigurationReport(report, root)).getOrElse(ModuleGraph.empty)
}
def printAsciiGraphTask =
(streams, asciiGraph) map (_.log.info(_))
}
def dependencyGraphMLTask =
(moduleGraph, dependencyGraphMLFile, streams) map { (graph, resultFile, streams)
rendering.GraphML.saveAsGraphML(graph, resultFile.getAbsolutePath)
streams.log.info("Wrote dependency graph to '%s'" format resultFile)
Def.task {
val resultFile = dependencyGraphMLFile.value
rendering.GraphML.saveAsGraphML(moduleGraph.value, resultFile.getAbsolutePath)
streams.value.log.info("Wrote dependency graph to '%s'" format resultFile)
resultFile
}
def dependencyDotStringTask =
(moduleGraph, dependencyDotHeader, dependencyDotNodeLabel).map {
(graph, dotHead, nodeLabel) rendering.DOT.dotGraph(graph, dotHead, nodeLabel, rendering.DOT.AngleBrackets)
}
def browseGraphHTMLTask =
(moduleGraph, dependencyDotHeader, dependencyDotNodeLabel, dependencyBrowseGraphTarget, streams).map { (graph, dotHead, nodeLabel, target, streams)
val dotGraph = rendering.DOT.dotGraph(graph, dotHead, nodeLabel, rendering.DOT.LabelTypeHtml)
val link = DagreHTML.createLink(dotGraph, target)
streams.log.info(s"HTML graph written to $link")
Def.task {
val dotGraph = rendering.DOT.dotGraph(moduleGraph.value, dependencyDotHeader.value, dependencyDotNodeLabel.value, rendering.DOT.LabelTypeHtml)
val link = DagreHTML.createLink(dotGraph, target.value)
streams.value.log.info(s"HTML graph written to $link")
link
}
def writeToFile(dataTask: TaskKey[String], fileTask: SettingKey[File]) =
(dataTask, fileTask, streams).map { (data, outFile, streams)
IOUtil.writeToFile(data, outFile)
Def.task {
val outFile = fileTask.value
IOUtil.writeToFile(dataTask.value, outFile)
streams.log.info("Wrote dependency graph to '%s'" format outFile)
streams.value.log.info("Wrote dependency graph to '%s'" format outFile)
outFile
}
def absoluteReportPath = (file: File) file.getAbsolutePath
def print(key: TaskKey[String]) =
(streams, key) map (_.log.info(_))
Def.task { streams.value.log.info(key.value) }
def printFromGraph(f: ModuleGraph String) =
(streams, moduleGraph) map ((streams, graph) streams.log.info(f(graph)))
Def.task { streams.value.log.info(f(moduleGraph.value)) }
def showLicenseInfo(graph: ModuleGraph, streams: TaskStreams) {
def showLicenseInfo(graph: ModuleGraph, streams: TaskStreams): Unit = {
val output =
graph.nodes.filter(_.isUsed).groupBy(_.license).toSeq.sortBy(_._1).map {
case (license, modules)
@ -183,24 +168,32 @@ object DependencyGraphSettings {
(Space ~> token("--force")).?.map(_.isDefined)
}
val artifactIdParser: Initialize[State Parser[ModuleId]] =
resolvedScoped { ctx
(state: State)
val graph = loadFromContext(moduleGraphStore, ctx, state) getOrElse ModuleGraph(Nil, Nil)
case class ArtifactPattern(
organisation: String,
name: String,
version: Option[String])
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(_._2 match {
case Some(_) id
case None id.copy(version = "")
})
}.reduceOption(_ | _).getOrElse {
(Space ~> token(StringBasic, "organization") ~ Space ~ token(StringBasic, "module") ~ (Space ~ token(StringBasic, "version")).?).map {
case (((org, _), mod), version)
ModuleId(org, mod, version.map(_._2).getOrElse(""))
}
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)
.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
@ -222,34 +215,4 @@ object DependencyGraphSettings {
case _ None
}
}
/**
* This is copied directly from sbt/main/Defaults.java and then changed to update the UpdateConfiguration
* to ignore missing artifacts.
*/
def ignoreMissingUpdateT =
ignoreMissingUpdate <<= Def.task {
val depsUpdated = transitiveUpdate.value.exists(!_.stats.cached)
val isRoot = executionRoots.value contains resolvedScoped.value
val s = streams.value
val scalaProvider = appConfiguration.value.provider.scalaProvider
// Only substitute unmanaged jars for managed jars when the major.minor parts of the versions the same for:
// the resolved Scala version and the scalaHome version: compatible (weakly- no qualifier checked)
// the resolved Scala version and the declared scalaVersion: assume the user intended scalaHome to override anything with scalaVersion
def subUnmanaged(subVersion: String, jars: Seq[File]) = (sv: String)
(partialVersion(sv), partialVersion(subVersion), partialVersion(scalaVersion.value)) match {
case (Some(res), Some(sh), _) if res == sh jars
case (Some(res), _, Some(decl)) if res == decl jars
case _ Nil
}
val subScalaJars: String Seq[File] = SbtAccess.unmanagedScalaInstanceOnly.value match {
case Some(si) subUnmanaged(si.version, si.jars)
case None sv if (scalaProvider.version == sv) scalaProvider.jars else Nil
}
val transform: UpdateReport UpdateReport = r Classpaths.substituteScalaFiles(scalaOrganization.value, r)(subScalaJars)
val show = Reference.display(thisProjectRef.value)
Classpaths.cachedUpdate(s.cacheDirectory, show, ivyModule.value, (updateConfiguration in ignoreMissingUpdate).value, transform, skip = (skip in update).value, force = isRoot, depsUpdated = depsUpdated, log = s.log)
}
}

View File

@ -36,7 +36,8 @@ object IvyReport {
revision mod \ "revision"
rev = revision.attribute("name").get.text
moduleId = moduleIdFromElement(mod, rev)
module = Module(moduleId,
module = Module(
moduleId,
(revision \ "license").headOption.flatMap(_.attribute("name")).map(_.text),
evictedByVersion = (revision \ "evicted-by").headOption.flatMap(_.attribute("rev").map(_.text)),
error = revision.attribute("error").map(_.text))

View File

@ -17,6 +17,9 @@
package net.virtualvoid.sbt.graph
package backend
import scala.language.implicitConversions
import scala.language.reflectiveCalls
import sbt._
object SbtUpdateReport {
@ -35,7 +38,8 @@ object SbtUpdateReport {
def moduleEdge(chosenVersion: Option[String])(report: ModuleReport): (Module, Seq[Edge]) = {
val evictedByVersion = if (report.evicted) chosenVersion else None
val jarFile = report.artifacts.find(_._1.`type` == "jar").orElse(report.artifacts.find(_._1.extension == "jar")).map(_._2)
(Module(
(
Module(
id = report.module,
license = report.licenses.headOption.map(_._1),
evictedByVersion = evictedByVersion,

View File

@ -18,19 +18,23 @@ package net.virtualvoid.sbt.graph
import java.io.File
import scala.collection.mutable.{ MultiMap, HashMap, Set }
import sbinary.Format
case class ModuleId(organisation: String,
name: String,
version: String) {
import scala.collection.mutable.{ HashMap, MultiMap, Set }
case class ModuleId(
organisation: String,
name: String,
version: String) {
def idString: String = organisation + ":" + name + ":" + version
}
case class Module(id: ModuleId,
license: Option[String] = None,
extraInfo: String = "",
evictedByVersion: Option[String] = None,
jarFile: Option[File] = None,
error: Option[String] = None) {
case class Module(
id: ModuleId,
license: Option[String] = None,
extraInfo: String = "",
evictedByVersion: Option[String] = None,
jarFile: Option[File] = None,
error: Option[String] = None) {
def hadError: Boolean = error.isDefined
def isUsed: Boolean = !isEvicted
def isEvicted: Boolean = evictedByVersion.isDefined
@ -65,8 +69,9 @@ case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) {
nodes.filter(n !edges.exists(_._2 == n.id)).sortBy(_.id.idString)
}
import sbinary.{ Format, DefaultProtocol }
object ModuleGraphProtocol extends DefaultProtocol {
object ModuleGraphProtocol extends ModuleGraphProtocolCompat {
import sbinary.DefaultProtocol._
implicit def seqFormat[T: Format]: Format[Seq[T]] = wrap[Seq[T], List[T]](_.toList, _.toSeq)
implicit val ModuleIdFormat: Format[ModuleId] = asProduct3(ModuleId)(ModuleId.unapply(_).get)
implicit val ModuleFormat: Format[Module] = asProduct6(Module)(Module.unapply(_).get)

View File

@ -20,15 +20,17 @@ package rendering
object DOT {
val EvictedStyle = "stroke-dasharray: 5,5"
def dotGraph(graph: ModuleGraph,
dotHead: String,
nodeFormation: (String, String, String) String,
labelRendering: HTMLLabelRendering): String = {
def dotGraph(
graph: ModuleGraph,
dotHead: String,
nodeFormation: (String, String, String) String,
labelRendering: HTMLLabelRendering): String = {
val nodes = {
for (n graph.nodes) yield {
val style = if (n.isEvicted) EvictedStyle else ""
val label = nodeFormation(n.id.organisation, n.id.name, n.id.version)
""" "%s"[%s style="%s"]""".format(n.id.idString,
""" "%s"[%s style="%s"]""".format(
n.id.idString,
labelRendering.renderLabel(label),
style)
}

View File

@ -21,7 +21,7 @@ import net.virtualvoid.sbt.graph.ModuleGraph
import scala.xml.XML
object GraphML {
def saveAsGraphML(graph: ModuleGraph, outputFile: String) {
def saveAsGraphML(graph: ModuleGraph, outputFile: String): Unit = {
val nodesXml =
for (n graph.nodes)
yield <node id={ n.id.idString }><data key="d0">

View File

@ -20,12 +20,12 @@ package rendering
object Statistics {
def renderModuleStatsList(graph: ModuleGraph): String = {
case class ModuleStats(
id: ModuleId,
numDirectDependencies: Int,
numTransitiveDependencies: Int,
selfSize: Option[Long],
transitiveSize: Long,
transitiveDependencyStats: Map[ModuleId, ModuleStats]) {
id: ModuleId,
numDirectDependencies: Int,
numTransitiveDependencies: Int,
selfSize: Option[Long],
transitiveSize: Long,
transitiveDependencyStats: Map[ModuleId, ModuleStats]) {
def transitiveStatsWithSelf: Map[ModuleId, ModuleStats] = transitiveDependencyStats + (id -> this)
}

View File

@ -5,16 +5,19 @@
*/
package net.virtualvoid.sbt.graph.util
import sbt.dependencygraph.SbtAccess
object AsciiTreeLayout {
// [info] foo
// [info] +-bar
// [info] | +-baz
// [info] |
// [info] +-quux
def toAscii[A](top: A,
children: A Seq[A],
display: A String,
maxColumn: Int = defaultColumnSize): String = {
def toAscii[A](
top: A,
children: A Seq[A],
display: A String,
maxColumn: Int = defaultColumnSize): String = {
val twoSpaces = " " + " " // prevent accidentally being converted into a tab
def limitLine(s: String): String =
if (s.length > maxColumn) s.slice(0, maxColumn - 2) + ".."
@ -52,7 +55,7 @@ object AsciiTreeLayout {
}
def defaultColumnSize: Int = {
val termWidth = sbt.SbtAccess.getTerminalWidth
val termWidth = SbtAccess.getTerminalWidth
if (termWidth > 20) termWidth - 8
else 80 // ignore termWidth
}

View File

@ -14,11 +14,13 @@
* limitations under the License.
*/
package sbt
package sbt.dependencygraph
import sbt.Defaults
/** Accessors to private[sbt] symbols. */
object SbtAccess {
val unmanagedScalaInstanceOnly = Defaults.unmanagedScalaInstanceOnly
def getTerminalWidth: Int = JLine.usingTerminal(_.getWidth)
def getTerminalWidth: Int = sbt.internal.util.JLine.usingTerminal(_.getWidth)
}

View File

@ -1 +0,0 @@
sbt.version=0.13.6

View File

@ -5,7 +5,9 @@ libraryDependencies ++= Seq(
"ch.qos.logback" % "logback-classic" % "1.0.7"
)
TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, graph) =>
TaskKey[Unit]("check") := {
val report = (ivyReport in Test).value
val graph = (asciiTree in Test).value
def sanitize(str: String): String = str.split('\n').drop(1).map(_.trim).mkString("\n")
val expectedGraph =
"""default:default-e95e05_2.9.2:0.1-SNAPSHOT [S]

View File

@ -1,17 +1,22 @@
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"
)
TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, graph) =>
TaskKey[Unit]("check") := {
val report = (ivyReport in Test).value
val graph = (asciiTree in Test).value
def sanitize(str: String): String = str.split('\n').drop(1).map(_.trim).mkString("\n")
val expectedGraph =
"""default:default-dbc48d_2.9.2:0.1-SNAPSHOT [S]
| +-com.codahale:jerkson_2.9.1:0.5.0 [S]
| +-org.codehaus.jackson:jackson-core-asl:1.9.13
| +-org.codehaus.jackson:jackson-mapper-asl:1.9.13
| +-org.codehaus.jackson:jackson-core-asl:1.9.13
| +-org.codehaus.jackson:jackson-core-asl:1.9.11
| +-org.codehaus.jackson:jackson-mapper-asl:1.9.11
| +-org.codehaus.jackson:jackson-core-asl:1.9.11
| """.stripMargin
IO.writeLines(file("/tmp/blib"), sanitize(graph).split("\n"))
IO.writeLines(file("/tmp/blub"), sanitize(expectedGraph).split("\n"))

View File

@ -1 +1 @@
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.3-SNAPSHOT")
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % sys.props("project.version"))

View File

@ -3,7 +3,10 @@ scalaVersion := "2.9.2"
libraryDependencies +=
"at.blub" % "blib" % "1.2.3" % "test"
TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, graph) =>
TaskKey[Unit]("check") := {
val report = (ivyReport in Test).value
val graph = (asciiTree in Test).value
def sanitize(str: String): String = str.split('\n').drop(1).mkString("\n")
val expectedGraph =
"""default:default-91180e_2.9.2:0.1-SNAPSHOT

View File

@ -0,0 +1,68 @@
import collection.mutable.ListBuffer
import net.virtualvoid.sbt.graph.DependencyGraphKeys.dependencyDot
import scala.collection.mutable.ListBuffer
def defaultSettings =
Seq(
scalaVersion := "2.9.2",
version := "0.1-SNAPSHOT"
)
lazy val justATransiviteDependencyEndpointProject =
Project("just-a-transitive-dependency-endpoint", file("a"))
.settings(defaultSettings: _*)
lazy val justATransitiveDependencyProject =
Project("just-a-transitive-dependency", file("b"))
.settings(defaultSettings: _*)
.dependsOn(justATransiviteDependencyEndpointProject)
lazy val justADependencyProject =
Project("just-a-dependency", file("c"))
.settings(defaultSettings: _*)
lazy val test_project =
Project("test-dot-file-generation", file("d"))
.settings(defaultSettings: _*)
.settings(
TaskKey[Unit]("check") := {
val dotFile = (dependencyDot in Compile).value
val expectedGraph =
"""digraph "dependency-graph" {
| graph[rankdir="LR"]
| edge [
| arrowtail="none"
| ]
| "test-dot-file-generation:test-dot-file-generation_2.9.2:0.1-SNAPSHOT"[label=<test-dot-file-generation<BR/><B>test-dot-file-generation_2.9.2</B><BR/>0.1-SNAPSHOT> style=""]
| "just-a-transitive-dependency:just-a-transitive-dependency_2.9.2:0.1-SNAPSHOT"[label=<just-a-transitive-dependency<BR/><B>just-a-transitive-dependency_2.9.2</B><BR/>0.1-SNAPSHOT> style=""]
| "just-a-transitive-dependency-endpoint:just-a-transitive-dependency-endpoint_2.9.2:0.1-SNAPSHOT"[label=<just-a-transitive-dependency-endpoint<BR/><B>just-a-transitive-dependency-endpoint_2.9.2</B><BR/>0.1-SNAPSHOT> style=""]
| "just-a-dependency:just-a-dependency_2.9.2:0.1-SNAPSHOT"[label=<just-a-dependency<BR/><B>just-a-dependency_2.9.2</B><BR/>0.1-SNAPSHOT> style=""]
| "test-dot-file-generation:test-dot-file-generation_2.9.2:0.1-SNAPSHOT" -> "just-a-transitive-dependency:just-a-transitive-dependency_2.9.2:0.1-SNAPSHOT"
| "just-a-transitive-dependency:just-a-transitive-dependency_2.9.2:0.1-SNAPSHOT" -> "just-a-transitive-dependency-endpoint:just-a-transitive-dependency-endpoint_2.9.2:0.1-SNAPSHOT"
| "test-dot-file-generation:test-dot-file-generation_2.9.2:0.1-SNAPSHOT" -> "just-a-dependency:just-a-dependency_2.9.2:0.1-SNAPSHOT"
|}
""".stripMargin
val graph : String = scala.io.Source.fromFile(dotFile.getAbsolutePath).mkString
val errors = compareByLine(graph, expectedGraph)
require(errors.isEmpty , errors.mkString("\n"))
()
}
)
.dependsOn(justADependencyProject, justATransitiveDependencyProject)
def compareByLine(got : String, expected : String) : Seq[String] = {
val errors = ListBuffer[String]()
got.split("\n").zip(expected.split("\n").toSeq).zipWithIndex.foreach { case((got_line : String, expected_line : String), i : Int) =>
if(got_line != expected_line) {
errors.append(
"""not matching lines at line %s
|expected: %s
|got: %s
|""".stripMargin.format(i,expected_line, got_line))
}
}
errors
}

View File

@ -1,68 +0,0 @@
import collection.mutable.ListBuffer
import sbt._
import sbt.Keys._
import net.virtualvoid.sbt.graph.DependencyGraphKeys._
object Build extends sbt.Build {
def defaultSettings =
Seq(scalaVersion := "2.9.2")
lazy val justATransiviteDependencyEndpointProject =
Project("just-a-transitive-dependency-endpoint", file("a"))
.settings(defaultSettings: _*)
lazy val justATransitiveDependencyProject =
Project("just-a-transitive-dependency", file("b"))
.settings(defaultSettings: _*)
.dependsOn(justATransiviteDependencyEndpointProject)
lazy val justADependencyProject =
Project("just-a-dependency", file("c"))
.settings(defaultSettings: _*)
lazy val test_project =
Project("test-dot-file-generation", file("d"))
.settings(defaultSettings: _*)
.settings(
TaskKey[Unit]("check") <<= (dependencyDot in Compile) map { (dotFile) =>
val expectedGraph =
"""digraph "dependency-graph" {
| graph[rankdir="LR"]
| edge [
| arrowtail="none"
| ]
| "test-dot-file-generation:test-dot-file-generation_2.9.2:0.1-SNAPSHOT"[label=<test-dot-file-generation<BR/><B>test-dot-file-generation_2.9.2</B><BR/>0.1-SNAPSHOT> style=""]
| "just-a-transitive-dependency:just-a-transitive-dependency_2.9.2:0.1-SNAPSHOT"[label=<just-a-transitive-dependency<BR/><B>just-a-transitive-dependency_2.9.2</B><BR/>0.1-SNAPSHOT> style=""]
| "just-a-transitive-dependency-endpoint:just-a-transitive-dependency-endpoint_2.9.2:0.1-SNAPSHOT"[label=<just-a-transitive-dependency-endpoint<BR/><B>just-a-transitive-dependency-endpoint_2.9.2</B><BR/>0.1-SNAPSHOT> style=""]
| "just-a-dependency:just-a-dependency_2.9.2:0.1-SNAPSHOT"[label=<just-a-dependency<BR/><B>just-a-dependency_2.9.2</B><BR/>0.1-SNAPSHOT> style=""]
| "test-dot-file-generation:test-dot-file-generation_2.9.2:0.1-SNAPSHOT" -> "just-a-transitive-dependency:just-a-transitive-dependency_2.9.2:0.1-SNAPSHOT"
| "just-a-transitive-dependency:just-a-transitive-dependency_2.9.2:0.1-SNAPSHOT" -> "just-a-transitive-dependency-endpoint:just-a-transitive-dependency-endpoint_2.9.2:0.1-SNAPSHOT"
| "test-dot-file-generation:test-dot-file-generation_2.9.2:0.1-SNAPSHOT" -> "just-a-dependency:just-a-dependency_2.9.2:0.1-SNAPSHOT"
|}
""".stripMargin
val graph : String = scala.io.Source.fromFile(dotFile.getAbsolutePath).mkString
val errors = compareByLine(graph, expectedGraph)
require(errors.isEmpty , errors.mkString("\n"))
()
}
)
.dependsOn(justADependencyProject, justATransitiveDependencyProject)
def compareByLine(got : String, expected : String) : Seq[String] = {
val errors = ListBuffer[String]()
got.split("\n").zip(expected.split("\n").toSeq).zipWithIndex.foreach { case((got_line : String, expected_line : String), i : Int) =>
if(got_line != expected_line) {
errors.append(
"""not matching lines at line %s
|expected: %s
|got: %s
|""".stripMargin.format(i,expected_line, got_line))
}
}
errors
}
}