From da69fd823dbe5f3e4d62f3cefb32c440c0f7a23c Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 15 Nov 2011 16:06:02 +0100 Subject: [PATCH 001/252] initial version --- .gitignore | 7 +++ build.sbt | 7 +++ .../sbt/graph/IvyGraphMLDependencies.scala | 63 +++++++++++++++++++ .../net/virtualvoid/sbt/graph/Plugin.scala | 20 ++++++ 4 files changed, 97 insertions(+) create mode 100644 .gitignore create mode 100644 build.sbt create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..5b68a8125 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.idea +project/boot/ +target/ +lib_managed/ +src_managed/ +test-output/ +*.iml \ No newline at end of file diff --git a/build.sbt b/build.sbt new file mode 100644 index 000000000..6cb5398ec --- /dev/null +++ b/build.sbt @@ -0,0 +1,7 @@ +sbtPlugin := true + +name := "sbt-dependency-graph" + +organization := "net.virtualvoid" + +version := "0.5" \ No newline at end of file diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala new file mode 100644 index 000000000..e0d350b11 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -0,0 +1,63 @@ +package net.virtualvoid.sbt.graph + +import xml.parsing.ConstructingParser +import java.io.File +import xml.{XML, Node} + +object IvyGraphMLDependencies extends App { + case class Module(organisation: String, name: String) { + def id: String = organisation+"."+name + } + def transform(ivyReportFile: String, outputFile: String) { + val doc = ConstructingParser.fromSource(io.Source.fromFile(ivyReportFile), false).document + + val edges = + for (mod <- doc \ "dependencies" \ "module"; + depModule = nodeFromElement(mod); + caller <- mod \ "revision" \ "caller"; + callerModule = nodeFromElement(caller)) + yield (callerModule, depModule) + + val nodes = edges.flatMap(e => Seq(e._1, e._2)).distinct + + val nodesXml = + for (n <- nodes) + yield + + + {n.id} + + + + val edgesXml = + for (e <- edges) + yield + + val xml = + + + + {nodesXml} + {edgesXml} + + + + XML.save(outputFile, xml) + } + def nodeFromElement(element: Node): Module = + Module(element.attribute("organisation").get.text, element.attribute("name").get.text) + + def die(msg: String): Nothing = { + println(msg) + sys.exit(1) + } + def usage: String = + "Usage: " + + val file = args.lift(0).filter(f => new File(f).exists).getOrElse(die(usage)) + val inputFile = args.lift(1).getOrElse(die(usage)) + transform(file, inputFile) +} \ No newline at end of file diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala new file mode 100644 index 000000000..39a706718 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -0,0 +1,20 @@ +package net.virtualvoid.sbt.graph + +import sbt._ +import Keys._ + +object Plugin extends sbt.Plugin { + val dependencyGraphTask = TaskKey[File]("dependency-graph") + + def graphSettings = Seq( + dependencyGraphTask <<= (projectID, appConfiguration, target, streams) map { (projectID, config, target, streams) => + val home = config.provider.scalaProvider.launcher.ivyHome + val fileName = "%s/cache/%s-%s-compile.xml" format (home, projectID.organization, projectID.name) + + val resultFile = target / "dependencies.graphml" + IvyGraphMLDependencies.transform(fileName, resultFile.getAbsolutePath) + streams.log.info("Wrote dependency graph to '%s'" format resultFile) + resultFile + } dependsOn(deliverLocal) + ) +} \ No newline at end of file From 0e9ca265e6430501dde37924bf6a1f7b3989836e Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 15 Nov 2011 16:01:32 +0100 Subject: [PATCH 002/252] readme and licensing --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 48 +++++++++++++ 2 files changed, 249 insertions(+) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..f49a4e16e --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..6668ba46b --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +sbt-dependency-graph +==================== + +Create a graph (in graphml format) from your project's dependencies. + +Requirements +------------ + +* Simple Build Tool + +How To Use +---------- + +For sbt 0.11, in `project/plugins/project/build.scala`: + +```scala +import sbt._ + +object Plugins extends Build { + lazy val root = Project("root", file(".")) dependsOn( + uri("git://github.com/") // where XX is branch + ) +} +``` + +Then, add the following in your `build.sbt`: + +```scala +seq(net.virtualvoid.sbt.graph.Plugin.graphSettings: _*) +``` + +In sbt you can then use the `dependency-graph` task in sbt to generate a graphml file +in `target/dependencies.graphml`. Use e.g. [yEd](http://www.yworks.com/en/products_yed_about.html) +to format the graph to your needs. + + +Inner Workings +-------------- + +The task relies on sbt/Ivy's `deliver-local` task to create an ivy report inside the `.ivy2/cache` +directory. This report is then transformed into a graphml file. + +License +------- + +Copyright (c) 2011 Johannes Rudolph + +Published under the [Apache License 2.0](http://en.wikipedia.org/wiki/Apache_license). \ No newline at end of file From d3d4bf968128218cc88192305d318fc5c05942be Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 15 Nov 2011 16:11:44 +0100 Subject: [PATCH 003/252] update git path --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6668ba46b..9200aeb08 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ import sbt._ object Plugins extends Build { lazy val root = Project("root", file(".")) dependsOn( - uri("git://github.com/") // where XX is branch + uri("git://github.com/jrudolph/sbt-dependency-graph.git#XX") // where XX is tag/branch ) } ``` From 94b93b0354aa03204edb855139e06f0a873c16f9 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 15 Nov 2011 16:14:03 +0100 Subject: [PATCH 004/252] add current version in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9200aeb08..f9f6f9831 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ import sbt._ object Plugins extends Build { lazy val root = Project("root", file(".")) dependsOn( - uri("git://github.com/jrudolph/sbt-dependency-graph.git#XX") // where XX is tag/branch + uri("git://github.com/jrudolph/sbt-dependency-graph.git#v0.5") // or another tag/branch ) } ``` From dcc082d215c27d062655f93279c2a71581ec6e40 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 15 Nov 2011 16:36:33 +0100 Subject: [PATCH 005/252] add other method of including the plugin in README.md --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f9f6f9831..4d28e57d9 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,20 @@ Requirements How To Use ---------- -For sbt 0.11, in `project/plugins/project/build.scala`: +For sbt 0.11, add sbt-assembly as a dependency in `project/plugins.sbt`: + +```scala +addSbtPlugin("net.virtualvoid" % "sbt-dependency-graph" % "0.5") +``` + +or, alternatively, in `project/plugins/project/build.scala`: ```scala import sbt._ object Plugins extends Build { lazy val root = Project("root", file(".")) dependsOn( - uri("git://github.com/jrudolph/sbt-dependency-graph.git#v0.5") // or another tag/branch + uri("git://github.com/jrudolph/sbt-dependency-graph.git#v0.5") // or another tag/branch/revision ) } ``` From 7286764bf95b8317decbe089d9e0b0e3ec30ffab Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 15 Nov 2011 17:27:53 +0100 Subject: [PATCH 006/252] add note about stand-alone usage --- README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4d28e57d9..043b8683b 100644 --- a/README.md +++ b/README.md @@ -39,12 +39,22 @@ In sbt you can then use the `dependency-graph` task in sbt to generate a graphml in `target/dependencies.graphml`. Use e.g. [yEd](http://www.yworks.com/en/products_yed_about.html) to format the graph to your needs. +Standalone usage +---------------- + +You can use the project without sbt as well by either depending on the library and calling +`IvyGraphMLDependencies.transfrom(sourceIvyReport, targetFile)` or by just getting the binary +and calling it like `scala sbt-dependency-graph-0.5.jar `. + Inner Workings -------------- -The task relies on sbt/Ivy's `deliver-local` task to create an ivy report inside the `.ivy2/cache` -directory. This report is then transformed into a graphml file. +sbt/Ivy's `deliver-local` task create ivy-report xml-files inside `.ivy2/cache`. You can +just open them with your browser to look at the dependency report for your project. +This project takes the report xml of your project and creates a graphml file out of it. (BTW, +ivy can create graphml files itself, but since I didn't want to spend to much time getting +sbt to call into Ivy to create graphs, I went with the easy way here) License ------- From 2520dc25ded56a60079198a014343bab7ee22809 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 18 Nov 2011 11:10:57 +0100 Subject: [PATCH 007/252] take scala version classifier into account when crossPath is true (fixes #1) --- .../net/virtualvoid/sbt/graph/Plugin.scala | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 39a706718..c8b56a425 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -4,12 +4,13 @@ import sbt._ import Keys._ object Plugin extends sbt.Plugin { - val dependencyGraphTask = TaskKey[File]("dependency-graph") + val dependencyGraphTask = TaskKey[File]("dependency-graph") - def graphSettings = Seq( - dependencyGraphTask <<= (projectID, appConfiguration, target, streams) map { (projectID, config, target, streams) => + def graphSettings = Seq( + dependencyGraphTask <<= (projectID, scalaVersion, appConfiguration, target, streams) map { (projectID, scalaVersion, config, target, streams) => val home = config.provider.scalaProvider.launcher.ivyHome - val fileName = "%s/cache/%s-%s-compile.xml" format (home, projectID.organization, projectID.name) + + val fileName = "%s/cache/%s-%s-compile.xml" format (home, projectID.organization, crossName(projectID, scalaVersion)) val resultFile = target / "dependencies.graphml" IvyGraphMLDependencies.transform(fileName, resultFile.getAbsolutePath) @@ -17,4 +18,12 @@ object Plugin extends sbt.Plugin { resultFile } dependsOn(deliverLocal) ) + + def crossName(moduleId: ModuleID, scalaVersion: String) = + moduleId.name + ( + if (moduleId.crossVersion) + "_"+scalaVersion + else + "" + ) } \ No newline at end of file From 09aa146fc5781f5c047f0096fcd369962872e465 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 18 Nov 2011 11:14:01 +0100 Subject: [PATCH 008/252] refactoring: function returning ivy report file for a config is now a separate SettingsKey --- .../scala/net/virtualvoid/sbt/graph/Plugin.scala | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index c8b56a425..b9d98b940 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -4,16 +4,19 @@ import sbt._ import Keys._ object Plugin extends sbt.Plugin { - val dependencyGraphTask = TaskKey[File]("dependency-graph") + val dependencyGraphTask = TaskKey[File]("dependency-graph", + "Creates a graphml file containing the dependency-graph for a project") + val ivyReport = SettingKey[String => File]("ivy-report", + "A function which returns the file containing the ivy report from the ivy cache for a given configuration") def graphSettings = Seq( - dependencyGraphTask <<= (projectID, scalaVersion, appConfiguration, target, streams) map { (projectID, scalaVersion, config, target, streams) => + ivyReport <<= (projectID, scalaVersion, appConfiguration) { (projectID, scalaVersion, config) => val home = config.provider.scalaProvider.launcher.ivyHome - - val fileName = "%s/cache/%s-%s-compile.xml" format (home, projectID.organization, crossName(projectID, scalaVersion)) - + (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(projectID, scalaVersion), c)) + }, + dependencyGraphTask <<= (ivyReport, target, streams) map { (report, target, streams) => val resultFile = target / "dependencies.graphml" - IvyGraphMLDependencies.transform(fileName, resultFile.getAbsolutePath) + IvyGraphMLDependencies.transform(report("compile").getAbsolutePath, resultFile.getAbsolutePath) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } dependsOn(deliverLocal) From fb38f8d2d2976651113ae0700ccefb5b0936e008 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 18 Nov 2011 11:15:15 +0100 Subject: [PATCH 009/252] bump version --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 6cb5398ec..b0606d69d 100644 --- a/build.sbt +++ b/build.sbt @@ -1,7 +1,7 @@ sbtPlugin := true +version := "0.5.1" + name := "sbt-dependency-graph" organization := "net.virtualvoid" - -version := "0.5" \ No newline at end of file From 5fe2abe28ece4ee200764ac4a6f94e4ea00d186c Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 18 Nov 2011 11:17:52 +0100 Subject: [PATCH 010/252] update readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 043b8683b..1e2d1ca6b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ How To Use For sbt 0.11, add sbt-assembly as a dependency in `project/plugins.sbt`: ```scala -addSbtPlugin("net.virtualvoid" % "sbt-dependency-graph" % "0.5") +addSbtPlugin("net.virtualvoid" % "sbt-dependency-graph" % "0.5.1") ``` or, alternatively, in `project/plugins/project/build.scala`: @@ -24,7 +24,7 @@ import sbt._ object Plugins extends Build { lazy val root = Project("root", file(".")) dependsOn( - uri("git://github.com/jrudolph/sbt-dependency-graph.git#v0.5") // or another tag/branch/revision + uri("git://github.com/jrudolph/sbt-dependency-graph.git#v0.5.1") // or another tag/branch/revision ) } ``` @@ -44,7 +44,7 @@ Standalone usage You can use the project without sbt as well by either depending on the library and calling `IvyGraphMLDependencies.transfrom(sourceIvyReport, targetFile)` or by just getting the binary -and calling it like `scala sbt-dependency-graph-0.5.jar `. +and calling it like `scala sbt-dependency-graph-0.5.1.jar `. Inner Workings From b231d33bd16db6e9defbbcb3aaebb6273dc06572 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 23 Nov 2011 09:18:45 +0100 Subject: [PATCH 011/252] s/assembly/dependency-graph --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e2d1ca6b..9e895b10b 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Requirements How To Use ---------- -For sbt 0.11, add sbt-assembly as a dependency in `project/plugins.sbt`: +For sbt 0.11, add sbt-dependency-graph as a dependency in `project/plugins.sbt`: ```scala addSbtPlugin("net.virtualvoid" % "sbt-dependency-graph" % "0.5.1") From 43c6006f4e3ea3d675ee058fc1584d896cd735bd Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 29 Nov 2011 15:23:41 +0100 Subject: [PATCH 012/252] add ls metadata --- build.sbt | 14 ++++++++++++++ project/plugins.sbt | 7 +++++++ src/main/ls/0.5.1.json | 18 ++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 project/plugins.sbt create mode 100644 src/main/ls/0.5.1.json diff --git a/build.sbt b/build.sbt index b0606d69d..2c6afbbc0 100644 --- a/build.sbt +++ b/build.sbt @@ -1,3 +1,5 @@ +seq(lsSettings :_*) + sbtPlugin := true version := "0.5.1" @@ -5,3 +7,15 @@ version := "0.5.1" name := "sbt-dependency-graph" organization := "net.virtualvoid" + +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") + +(LsKeys.tags in LsKeys.lsync) := Seq("dependency", "graph", "sbt-plugin", "sbt") + +(LsKeys.docsUrl in LsKeys.lsync) <<= homepage + +(description in LsKeys.lsync) := + "An sbt plugin which allows to create a graphml file from the dependencies of the project." + diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 000000000..3a55a6480 --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1,7 @@ + + +resolvers ++= Seq( + "less is" at "http://repo.lessis.me", + "coda" at "http://repo.codahale.com") + +addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.0") diff --git a/src/main/ls/0.5.1.json b/src/main/ls/0.5.1.json new file mode 100644 index 000000000..80a39a08d --- /dev/null +++ b/src/main/ls/0.5.1.json @@ -0,0 +1,18 @@ + +{ + "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 +} \ No newline at end of file From dc9d70200cc332692083a020b1d419f220ac1173 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Thu, 1 Dec 2011 11:39:45 +0100 Subject: [PATCH 013/252] rename `ivy-report` to `ivy-report-function` and introduce new InputTask `ivy-report` which results in the location of the ivy report file when given a configuration --- .../scala/net/virtualvoid/sbt/graph/Plugin.scala | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index b9d98b940..420262ea8 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -6,15 +6,25 @@ import Keys._ object Plugin extends sbt.Plugin { val dependencyGraphTask = TaskKey[File]("dependency-graph", "Creates a graphml file containing the dependency-graph for a project") - val ivyReport = SettingKey[String => File]("ivy-report", + val ivyReportF = SettingKey[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 = InputKey[File]("ivy-report", + "A task which returns the location of the ivy report file for a given configuration (default `compile`).") def graphSettings = Seq( - ivyReport <<= (projectID, scalaVersion, appConfiguration) { (projectID, scalaVersion, config) => + ivyReportF <<= (projectID, scalaVersion, appConfiguration) { (projectID, scalaVersion, config) => val home = config.provider.scalaProvider.launcher.ivyHome (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(projectID, scalaVersion), c)) }, - dependencyGraphTask <<= (ivyReport, target, streams) map { (report, target, streams) => + ivyReport <<= inputTask { args => + (args, ivyReportF) map { (args, report) => + if (args.isEmpty) + report("compile") + else + report(args(0)) + } + }, + dependencyGraphTask <<= (ivyReportF, target, streams) map { (report, target, streams) => val resultFile = target / "dependencies.graphml" IvyGraphMLDependencies.transform(report("compile").getAbsolutePath, resultFile.getAbsolutePath) streams.log.info("Wrote dependency graph to '%s'" format resultFile) From 2c2af36531617c16030bcbfd90cec52b1828577a Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 13 Feb 2012 11:18:25 +0100 Subject: [PATCH 014/252] add information for publishing to sonatype --- README.md | 2 +- build.sbt | 19 ------------------- project.sbt | 18 ++++++++++++++++++ project/Helpers.scala | 16 ++++++++++++++++ project/gpg.sbt | 3 +++ project/plugins.sbt | 6 +----- publish.sbt | 20 ++++++++++++++++++++ 7 files changed, 59 insertions(+), 25 deletions(-) create mode 100644 project.sbt create mode 100644 project/Helpers.scala create mode 100644 project/gpg.sbt create mode 100644 publish.sbt diff --git a/README.md b/README.md index 9e895b10b..e4542c5e8 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ How To Use For sbt 0.11, add sbt-dependency-graph as a dependency in `project/plugins.sbt`: ```scala -addSbtPlugin("net.virtualvoid" % "sbt-dependency-graph" % "0.5.1") +addSbtPlugin("net.virtualvoid" % "sbt-dependency-graph" % "0.5.2") ``` or, alternatively, in `project/plugins/project/build.scala`: diff --git a/build.sbt b/build.sbt index 2c6afbbc0..a20cff214 100644 --- a/build.sbt +++ b/build.sbt @@ -1,21 +1,2 @@ seq(lsSettings :_*) -sbtPlugin := true - -version := "0.5.1" - -name := "sbt-dependency-graph" - -organization := "net.virtualvoid" - -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") - -(LsKeys.tags in LsKeys.lsync) := Seq("dependency", "graph", "sbt-plugin", "sbt") - -(LsKeys.docsUrl in LsKeys.lsync) <<= homepage - -(description in LsKeys.lsync) := - "An sbt plugin which allows to create a graphml file from the dependencies of the project." - diff --git a/project.sbt b/project.sbt new file mode 100644 index 000000000..f712ceb01 --- /dev/null +++ b/project.sbt @@ -0,0 +1,18 @@ +sbtPlugin := true + +name := "sbt-dependency-graph" + +organization := "net.virtualvoid" + +version := "0.5.2" + +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") + +(LsKeys.tags in LsKeys.lsync) := Seq("dependency", "graph", "sbt-plugin", "sbt") + +(LsKeys.docsUrl in LsKeys.lsync) <<= homepage + +(description in LsKeys.lsync) := + "An sbt plugin which allows to create a graphml file from the dependencies of the project." diff --git a/project/Helpers.scala b/project/Helpers.scala new file mode 100644 index 000000000..4c426be62 --- /dev/null +++ b/project/Helpers.scala @@ -0,0 +1,16 @@ +import java.net.URL + +object Helpers { + def generatePomExtra(scmUrl: String, scmConnection: String, + developerId: String, developerName: String): xml.NodeSeq = + + { scmUrl } + { scmConnection } + + + + { developerId } + { developerName } + + +} \ No newline at end of file diff --git a/project/gpg.sbt b/project/gpg.sbt new file mode 100644 index 000000000..b53697a4d --- /dev/null +++ b/project/gpg.sbt @@ -0,0 +1,3 @@ +resolvers += Resolver.url("scalasbt", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases"))(Resolver.ivyStylePatterns) + +addSbtPlugin("com.jsuereth" % "xsbt-gpg-plugin" % "0.5") \ No newline at end of file diff --git a/project/plugins.sbt b/project/plugins.sbt index 3a55a6480..a5ab0e7ad 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,7 +1,3 @@ - - -resolvers ++= Seq( - "less is" at "http://repo.lessis.me", - "coda" at "http://repo.codahale.com") +resolvers += "less is" at "http://repo.lessis.me" addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.0") diff --git a/publish.sbt b/publish.sbt new file mode 100644 index 000000000..4b0fbca64 --- /dev/null +++ b/publish.sbt @@ -0,0 +1,20 @@ +publishTo <<= version { v: String => + 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") +} + +publishMavenStyle := true + +publishArtifact in Test := false + +pomIncludeRepository := { _ => false } + +credentials += Credentials(Path.userHome / ".ivy2" / ".credentials") + +pomExtra := + Helpers.generatePomExtra("git@github.com:jrudolph/sbt-dependency-graph.git", + "scm:git:git@github.com:jrudolph/sbt-dependency-graph.git", + "jrudolph", "Johannes Rudolph") + +useGpg := true From 1fa68c6a5c13be820d3f9373fea1dd874d6b5a2b Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 13 Feb 2012 11:18:54 +0100 Subject: [PATCH 015/252] update license headers --- .../sbt/graph/IvyGraphMLDependencies.scala | 16 ++++++++++++++++ .../scala/net/virtualvoid/sbt/graph/Plugin.scala | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index e0d350b11..def166018 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -1,3 +1,19 @@ +/* + * Copyright 2011, 2012 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 import xml.parsing.ConstructingParser diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 420262ea8..6d98092d2 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -1,3 +1,19 @@ +/* + * Copyright 2011, 2012 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 import sbt._ From 37fe81565ebfa66cb241b8daf358c71d3af45d43 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 13 Feb 2012 11:19:51 +0100 Subject: [PATCH 016/252] release 0.5.2 --- src/main/ls/0.5.2.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/ls/0.5.2.json diff --git a/src/main/ls/0.5.2.json b/src/main/ls/0.5.2.json new file mode 100644 index 000000000..895322b6a --- /dev/null +++ b/src/main/ls/0.5.2.json @@ -0,0 +1,18 @@ + +{ + "organization":"net.virtualvoid", + "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 +} \ No newline at end of file From 5bce725bdfc2b2dd39f595ff3c9462e113f168e3 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 13 Feb 2012 11:26:14 +0100 Subject: [PATCH 017/252] use new organization --- README.md | 6 ++++-- project.sbt | 2 +- src/main/ls/0.5.2.json | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e4542c5e8..58b313c28 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,11 @@ How To Use For sbt 0.11, add sbt-dependency-graph as a dependency in `project/plugins.sbt`: ```scala -addSbtPlugin("net.virtualvoid" % "sbt-dependency-graph" % "0.5.2") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.5.2") ``` +*Note*: The organization has recently been changed to `net.virtual-void`. + or, alternatively, in `project/plugins/project/build.scala`: ```scala @@ -24,7 +26,7 @@ import sbt._ object Plugins extends Build { lazy val root = Project("root", file(".")) dependsOn( - uri("git://github.com/jrudolph/sbt-dependency-graph.git#v0.5.1") // or another tag/branch/revision + uri("git://github.com/jrudolph/sbt-dependency-graph.git#v0.5.2") // or another tag/branch/revision ) } ``` diff --git a/project.sbt b/project.sbt index f712ceb01..f000b7925 100644 --- a/project.sbt +++ b/project.sbt @@ -2,7 +2,7 @@ sbtPlugin := true name := "sbt-dependency-graph" -organization := "net.virtualvoid" +organization := "net.virtual-void" version := "0.5.2" diff --git a/src/main/ls/0.5.2.json b/src/main/ls/0.5.2.json index 895322b6a..53582b5a0 100644 --- a/src/main/ls/0.5.2.json +++ b/src/main/ls/0.5.2.json @@ -1,6 +1,6 @@ { - "organization":"net.virtualvoid", + "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.", From 70462d7a62484c415bd11fb331aaa84c6e7fa070 Mon Sep 17 00:00:00 2001 From: Gerolf Seitz Date: Thu, 1 Dec 2011 23:57:05 +0100 Subject: [PATCH 018/252] Add version to nodes. --- .../sbt/graph/IvyGraphMLDependencies.scala | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index def166018..b2f07bdea 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -21,18 +21,18 @@ import java.io.File import xml.{XML, Node} object IvyGraphMLDependencies extends App { - case class Module(organisation: String, name: String) { - def id: String = organisation+"."+name + case class Module(organisation: String, name: String, version: String) { + def id: String = organisation+"."+name+"-"+version } def transform(ivyReportFile: String, outputFile: String) { val doc = ConstructingParser.fromSource(io.Source.fromFile(ivyReportFile), false).document - val edges = - for (mod <- doc \ "dependencies" \ "module"; - depModule = nodeFromElement(mod); - caller <- mod \ "revision" \ "caller"; - callerModule = nodeFromElement(caller)) - yield (callerModule, depModule) + val edges = for { + mod <- doc \ "dependencies" \ "module" + caller <- mod \ "revision" \ "caller" + callerModule = nodeFromElement(caller, caller.attribute("callerrev").get.text) + depModule = nodeFromElement(mod, caller.attribute("rev").get.text) + } yield (callerModule, depModule) val nodes = edges.flatMap(e => Seq(e._1, e._2)).distinct @@ -63,8 +63,8 @@ object IvyGraphMLDependencies extends App { XML.save(outputFile, xml) } - def nodeFromElement(element: Node): Module = - Module(element.attribute("organisation").get.text, element.attribute("name").get.text) + def nodeFromElement(element: Node, version: String): Module = + Module(element.attribute("organisation").get.text, element.attribute("name").get.text, version) def die(msg: String): Nothing = { println(msg) @@ -76,4 +76,4 @@ object IvyGraphMLDependencies extends App { val file = args.lift(0).filter(f => new File(f).exists).getOrElse(die(usage)) val inputFile = args.lift(1).getOrElse(die(usage)) transform(file, inputFile) -} \ No newline at end of file +} From f69915cb8c906ebe0a335e34f74a1330b8f8b4a5 Mon Sep 17 00:00:00 2001 From: Gerolf Seitz Date: Thu, 3 May 2012 18:03:59 +0200 Subject: [PATCH 019/252] Some visual improvements + Display nodes as groupId:artifact:version + Provide tasks for printing ascii representations of the dependency graphs for the various configurations: compile, test, runtime, optional, provided --- project.sbt | 2 +- project/build.properties | 1 + .../sbt/graph/IvyGraphMLDependencies.scala | 52 +++++++++++++++---- .../net/virtualvoid/sbt/graph/Plugin.scala | 33 ++++++++++-- 4 files changed, 73 insertions(+), 15 deletions(-) mode change 100644 => 100755 project.sbt create mode 100644 project/build.properties mode change 100644 => 100755 src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala mode change 100644 => 100755 src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala diff --git a/project.sbt b/project.sbt old mode 100644 new mode 100755 index f000b7925..f123069ac --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.5.2" +version := "0.5.3-SNAPSHOT" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 000000000..b6fc683c7 --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.12.0-Beta2 diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala old mode 100644 new mode 100755 index b2f07bdea..e981339b3 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -18,24 +18,54 @@ package net.virtualvoid.sbt.graph import xml.parsing.ConstructingParser import java.io.File -import xml.{XML, Node} +import collection.mutable.HashMap +import collection.mutable.MultiMap +import collection.mutable.{Set => MSet} +import sbt.Graph +import xml.{Document, XML, Node} object IvyGraphMLDependencies extends App { case class Module(organisation: String, name: String, version: String) { - def id: String = organisation+"."+name+"-"+version + def id: String = organisation+":"+name+":"+version } - def transform(ivyReportFile: String, outputFile: String) { - val doc = ConstructingParser.fromSource(io.Source.fromFile(ivyReportFile), false).document + case class ModuleGraph(nodes: Seq[Module], edges: Seq[(Module, Module)]) + + def buildGraph(doc: Document): ModuleGraph = { val edges = for { - mod <- doc \ "dependencies" \ "module" - caller <- mod \ "revision" \ "caller" - callerModule = nodeFromElement(caller, caller.attribute("callerrev").get.text) - depModule = nodeFromElement(mod, caller.attribute("rev").get.text) - } yield (callerModule, depModule) + mod <- doc \ "dependencies" \ "module" + caller <- mod \ "revision" \ "caller" + callerModule = nodeFromElement(caller, caller.attribute("callerrev").get.text) + depModule = nodeFromElement(mod, caller.attribute("rev").get.text) + } yield (callerModule, depModule) val nodes = edges.flatMap(e => Seq(e._1, e._2)).distinct + ModuleGraph(nodes, edges) + } + + + def ascii(ivyReportFile: String): String = { + val doc = buildDoc(ivyReportFile) + val graph = buildGraph(doc) + import graph._ + val deps = { + val m = new HashMap[Module, MSet[Module]] with MultiMap[Module, Module] + edges.foreach { case (from, to) => m.addBinding(from, to) } + m.toMap.mapValues(_.toSeq.sortBy(_.id)) + } + // there should only be one root node (the project itself) + val roots = nodes.filter(n => !edges.exists(_._2 == n)).sortBy(_.id) + roots.map(root => + Graph.toAscii[Module](root, node => deps.getOrElse(node, Seq.empty[Module]), _.id) + ).mkString("\n") + } + + def transform(ivyReportFile: String, outputFile: String) { + val doc = buildDoc(ivyReportFile) + val graph = buildGraph(doc) + import graph._ + val nodesXml = for (n <- nodes) yield @@ -63,9 +93,11 @@ object IvyGraphMLDependencies extends App { XML.save(outputFile, xml) } - def nodeFromElement(element: Node, version: String): Module = + private def nodeFromElement(element: Node, version: String): Module = Module(element.attribute("organisation").get.text, element.attribute("name").get.text, version) + private def buildDoc(ivyReportFile: String) = ConstructingParser.fromSource(io.Source.fromFile(ivyReportFile), false).document + def die(msg: String): Nothing = { println(msg) sys.exit(1) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala old mode 100644 new mode 100755 index 6d98092d2..c386a4be7 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -22,6 +22,10 @@ import Keys._ object Plugin extends sbt.Plugin { val dependencyGraphTask = TaskKey[File]("dependency-graph", "Creates a graphml file containing the dependency-graph for a project") + val asciiGraph = TaskKey[String]("ascii-graph", + "Returns a string containing the ascii representation of the dependency graph for a project") + val printAsciiGraph = TaskKey[Unit]("print-ascii-graph", + "Prints the ascii graph to the console") val ivyReportF = SettingKey[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 = InputKey[File]("ivy-report", @@ -40,6 +44,19 @@ object Plugin extends sbt.Plugin { report(args(0)) } }, + + asciiGraph in Compile <<= asciiGraphTask(Compile), + asciiGraph in Test <<= asciiGraphTask(Test), + asciiGraph in Runtime <<= asciiGraphTask(Runtime), + asciiGraph in Provided <<= asciiGraphTask(Provided), + asciiGraph in Optional <<= asciiGraphTask(Optional), + + printAsciiGraph in Compile <<= printAsciiGraphTask(Compile), + printAsciiGraph in Test <<= printAsciiGraphTask(Test), + printAsciiGraph in Runtime <<= printAsciiGraphTask(Runtime), + printAsciiGraph in Provided <<= printAsciiGraphTask(Provided), + printAsciiGraph in Optional <<= printAsciiGraphTask(Optional), + dependencyGraphTask <<= (ivyReportF, target, streams) map { (report, target, streams) => val resultFile = target / "dependencies.graphml" IvyGraphMLDependencies.transform(report("compile").getAbsolutePath, resultFile.getAbsolutePath) @@ -48,11 +65,19 @@ object Plugin extends sbt.Plugin { } dependsOn(deliverLocal) ) + def asciiGraphTask(conf: Configuration) = (ivyReportF in conf) map { (report) => + IvyGraphMLDependencies.ascii(report(conf.name).getAbsolutePath) + } dependsOn(deliverLocal) + + def printAsciiGraphTask(conf: Configuration) = (asciiGraph in conf, streams in conf) map { (graph, streams) => + streams.log.info(graph) + } + def crossName(moduleId: ModuleID, scalaVersion: String) = moduleId.name + ( - if (moduleId.crossVersion) - "_"+scalaVersion - else - "" + moduleId.crossVersion match { + case CrossVersion.Disabled => "" + case _ => "_"+scalaVersion + } ) } \ No newline at end of file From f3aadf22a03f983f12412385b932e072a5378d65 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 20 May 2012 18:06:28 +0200 Subject: [PATCH 020/252] add coda hale's repository for jerkson (needed for ls) --- project/plugins.sbt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/project/plugins.sbt b/project/plugins.sbt index a5ab0e7ad..e62de8942 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,5 @@ resolvers += "less is" at "http://repo.lessis.me" addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.0") + +resolvers += "Coda Hale's Repo" at "http://repo.codahale.com" \ No newline at end of file From c0e30531800847f5a515947271aaa8940d62ae7e Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 20 May 2012 18:08:08 +0200 Subject: [PATCH 021/252] add build-hive status batch to readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58b313c28..29937446c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -sbt-dependency-graph +sbt-dependency-graph ![Build status](https://buildhive.cloudbees.com/job/jrudolph/job/sbt-dependency-graph/badge/icon) ==================== Create a graph (in graphml format) from your project's dependencies. From 2304f1ecf76dfe645f5c733a370202f4df2067c6 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 20 May 2012 19:10:45 +0300 Subject: [PATCH 022/252] Link to build page instead of to badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 29937446c..a4599181e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -sbt-dependency-graph ![Build status](https://buildhive.cloudbees.com/job/jrudolph/job/sbt-dependency-graph/badge/icon) +sbt-dependency-graph [![Build Status](https://buildhive.cloudbees.com/job/jrudolph/job/sbt-dependency-graph/badge/icon)](https://buildhive.cloudbees.com/job/jrudolph/job/sbt-dependency-graph/) ==================== Create a graph (in graphml format) from your project's dependencies. From 67225369911a7c4ea8f08edd50ea59e862c5cd88 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 20 May 2012 18:19:51 +0200 Subject: [PATCH 023/252] depending on update is enough for ivy report to be generated --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 6d98092d2..514db1ba7 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -45,7 +45,7 @@ object Plugin extends sbt.Plugin { IvyGraphMLDependencies.transform(report("compile").getAbsolutePath, resultFile.getAbsolutePath) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile - } dependsOn(deliverLocal) + } dependsOn(update) ) def crossName(moduleId: ModuleID, scalaVersion: String) = From be22b8c66321f13071df28b7faa71b42008dabef Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 20 May 2012 18:21:17 +0200 Subject: [PATCH 024/252] use `scalaVersion in update` to lookup report file This will help if you use the common scalaVersion := "2.9.2" scalaVersion in update := "2.9.1" idiom. --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 514db1ba7..4bdbc264a 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -28,7 +28,7 @@ object Plugin extends sbt.Plugin { "A task which returns the location of the ivy report file for a given configuration (default `compile`).") def graphSettings = Seq( - ivyReportF <<= (projectID, scalaVersion, appConfiguration) { (projectID, scalaVersion, config) => + ivyReportF <<= (projectID, scalaVersion in update, appConfiguration) { (projectID, scalaVersion, config) => val home = config.provider.scalaProvider.launcher.ivyHome (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(projectID, scalaVersion), c)) }, From 116c13e51be4c78798f9a67b62dabf4f1271d174 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 21 May 2012 11:13:55 +0200 Subject: [PATCH 025/252] use sbt 0.12.0-Beta2 for building Had to disable ls for now since it is not yet supported for 0.12.0-Beta2 --- build.sbt | 2 +- project.sbt | 8 ++++---- project/build.properties | 1 + project/gpg.sbt | 2 +- project/plugins.sbt | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) create mode 100644 project/build.properties diff --git a/build.sbt b/build.sbt index a20cff214..73af45493 100644 --- a/build.sbt +++ b/build.sbt @@ -1,2 +1,2 @@ -seq(lsSettings :_*) +//seq(lsSettings :_*) diff --git a/project.sbt b/project.sbt index f000b7925..22167785e 100644 --- a/project.sbt +++ b/project.sbt @@ -10,9 +10,9 @@ 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") -(LsKeys.tags in LsKeys.lsync) := Seq("dependency", "graph", "sbt-plugin", "sbt") +//(LsKeys.tags in LsKeys.lsync) := Seq("dependency", "graph", "sbt-plugin", "sbt") -(LsKeys.docsUrl in LsKeys.lsync) <<= homepage +//(LsKeys.docsUrl in LsKeys.lsync) <<= homepage -(description in LsKeys.lsync) := - "An sbt plugin which allows to create a graphml file from the dependencies of the project." +//(description in LsKeys.lsync) := +// "An sbt plugin which allows to create a graphml file from the dependencies of the project." diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 000000000..82c888f3c --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.12.0-Beta2 \ No newline at end of file diff --git a/project/gpg.sbt b/project/gpg.sbt index b53697a4d..5f5af3d10 100644 --- a/project/gpg.sbt +++ b/project/gpg.sbt @@ -1,3 +1,3 @@ resolvers += Resolver.url("scalasbt", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases"))(Resolver.ivyStylePatterns) -addSbtPlugin("com.jsuereth" % "xsbt-gpg-plugin" % "0.5") \ No newline at end of file +addSbtPlugin("com.jsuereth" % "xsbt-gpg-plugin" % "0.6", sbtVersion = "0.12.0-Beta2") \ No newline at end of file diff --git a/project/plugins.sbt b/project/plugins.sbt index e62de8942..e3e0db641 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,5 +1,5 @@ resolvers += "less is" at "http://repo.lessis.me" -addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.0") +//addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.1", sbtVersion = "0.12.0-Beta2") resolvers += "Coda Hale's Repo" at "http://repo.codahale.com" \ No newline at end of file From d5ffe97485278738642e39e5c19587cfd65889c5 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 21 May 2012 11:31:28 +0200 Subject: [PATCH 026/252] improve DRYness --- .../net/virtualvoid/sbt/graph/Plugin.scala | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 04ffe7427..e51f1fc9b 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -31,7 +31,7 @@ object Plugin extends sbt.Plugin { val ivyReport = InputKey[File]("ivy-report", "A task which returns the location of the ivy report file for a given configuration (default `compile`).") - def graphSettings = Seq( + def graphSettings: Seq[Setting[_]] = seq( ivyReportF <<= (projectID, scalaVersion in update, appConfiguration) { (projectID, scalaVersion, config) => val home = config.provider.scalaProvider.launcher.ivyHome (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(projectID, scalaVersion), c)) @@ -45,25 +45,19 @@ object Plugin extends sbt.Plugin { } }, - asciiGraph in Compile <<= asciiGraphTask(Compile), - asciiGraph in Test <<= asciiGraphTask(Test), - asciiGraph in Runtime <<= asciiGraphTask(Runtime), - asciiGraph in Provided <<= asciiGraphTask(Provided), - asciiGraph in Optional <<= asciiGraphTask(Optional), - - printAsciiGraph in Compile <<= printAsciiGraphTask(Compile), - printAsciiGraph in Test <<= printAsciiGraphTask(Test), - printAsciiGraph in Runtime <<= printAsciiGraphTask(Runtime), - printAsciiGraph in Provided <<= printAsciiGraphTask(Provided), - printAsciiGraph in Optional <<= printAsciiGraphTask(Optional), - dependencyGraphTask <<= (ivyReportF, target, streams) map { (report, target, streams) => val resultFile = target / "dependencies.graphml" IvyGraphMLDependencies.transform(report("compile").getAbsolutePath, resultFile.getAbsolutePath) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } dependsOn(update) - ) + ) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(asciiGraphSettings) + + def asciiGraphSettings(config: Configuration) = + seq( + asciiGraph in config <<= asciiGraphTask(config), + printAsciiGraph in config <<= printAsciiGraphTask(config) + ) def asciiGraphTask(conf: Configuration) = (ivyReportF in conf) map { (report) => IvyGraphMLDependencies.ascii(report(conf.name).getAbsolutePath) From b7fbd8acdd90ed3be03a9b8dbb9ad6cd294cb56f Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 20 May 2012 18:19:51 +0200 Subject: [PATCH 027/252] depending on update is enough for ivy report to be generated --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 6d98092d2..514db1ba7 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -45,7 +45,7 @@ object Plugin extends sbt.Plugin { IvyGraphMLDependencies.transform(report("compile").getAbsolutePath, resultFile.getAbsolutePath) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile - } dependsOn(deliverLocal) + } dependsOn(update) ) def crossName(moduleId: ModuleID, scalaVersion: String) = From e232a9906ffd0bdfacc35e6eba1002dab8b5477d Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 20 May 2012 18:21:17 +0200 Subject: [PATCH 028/252] use `scalaVersion in update` to lookup report file This will help if you use the common scalaVersion := "2.9.2" scalaVersion in update := "2.9.1" idiom. --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 514db1ba7..4bdbc264a 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -28,7 +28,7 @@ object Plugin extends sbt.Plugin { "A task which returns the location of the ivy report file for a given configuration (default `compile`).") def graphSettings = Seq( - ivyReportF <<= (projectID, scalaVersion, appConfiguration) { (projectID, scalaVersion, config) => + ivyReportF <<= (projectID, scalaVersion in update, appConfiguration) { (projectID, scalaVersion, config) => val home = config.provider.scalaProvider.launcher.ivyHome (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(projectID, scalaVersion), c)) }, From 9a0d44ace74a78812ff03c4239610e86bd9c973c Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 21 May 2012 12:11:50 +0200 Subject: [PATCH 029/252] let ivy-report already depend on update to make sure report actually exists --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 4bdbc264a..1368d6d21 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -39,13 +39,13 @@ object Plugin extends sbt.Plugin { else report(args(0)) } - }, + } dependsOn(update), dependencyGraphTask <<= (ivyReportF, target, streams) map { (report, target, streams) => val resultFile = target / "dependencies.graphml" IvyGraphMLDependencies.transform(report("compile").getAbsolutePath, resultFile.getAbsolutePath) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile - } dependsOn(update) + } ) def crossName(moduleId: ModuleID, scalaVersion: String) = From b765bc6453775b8ad300aef17721bcc84357107d Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 21 May 2012 12:12:25 +0200 Subject: [PATCH 030/252] simpler sbt version independent crossName implementation --- .../net/virtualvoid/sbt/graph/Plugin.scala | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 1368d6d21..9926d9edd 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -22,15 +22,15 @@ import Keys._ object Plugin extends sbt.Plugin { val dependencyGraphTask = TaskKey[File]("dependency-graph", "Creates a graphml file containing the dependency-graph for a project") - val ivyReportF = SettingKey[String => File]("ivy-report-function", + val ivyReportF = 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 = InputKey[File]("ivy-report", "A task which returns the location of the ivy report file for a given configuration (default `compile`).") def graphSettings = Seq( - ivyReportF <<= (projectID, scalaVersion in update, appConfiguration) { (projectID, scalaVersion, config) => + ivyReportF <<= (projectID, ivyModule, appConfiguration) map { (projectID, ivyModule, config) => val home = config.provider.scalaProvider.launcher.ivyHome - (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(projectID, scalaVersion), c)) + (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c)) }, ivyReport <<= inputTask { args => (args, ivyReportF) map { (args, report) => @@ -48,11 +48,8 @@ object Plugin extends sbt.Plugin { } ) - def crossName(moduleId: ModuleID, scalaVersion: String) = - moduleId.name + ( - if (moduleId.crossVersion) - "_"+scalaVersion - else - "" - ) + def crossName(ivyModule: IvySbt#Module) = + ivyModule.moduleSettings match { + case ic: InlineConfiguration => ic.module.name + } } \ No newline at end of file From 376e037277d2f5e68d862f2b12506b7d01bfca01 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 21 May 2012 14:57:52 +0200 Subject: [PATCH 031/252] fix dependsOn update compile error --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 9926d9edd..3c213d15b 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -38,8 +38,8 @@ object Plugin extends sbt.Plugin { report("compile") else report(args(0)) - } - } dependsOn(update), + } dependsOn(update) + }, dependencyGraphTask <<= (ivyReportF, target, streams) map { (report, target, streams) => val resultFile = target / "dependencies.graphml" IvyGraphMLDependencies.transform(report("compile").getAbsolutePath, resultFile.getAbsolutePath) From 7ad5a74d4d5946b2132e04d1b69caf3aa106dfcf Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 21 May 2012 17:48:46 +0200 Subject: [PATCH 032/252] update build to sbt 0.11.3 --- build.sbt | 1 + project.sbt | 2 +- project/build.properties | 1 + project/gpg.sbt | 2 +- project/plugins.sbt | 6 ++++-- 5 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 project/build.properties diff --git a/build.sbt b/build.sbt index a20cff214..bd07b2865 100644 --- a/build.sbt +++ b/build.sbt @@ -1,2 +1,3 @@ seq(lsSettings :_*) +CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12.0-Beta2") \ No newline at end of file diff --git a/project.sbt b/project.sbt index f000b7925..c9d84e833 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.5.2" +version := "0.6.0-SNAPSHOT" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 000000000..d4287112c --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.11.3 diff --git a/project/gpg.sbt b/project/gpg.sbt index b53697a4d..d78507cdd 100644 --- a/project/gpg.sbt +++ b/project/gpg.sbt @@ -1,3 +1,3 @@ resolvers += Resolver.url("scalasbt", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases"))(Resolver.ivyStylePatterns) -addSbtPlugin("com.jsuereth" % "xsbt-gpg-plugin" % "0.5") \ No newline at end of file +addSbtPlugin("com.jsuereth" % "xsbt-gpg-plugin" % "0.6") \ No newline at end of file diff --git a/project/plugins.sbt b/project/plugins.sbt index e62de8942..b429bf973 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,5 +1,7 @@ resolvers += "less is" at "http://repo.lessis.me" -addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.0") +addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.1") -resolvers += "Coda Hale's Repo" at "http://repo.codahale.com" \ No newline at end of file +resolvers += "Coda Hale's Repo" at "http://repo.codahale.com" + +addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.6.0") From a7e37c4ac042b5ec693710c19c33cb98451ce73b Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 21 May 2012 18:31:07 +0200 Subject: [PATCH 033/252] a bunch of refactorings and setting renamings --- .../net/virtualvoid/sbt/graph/Plugin.scala | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index d11d59973..8384e1773 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -20,31 +20,31 @@ import sbt._ import Keys._ object Plugin extends sbt.Plugin { - val dependencyGraphTask = TaskKey[File]("dependency-graph", + val dependencyGraphML = TaskKey[File]("dependency-graph-ml", "Creates a graphml file containing the dependency-graph for a project") - val asciiGraph = TaskKey[String]("ascii-graph", + val asciiGraph = TaskKey[String]("dependency-graph-string", "Returns a string containing the ascii representation of the dependency graph for a project") - val printAsciiGraph = TaskKey[Unit]("print-ascii-graph", + val dependencyGraph = TaskKey[Unit]("dependency-graph", "Prints the ascii graph to the console") - val ivyReportF = 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 = InputKey[File]("ivy-report", "A task which returns the location of the ivy report file for a given configuration (default `compile`).") def graphSettings = Seq( - ivyReportF <<= (projectID, ivyModule, appConfiguration) map { (projectID, ivyModule, config) => + ivyReportFunction <<= (projectID, ivyModule, appConfiguration) map { (projectID, ivyModule, config) => val home = config.provider.scalaProvider.launcher.ivyHome (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c)) }, ivyReport <<= inputTask { args => - (args, ivyReportF) map { (args, report) => + (args, ivyReportFunction) map { (args, report) => if (args.isEmpty) report("compile") else report(args(0)) } dependsOn(update) }, - dependencyGraphTask <<= (ivyReportF, target, streams) map { (report, target, streams) => + dependencyGraphML <<= (ivyReportFunction, target, streams) map { (report, target, streams) => val resultFile = target / "dependencies.graphml" IvyGraphMLDependencies.transform(report("compile").getAbsolutePath, resultFile.getAbsolutePath) streams.log.info("Wrote dependency graph to '%s'" format resultFile) @@ -55,17 +55,14 @@ object Plugin extends sbt.Plugin { def asciiGraphSettings(config: Configuration) = seq( asciiGraph in config <<= asciiGraphTask(config), - printAsciiGraph in config <<= printAsciiGraphTask(config) + dependencyGraph in config <<= printAsciiGraphTask(config) ) - def asciiGraphTask(conf: Configuration) = (ivyReportF in conf) map { (report) => + def asciiGraphTask(conf: Configuration) = (ivyReportFunction in conf) map { (report) => IvyGraphMLDependencies.ascii(report(conf.name).getAbsolutePath) } dependsOn(deliverLocal) - def printAsciiGraphTask(conf: Configuration) = (asciiGraph in conf, streams in conf) map { (graph, streams) => - streams.log.info(graph) - } - + def printAsciiGraphTask(conf: Configuration) = (streams in conf, asciiGraph in conf) map (_.log.info(_)) def crossName(ivyModule: IvySbt#Module) = ivyModule.moduleSettings match { case ic: InlineConfiguration => ic.module.name From b30519f2d4ceb402655e721872c68b1cd4162da3 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 23 May 2012 10:47:26 +0200 Subject: [PATCH 034/252] ivyReport is not an InputKey any more, all tasks are now defined for all configurations --- .../net/virtualvoid/sbt/graph/Plugin.scala | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 8384e1773..1ca5a842d 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -28,41 +28,38 @@ object Plugin extends sbt.Plugin { "Prints the ascii graph to the console") 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 = InputKey[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`).") - def graphSettings = Seq( + def graphSettings = seq( ivyReportFunction <<= (projectID, ivyModule, appConfiguration) map { (projectID, ivyModule, config) => val home = config.provider.scalaProvider.launcher.ivyHome (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c)) - }, - ivyReport <<= inputTask { args => - (args, ivyReportFunction) map { (args, report) => - if (args.isEmpty) - report("compile") - else - report(args(0)) - } dependsOn(update) - }, - dependencyGraphML <<= (ivyReportFunction, target, streams) map { (report, target, streams) => + } + ) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(ivyReportForConfig) + + def ivyReportForConfig(config: Configuration) = inConfig(config)(seq( + ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(update), + asciiGraph <<= asciiGraphTask, + dependencyGraph <<= printAsciiGraphTask, + dependencyGraphML <<= dependencyGraphMLTask + )) + + def asciiGraphTask = (ivyReport) map { report => + IvyGraphMLDependencies.ascii(report.getAbsolutePath) + } + + def printAsciiGraphTask = + (streams, asciiGraph) map (_.log.info(_)) + + def dependencyGraphMLTask = + (ivyReport, target, streams) map { (report, target, streams) => val resultFile = target / "dependencies.graphml" - IvyGraphMLDependencies.transform(report("compile").getAbsolutePath, resultFile.getAbsolutePath) + IvyGraphMLDependencies.transform(report.getAbsolutePath, resultFile.getAbsolutePath) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } - ) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(asciiGraphSettings) - def asciiGraphSettings(config: Configuration) = - seq( - asciiGraph in config <<= asciiGraphTask(config), - dependencyGraph in config <<= printAsciiGraphTask(config) - ) - - def asciiGraphTask(conf: Configuration) = (ivyReportFunction in conf) map { (report) => - IvyGraphMLDependencies.ascii(report(conf.name).getAbsolutePath) - } dependsOn(deliverLocal) - - def printAsciiGraphTask(conf: Configuration) = (streams in conf, asciiGraph in conf) map (_.log.info(_)) def crossName(ivyModule: IvySbt#Module) = ivyModule.moduleSettings match { case ic: InlineConfiguration => ic.module.name From 18d2663a88fe8b4beb02f66d2215175b1fb5b874 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 23 May 2012 12:28:18 +0200 Subject: [PATCH 035/252] generated .graphml files name contain the configuration name --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 1ca5a842d..e061bf988 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -42,7 +42,7 @@ object Plugin extends sbt.Plugin { ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(update), asciiGraph <<= asciiGraphTask, dependencyGraph <<= printAsciiGraphTask, - dependencyGraphML <<= dependencyGraphMLTask + dependencyGraphML <<= dependencyGraphMLTask(config) )) def asciiGraphTask = (ivyReport) map { report => @@ -52,9 +52,9 @@ object Plugin extends sbt.Plugin { def printAsciiGraphTask = (streams, asciiGraph) map (_.log.info(_)) - def dependencyGraphMLTask = + def dependencyGraphMLTask(config: Configuration) = (ivyReport, target, streams) map { (report, target, streams) => - val resultFile = target / "dependencies.graphml" + val resultFile = target / "dependencies-%s.graphml".format(config.toString) IvyGraphMLDependencies.transform(report.getAbsolutePath, resultFile.getAbsolutePath) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile From 05dce31593d5bf14140292ef753a713849859121 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 23 May 2012 12:32:15 +0200 Subject: [PATCH 036/252] remove compile warning by handling unexpected configurations --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index e061bf988..effee1686 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -63,5 +63,7 @@ object Plugin extends sbt.Plugin { def crossName(ivyModule: IvySbt#Module) = ivyModule.moduleSettings match { case ic: InlineConfiguration => ic.module.name + case _ => + throw new IllegalStateException("sbt-dependency-graph plugin currently only supports InlineConfiguration of ivy settings (the default in sbt)") } } \ No newline at end of file From d480c79ccc1f2dd09314cdc231830551a44d8283 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 23 May 2012 12:33:54 +0200 Subject: [PATCH 037/252] new `dependency-graph-ml-file` setting to specify output location --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index effee1686..9668c1507 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -20,6 +20,8 @@ import sbt._ import Keys._ object Plugin extends sbt.Plugin { + val dependencyGraphMLFile = SettingKey[File]("dependency-graph-ml-file", + "The location the graphml file should be generated at") val dependencyGraphML = TaskKey[File]("dependency-graph-ml", "Creates a graphml file containing the dependency-graph for a project") val asciiGraph = TaskKey[String]("dependency-graph-string", @@ -42,7 +44,8 @@ object Plugin extends sbt.Plugin { ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(update), asciiGraph <<= asciiGraphTask, dependencyGraph <<= printAsciiGraphTask, - dependencyGraphML <<= dependencyGraphMLTask(config) + dependencyGraphMLFile <<= target / "dependencies-%s.graphml".format(config.toString), + dependencyGraphML <<= dependencyGraphMLTask )) def asciiGraphTask = (ivyReport) map { report => @@ -52,9 +55,8 @@ object Plugin extends sbt.Plugin { def printAsciiGraphTask = (streams, asciiGraph) map (_.log.info(_)) - def dependencyGraphMLTask(config: Configuration) = - (ivyReport, target, streams) map { (report, target, streams) => - val resultFile = target / "dependencies-%s.graphml".format(config.toString) + def dependencyGraphMLTask = + (ivyReport, dependencyGraphMLFile, streams) map { (report, resultFile, streams) => IvyGraphMLDependencies.transform(report.getAbsolutePath, resultFile.getAbsolutePath) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile From 3132466e0644de936acb212773db21637ff35834 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 23 May 2012 12:35:49 +0200 Subject: [PATCH 038/252] README and notes --- README.md | 22 ++++++++++++++++------ notes/0.6.0.markdown | 12 ++++++++++++ notes/about.markdown | 3 +++ 3 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 notes/0.6.0.markdown create mode 100644 notes/about.markdown diff --git a/README.md b/README.md index a4599181e..7a3a69067 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ How To Use For sbt 0.11, add sbt-dependency-graph as a dependency in `project/plugins.sbt`: ```scala -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.5.2") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.6.0") ``` *Note*: The organization has recently been changed to `net.virtual-void`. @@ -34,12 +34,22 @@ object Plugins extends Build { Then, add the following in your `build.sbt`: ```scala -seq(net.virtualvoid.sbt.graph.Plugin.graphSettings: _*) +net.virtualvoid.sbt.graph.Plugin.graphSettings ``` -In sbt you can then use the `dependency-graph` task in sbt to generate a graphml file -in `target/dependencies.graphml`. Use e.g. [yEd](http://www.yworks.com/en/products_yed_about.html) -to format the graph to your needs. +Tasks & Settings +---------------- + + * `dependency-graph`: Shows an ASCII graph of your dependency on the sbt console + * `dependency-graph-ml`: Generates a .graphml file with your dependencies to `target/dependencies-.graphml`. + Use e.g. [yEd](http://www.yworks.com/en/products_yed_about.html) to format the graph to your needs. + * `dependency-graph-ml-file`: a setting which allows configuring the output path of `dependency-graph-ml`. + * `ivy-report`: let's ivy generate the resolution report for you project. Use + `show ivy-report` for the filename of the generated report + +All tasks can be scoped to a configuration to get the report for a specific configuration. `test:dependency-graph`, +for example, prints the dependencies in the `test` configuration. If you don't specify any configuration, `compile` is +assumed as usual. Standalone usage ---------------- @@ -52,7 +62,7 @@ and calling it like `scala sbt-dependency-graph-0.5.1.jar Inner Workings -------------- -sbt/Ivy's `deliver-local` task create ivy-report xml-files inside `.ivy2/cache`. You can +sbt/Ivy's `update` task create ivy-report xml-files inside `.ivy2/cache`. You can just open them with your browser to look at the dependency report for your project. This project takes the report xml of your project and creates a graphml file out of it. (BTW, ivy can create graphml files itself, but since I didn't want to spend to much time getting diff --git a/notes/0.6.0.markdown b/notes/0.6.0.markdown new file mode 100644 index 000000000..0146dbd92 --- /dev/null +++ b/notes/0.6.0.markdown @@ -0,0 +1,12 @@ +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 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. diff --git a/notes/about.markdown b/notes/about.markdown new file mode 100644 index 000000000..01fbb70cf --- /dev/null +++ b/notes/about.markdown @@ -0,0 +1,3 @@ +[sbt-dependency-graph][gh] is an sbt plugin to visualize dependencies of your build. + +[gh]:https://github.com/jrudolph/sbt-dependency-graph/ \ No newline at end of file From 6c403b670ac8d4a72f8ae9c69526ed5850203b75 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 23 May 2012 12:36:16 +0200 Subject: [PATCH 039/252] bump version --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index c9d84e833..e02b3dacf 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.6.0-SNAPSHOT" +version := "0.6.0" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From de001b3de42e6c6a190325625030a195a778b8e9 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 23 May 2012 12:39:52 +0200 Subject: [PATCH 040/252] more README stuff --- NOTICE | 26 ++++++++++++++++++++++++++ project.sbt | 2 +- src/main/ls/0.6.0.json | 17 +++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 NOTICE create mode 100644 src/main/ls/0.6.0.json diff --git a/NOTICE b/NOTICE new file mode 100644 index 000000000..59536b942 --- /dev/null +++ b/NOTICE @@ -0,0 +1,26 @@ +Graph.scala is copied from sbt and is distributed under the following license: + +Copyright (c) 2008, 2009, 2010 Steven Blundy, Josh Cough, Mark Harrah, Stuart Roebuck, Tony Sloane, Vesa Vilhonen, Jason Zaugg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/project.sbt b/project.sbt index e02b3dacf..e38108c21 100644 --- a/project.sbt +++ b/project.sbt @@ -15,4 +15,4 @@ licenses in GlobalScope += "Apache License 2.0" -> url("https://github.com/jrudo (LsKeys.docsUrl in LsKeys.lsync) <<= homepage (description in LsKeys.lsync) := - "An sbt plugin which allows to create a graphml file from the dependencies of the project." + "An sbt plugin to visualize dependencies of your build." diff --git a/src/main/ls/0.6.0.json b/src/main/ls/0.6.0.json new file mode 100644 index 000000000..89d9a2c6c --- /dev/null +++ b/src/main/ls/0.6.0.json @@ -0,0 +1,17 @@ +{ + "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 +} \ No newline at end of file From 1539dcf7befc6f212f9ef0d65ee1204551277713 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 23 May 2012 13:42:04 +0300 Subject: [PATCH 041/252] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7a3a69067..897b7f990 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ sbt-dependency-graph [![Build Status](https://buildhive.cloudbees.com/job/jrudolph/job/sbt-dependency-graph/badge/icon)](https://buildhive.cloudbees.com/job/jrudolph/job/sbt-dependency-graph/) ==================== -Create a graph (in graphml format) from your project's dependencies. +Visualize your project's dependencies. Requirements ------------ @@ -26,7 +26,7 @@ import sbt._ object Plugins extends Build { lazy val root = Project("root", file(".")) dependsOn( - uri("git://github.com/jrudolph/sbt-dependency-graph.git#v0.5.2") // or another tag/branch/revision + uri("git://github.com/jrudolph/sbt-dependency-graph.git#v0.6.0") // or another tag/branch/revision ) } ``` @@ -71,6 +71,6 @@ sbt to call into Ivy to create graphs, I went with the easy way here) License ------- -Copyright (c) 2011 Johannes Rudolph +Copyright (c) 2011, 2012 Johannes Rudolph Published under the [Apache License 2.0](http://en.wikipedia.org/wiki/Apache_license). \ No newline at end of file From 6aced4f5076ac37bd34805bd3b90c925ad5355da Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 23 May 2012 12:58:14 +0200 Subject: [PATCH 042/252] another small notes fix --- notes/0.6.0.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notes/0.6.0.markdown b/notes/0.6.0.markdown index 0146dbd92..ddfef082d 100644 --- a/notes/0.6.0.markdown +++ b/notes/0.6.0.markdown @@ -3,7 +3,7 @@ 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 contain the dependency version as well (contributed by @gseitz). + 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 From 47ba5ef22fd501f52b8505ccdabbcfaa96588950 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 23 May 2012 13:03:14 +0200 Subject: [PATCH 043/252] herald wouldn't correctly show the link, so I changed the link to inline syntax --- notes/about.markdown | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/notes/about.markdown b/notes/about.markdown index 01fbb70cf..62e921d0a 100644 --- a/notes/about.markdown +++ b/notes/about.markdown @@ -1,3 +1 @@ -[sbt-dependency-graph][gh] is an sbt plugin to visualize dependencies of your build. - -[gh]:https://github.com/jrudolph/sbt-dependency-graph/ \ No newline at end of file +[sbt-dependency-graph](https://github.com/jrudolph/sbt-dependency-graph/) is an sbt plugin to visualize dependencies of your build. From d3cd49bd739e5199d4b6ac14b811367f9f597931 Mon Sep 17 00:00:00 2001 From: Matt Russell Date: Tue, 26 Jun 2012 08:06:06 +0100 Subject: [PATCH 044/252] Add support for ASCII-art dependency graphs --- build.sbt | 2 +- project.sbt | 7 ++++++- .../sbt/graph/IvyGraphMLDependencies.scala | 20 +++++++++++++++++-- .../net/virtualvoid/sbt/graph/Plugin.scala | 15 +++++++++++++- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/build.sbt b/build.sbt index bd07b2865..4518fef11 100644 --- a/build.sbt +++ b/build.sbt @@ -1,3 +1,3 @@ seq(lsSettings :_*) -CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12.0-Beta2") \ No newline at end of file +CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12.0-Beta2") diff --git a/project.sbt b/project.sbt index e38108c21..751b4e9ae 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.6.0" +version := "0.6.1-SNAPSHOT" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) @@ -16,3 +16,8 @@ licenses in GlobalScope += "Apache License 2.0" -> url("https://github.com/jrudo (description in LsKeys.lsync) := "An sbt plugin to visualize dependencies of your build." + +libraryDependencies += "com.github.mdr" %% "ascii-graphs" % "0.0.1-SNAPSHOT" + +resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots" + diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 95dc2b1f5..404ff5501 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -23,6 +23,8 @@ import collection.mutable.MultiMap import collection.mutable.{Set => MSet} import sbt.Graph import xml.{Document, XML, Node} +import com.github.mdr.ascii.layout +import com.github.mdr.ascii.layout._ object IvyGraphMLDependencies extends App { case class Module(organisation: String, name: String, version: String) { @@ -44,8 +46,22 @@ object IvyGraphMLDependencies extends App { ModuleGraph(nodes, edges) } - - def ascii(ivyReportFile: String): String = { + private def asciiGraph(moduleGraph: ModuleGraph): layout.Graph[String] = { + def renderVertex(module: Module): String = { + module.name + "\n" + module.organisation + "\n" + module.version + } + val vertices = moduleGraph.nodes.map(renderVertex).toList + val edges = moduleGraph.edges.toList.map { case (from, to) ⇒ (renderVertex(from), renderVertex(to)) } + layout.Graph(vertices, edges) + } + + def asciiGraph(ivyReportFile: String): String = { + val doc = buildDoc(ivyReportFile) + val graph = buildGraph(doc) + Layouter.renderGraph(asciiGraph(graph)) + } + + def asciiTree(ivyReportFile: String): String = { val doc = buildDoc(ivyReportFile) val graph = buildGraph(doc) import graph._ diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 9668c1507..425bff16c 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -28,6 +28,10 @@ object Plugin extends sbt.Plugin { "Returns a string containing the ascii representation of the dependency graph for a project") val dependencyGraph = TaskKey[Unit]("dependency-graph", "Prints the ascii graph to the console") + 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", + "Prints the ascii tree to the console") 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", @@ -44,12 +48,14 @@ object Plugin extends sbt.Plugin { ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(update), asciiGraph <<= asciiGraphTask, dependencyGraph <<= printAsciiGraphTask, + asciiTree <<= asciiTreeTask, + dependencyTree <<= printAsciiTreeTask, dependencyGraphMLFile <<= target / "dependencies-%s.graphml".format(config.toString), dependencyGraphML <<= dependencyGraphMLTask )) def asciiGraphTask = (ivyReport) map { report => - IvyGraphMLDependencies.ascii(report.getAbsolutePath) + IvyGraphMLDependencies.asciiGraph(report.getAbsolutePath) } def printAsciiGraphTask = @@ -62,6 +68,13 @@ object Plugin extends sbt.Plugin { resultFile } + def asciiTreeTask = (ivyReport) map { report => + IvyGraphMLDependencies.asciiTree(report.getAbsolutePath) + } + + def printAsciiTreeTask = + (streams, asciiTree) map (_.log.info(_)) + def crossName(ivyModule: IvySbt#Module) = ivyModule.moduleSettings match { case ic: InlineConfiguration => ic.module.name From f753a05be756f776b0450dc36e267e33e85ac041 Mon Sep 17 00:00:00 2001 From: Matt Russell Date: Wed, 27 Jun 2012 13:15:14 +0100 Subject: [PATCH 045/252] Use non SNAPSHOT version of ascii-graphs --- project.sbt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/project.sbt b/project.sbt index 751b4e9ae..3f863d442 100644 --- a/project.sbt +++ b/project.sbt @@ -17,7 +17,4 @@ licenses in GlobalScope += "Apache License 2.0" -> url("https://github.com/jrudo (description in LsKeys.lsync) := "An sbt plugin to visualize dependencies of your build." -libraryDependencies += "com.github.mdr" %% "ascii-graphs" % "0.0.1-SNAPSHOT" - -resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots" - +libraryDependencies += "com.github.mdr" %% "ascii-graphs" % "0.0.1" From 50e0c6ebfdf3b6de419920022aa20cbb15faaa7d Mon Sep 17 00:00:00 2001 From: Matt Russell Date: Sun, 1 Jul 2012 18:01:46 +0100 Subject: [PATCH 046/252] Bump ascii-graphs version to 0.0.2 --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index 3f863d442..5e3de20e0 100644 --- a/project.sbt +++ b/project.sbt @@ -17,4 +17,4 @@ licenses in GlobalScope += "Apache License 2.0" -> url("https://github.com/jrudo (description in LsKeys.lsync) := "An sbt plugin to visualize dependencies of your build." -libraryDependencies += "com.github.mdr" %% "ascii-graphs" % "0.0.1" +libraryDependencies += "com.github.mdr" %% "ascii-graphs" % "0.0.2" From 5ffd60c6c89302e233fd1e3033f6e5b58e8b1bdf Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 13 Jul 2012 11:32:23 +0300 Subject: [PATCH 047/252] Improve readme instructions. --- README.md | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 897b7f990..360050123 100644 --- a/README.md +++ b/README.md @@ -19,24 +19,20 @@ addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.6.0") *Note*: The organization has recently been changed to `net.virtual-void`. -or, alternatively, in `project/plugins/project/build.scala`: - -```scala -import sbt._ - -object Plugins extends Build { - lazy val root = Project("root", file(".")) dependsOn( - uri("git://github.com/jrudolph/sbt-dependency-graph.git#v0.6.0") // or another tag/branch/revision - ) -} -``` - -Then, add the following in your `build.sbt`: +Then, add the following to your `build.sbt` as a standalone line: ```scala net.virtualvoid.sbt.graph.Plugin.graphSettings ``` +or if you use the full configuration, add + +```scala +.settings(net.virtualvoid.sbt.graph.Plugin.graphSettings: _*) +``` + +to your project definition. + Tasks & Settings ---------------- From bfb9217f83ea91b5a156d13dc6ec5be79ae0ccfe Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 13 Jul 2012 11:35:30 +0300 Subject: [PATCH 048/252] Update master --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 360050123..9589c4fac 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.6.0") *Note*: The organization has recently been changed to `net.virtual-void`. -Then, add the following to your `build.sbt` as a standalone line: +Then, add the following to your `/build.sbt` (that's not `project/build.sbt`!) as a standalone line: ```scala net.virtualvoid.sbt.graph.Plugin.graphSettings From f4a2ae8ce54d3e1f08bf3b4242aa5903de959f8a Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 15 Jul 2012 11:54:00 +0300 Subject: [PATCH 049/252] remove build hive batch since that never worked --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9589c4fac..c719037d8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -sbt-dependency-graph [![Build Status](https://buildhive.cloudbees.com/job/jrudolph/job/sbt-dependency-graph/badge/icon)](https://buildhive.cloudbees.com/job/jrudolph/job/sbt-dependency-graph/) +sbt-dependency-graph ==================== Visualize your project's dependencies. From 814ae40ae8d81efc7d867a5213b61f4ab7dad6d8 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 15 Jul 2012 12:02:33 +0300 Subject: [PATCH 050/252] add some more usage info for multi-module projects --- README.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c719037d8..fc5380845 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,25 @@ Then, add the following to your `/build.sbt` (that's not `project/ net.virtualvoid.sbt.graph.Plugin.graphSettings ``` -or if you use the full configuration, add +OR, alternatively, if you use the full configuration, i.e. you define your build definition in `project/build.scala`, for example, +to define a multi-module project, you should add ```scala .settings(net.virtualvoid.sbt.graph.Plugin.graphSettings: _*) ``` -to your project definition. +to each of the project definitions for which you want to use the plugin. The definition of your project should then +look approximately this way: + +```scala +object MyBuild extends Build { + val proj = + Project("my-project", file("base")) + .settings(net.virtualvoid.sbt.graph.Plugin.graphSettings: _*) +} +``` + +Check out the [example project] for a skeleton build setup. Tasks & Settings ---------------- @@ -69,4 +81,6 @@ License Copyright (c) 2011, 2012 Johannes Rudolph -Published under the [Apache License 2.0](http://en.wikipedia.org/wiki/Apache_license). \ No newline at end of file +Published under the [Apache License 2.0](http://en.wikipedia.org/wiki/Apache_license). + +[example project]: https://gist.github.com/3106492 \ No newline at end of file From 6373970e4804bb03384ff1f288ed3dfb060ce329 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 27 Aug 2012 10:55:18 +0200 Subject: [PATCH 051/252] upgrade to latest ls-sbt --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index b429bf973..f62ba4ffc 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,6 +1,6 @@ resolvers += "less is" at "http://repo.lessis.me" -addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.1") +addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.2") resolvers += "Coda Hale's Repo" at "http://repo.codahale.com" From fc51b4c16bb8625ad5b472465991554c61ffe04c Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 27 Aug 2012 11:15:58 +0200 Subject: [PATCH 052/252] publish for 0.12, fixes #14 --- build.sbt | 2 +- project/plugins.sbt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index bd07b2865..d6481a771 100644 --- a/build.sbt +++ b/build.sbt @@ -1,3 +1,3 @@ seq(lsSettings :_*) -CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12.0-Beta2") \ No newline at end of file +CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12") \ No newline at end of file diff --git a/project/plugins.sbt b/project/plugins.sbt index f62ba4ffc..b30f5221d 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,4 +4,4 @@ addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.2") resolvers += "Coda Hale's Repo" at "http://repo.codahale.com" -addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.6.0") +addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.7.0-RC1") From 931ee96cd0ff570437569ca6815c50a5e1804187 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Thu, 18 Oct 2012 10:47:28 +0200 Subject: [PATCH 053/252] use sbt 0.12.1 --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index d4287112c..4474a03e1 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.11.3 +sbt.version=0.12.1 From 2ef694744cef1d38f21b5131c4893fddff065853 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 20 Oct 2012 12:53:32 +0200 Subject: [PATCH 054/252] fix #16: starting with sbt 0.12.1 the resolution files will be located at another position --- .../net/virtualvoid/sbt/graph/Plugin.scala | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 9668c1507..fa9286e1c 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -18,6 +18,7 @@ package net.virtualvoid.sbt.graph import sbt._ import Keys._ +import org.apache.ivy.core.resolve.ResolveOptions object Plugin extends sbt.Plugin { val dependencyGraphMLFile = SettingKey[File]("dependency-graph-ml-file", @@ -34,9 +35,17 @@ object Plugin extends sbt.Plugin { "A task which returns the location of the ivy report file for a given configuration (default `compile`).") def graphSettings = seq( - ivyReportFunction <<= (projectID, ivyModule, appConfiguration) map { (projectID, ivyModule, config) => - val home = config.provider.scalaProvider.launcher.ivyHome - (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c)) + ivyReportFunction <<= (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 >= 1) => + 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)) + } } ) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(ivyReportForConfig) @@ -68,4 +77,12 @@ object Plugin extends sbt.Plugin { case _ => throw new IllegalStateException("sbt-dependency-graph plugin currently only supports InlineConfiguration of ivy settings (the default in sbt)") } + + val VersionPattern = """(\d+)\.(\d+)\.(\d+)(?:-(.*))?""".r + object Version { + def unapplySeq(str: String): Option[(Int, Int, Int, Seq[String])] = str match { + case VersionPattern(major, minor, fix, appendix) => Some((major.toInt, minor.toInt, fix.toInt, Option(appendix).toSeq)) + case _ => None + } + } } \ No newline at end of file From aacb6530cee660a9142d67e014391c97dbabbf63 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 20 Oct 2012 12:56:56 +0200 Subject: [PATCH 055/252] use sbt-cross-building 0.7.0-RC2 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index b30f5221d..23bdc1cdb 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,4 +4,4 @@ addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.2") resolvers += "Coda Hale's Repo" at "http://repo.codahale.com" -addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.7.0-RC1") +addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.7.0-RC2") From dbf1f30d42f256180434be3a0731e7fa080bba96 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 20 Oct 2012 13:01:37 +0200 Subject: [PATCH 056/252] next version 0.6.1 --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index e38108c21..908dea47b 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.6.0" +version := "0.6.1-SNAPSHOT" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From d19dab955f95583df88c79f9d93e3412f58952e8 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 21 Oct 2012 11:05:50 +0200 Subject: [PATCH 057/252] use id as graph key instead of complete module --- .../net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 95dc2b1f5..cecb82785 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -50,14 +50,14 @@ object IvyGraphMLDependencies extends App { val graph = buildGraph(doc) import graph._ val deps = { - val m = new HashMap[Module, MSet[Module]] with MultiMap[Module, Module] - edges.foreach { case (from, to) => m.addBinding(from, to) } + val m = new HashMap[String, MSet[Module]] with MultiMap[String, Module] + edges.foreach { case (from, to) => m.addBinding(from.id, to) } m.toMap.mapValues(_.toSeq.sortBy(_.id)) } // there should only be one root node (the project itself) val roots = nodes.filter(n => !edges.exists(_._2 == n)).sortBy(_.id) roots.map(root => - Graph.toAscii[Module](root, node => deps.getOrElse(node, Seq.empty[Module]), _.id) + Graph.toAscii[Module](root, node => deps.getOrElse(node.id, Seq.empty[Module]), _.id) ).mkString("\n") } From bb98a5faca1bfdacf301458aa5155024d904c1cd Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 21 Oct 2012 11:35:42 +0200 Subject: [PATCH 058/252] fixes #17: don't fail if some artifacts are missing, show error in graph, tests --- build.sbt | 4 +++- .../net/virtualvoid/sbt/graph/Compat.scala | 20 +++++++++++++++++ .../net/virtualvoid/sbt/graph/Compat.scala | 22 +++++++++++++++++++ .../sbt/graph/IvyGraphMLDependencies.scala | 10 ++++----- .../net/virtualvoid/sbt/graph/Plugin.scala | 7 ++++-- .../showMissingUpdates/build.sbt | 19 ++++++++++++++++ .../showMissingUpdates/project/plugins.sbt | 1 + .../showMissingUpdates/test | 1 + 8 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 src/main/scala-sbt-0.11/net/virtualvoid/sbt/graph/Compat.scala create mode 100644 src/main/scala-sbt-0.12/net/virtualvoid/sbt/graph/Compat.scala create mode 100644 src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt create mode 100644 src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt create mode 100644 src/sbt-test/sbt-dependency-graph/showMissingUpdates/test diff --git a/build.sbt b/build.sbt index d6481a771..065e68569 100644 --- a/build.sbt +++ b/build.sbt @@ -1,3 +1,5 @@ seq(lsSettings :_*) -CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12") \ No newline at end of file +CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12") + +CrossBuilding.scriptedSettings diff --git a/src/main/scala-sbt-0.11/net/virtualvoid/sbt/graph/Compat.scala b/src/main/scala-sbt-0.11/net/virtualvoid/sbt/graph/Compat.scala new file mode 100644 index 000000000..d34e555f6 --- /dev/null +++ b/src/main/scala-sbt-0.11/net/virtualvoid/sbt/graph/Compat.scala @@ -0,0 +1,20 @@ +package net.virtualvoid.sbt.graph + +import sbt._ +import Keys._ + +import Plugin.ignoreMissingUpdate + +object Compat { + /** + * This is copied directly from sbt/main/Defaults.java and then changed to update the UpdateConfiguration + * to ignore missing artifacts. + */ + def ignoreMissingUpdateT = + ignoreMissingUpdate <<= (ivyModule, thisProjectRef, updateConfiguration, cacheDirectory, scalaInstance, transitiveUpdate, streams) map { (module, ref, config, cacheDirectory, si, reports, s) => + val depsUpdated = reports.exists(!_.stats.cached) + val missingOkConfig = new UpdateConfiguration(config.retrieve, true, config.logging) + + Classpaths.cachedUpdate(cacheDirectory / "update", Project.display(ref), module, missingOkConfig, Some(si), depsUpdated, s.log) + } +} \ No newline at end of file diff --git a/src/main/scala-sbt-0.12/net/virtualvoid/sbt/graph/Compat.scala b/src/main/scala-sbt-0.12/net/virtualvoid/sbt/graph/Compat.scala new file mode 100644 index 000000000..5bc770217 --- /dev/null +++ b/src/main/scala-sbt-0.12/net/virtualvoid/sbt/graph/Compat.scala @@ -0,0 +1,22 @@ +package net.virtualvoid.sbt.graph + +import sbt._ +import Keys._ + +import Plugin.ignoreMissingUpdate + +object Compat { + /** + * This is copied directly from sbt/main/Defaults.java and then changed to update the UpdateConfiguration + * to ignore missing artifacts. + */ + def ignoreMissingUpdateT = + ignoreMissingUpdate <<= (ivyModule, thisProjectRef, updateConfiguration, cacheDirectory, scalaInstance, transitiveUpdate, executionRoots, resolvedScoped, skip in update, streams) map { + (module, ref, config, cacheDirectory, si, reports, roots, resolved, skip, s) => + val depsUpdated = reports.exists(!_.stats.cached) + val isRoot = roots contains resolved + val missingOkConfig = new UpdateConfiguration(config.retrieve, true, config.logging) + + Classpaths.cachedUpdate(cacheDirectory / "update", Project.display(ref), module, missingOkConfig, Some(si), skip = skip, force = isRoot, depsUpdated = depsUpdated, log = s.log) + } tag(Tags.Update, Tags.Network) +} \ No newline at end of file diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index cecb82785..526a02ac5 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -25,7 +25,7 @@ import sbt.Graph import xml.{Document, XML, Node} object IvyGraphMLDependencies extends App { - case class Module(organisation: String, name: String, version: String) { + case class Module(organisation: String, name: String, version: String, error: Option[String] = None) { def id: String = organisation+":"+name+":"+version } @@ -36,7 +36,7 @@ object IvyGraphMLDependencies extends App { mod <- doc \ "dependencies" \ "module" caller <- mod \ "revision" \ "caller" callerModule = nodeFromElement(caller, caller.attribute("callerrev").get.text) - depModule = nodeFromElement(mod, caller.attribute("rev").get.text) + depModule = nodeFromElement(mod, caller.attribute("rev").get.text, (mod \ "revision").head.attribute("error").map(_.text)) } yield (callerModule, depModule) val nodes = edges.flatMap(e => Seq(e._1, e._2)).distinct @@ -57,7 +57,7 @@ object IvyGraphMLDependencies extends App { // there should only be one root node (the project itself) val roots = nodes.filter(n => !edges.exists(_._2 == n)).sortBy(_.id) roots.map(root => - Graph.toAscii[Module](root, node => deps.getOrElse(node.id, Seq.empty[Module]), _.id) + Graph.toAscii[Module](root, node => deps.getOrElse(node.id, Seq.empty[Module]), x => x.id + x.error.map(" (error: "+_+")").getOrElse("")) ).mkString("\n") } @@ -93,8 +93,8 @@ object IvyGraphMLDependencies extends App { XML.save(outputFile, xml) } - private def nodeFromElement(element: Node, version: String): Module = - Module(element.attribute("organisation").get.text, element.attribute("name").get.text, version) + private def nodeFromElement(element: Node, version: String, error: Option[String] = None): Module = + Module(element.attribute("organisation").get.text, element.attribute("name").get.text, version, error) private def buildDoc(ivyReportFile: String) = ConstructingParser.fromSource(io.Source.fromFile(ivyReportFile), false).document diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index fa9286e1c..fc37bc7fa 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -33,6 +33,8 @@ object Plugin extends sbt.Plugin { "A function which returns the file containing the ivy report from the ivy cache for a given configuration") 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 = TaskKey[UpdateReport]("update-ignore-missing", + "A copy of the update task which ignores missing artifacts") def graphSettings = seq( ivyReportFunction <<= (sbtVersion, target, projectID, ivyModule, appConfiguration, streams) map { (sbtV, target, projectID, ivyModule, config, streams) => @@ -50,11 +52,12 @@ object Plugin extends sbt.Plugin { ) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(ivyReportForConfig) def ivyReportForConfig(config: Configuration) = inConfig(config)(seq( - ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(update), + ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(ignoreMissingUpdate), asciiGraph <<= asciiGraphTask, dependencyGraph <<= printAsciiGraphTask, dependencyGraphMLFile <<= target / "dependencies-%s.graphml".format(config.toString), - dependencyGraphML <<= dependencyGraphMLTask + dependencyGraphML <<= dependencyGraphMLTask, + Compat.ignoreMissingUpdateT )) def asciiGraphTask = (ivyReport) map { report => diff --git a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt new file mode 100644 index 000000000..f610bcf02 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt @@ -0,0 +1,19 @@ +import net.virtualvoid.sbt.graph.Plugin._ + +graphSettings + +scalaVersion := "2.9.2" + +libraryDependencies += + "at.blub" % "blib" % "1.2.3" % "test" + +TaskKey[Unit]("check") <<= (ivyReport in Test, asciiGraph in Test) map { (report, graph) => + def sanitize(str: String): String = str.split('\n').drop(1).mkString("\n") + val expectedGraph = + """default:default-91180e_2.9.2:0.1-SNAPSHOT + | +-at.blub:blib:1.2.3 (error: not found) + | +-org.scala-lang:scala-library:2.9.2 + | """.stripMargin + require(sanitize(graph) == sanitize(expectedGraph), "Graph for report %s was '\n%s' but should have been '\n%s'" format (report, sanitize(graph), sanitize(expectedGraph))) + () +} diff --git a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt new file mode 100644 index 000000000..08b3f3d0a --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.6.1-SNAPSHOT") \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/test b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/test new file mode 100644 index 000000000..a5912a391 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/test @@ -0,0 +1 @@ +> check \ No newline at end of file From fb3d99e5e0b61464aa930fdec52fd101d1b889ab Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 21 Oct 2012 19:12:35 +0200 Subject: [PATCH 059/252] dry up graph structure generation and expose graph structure for other consumers as sbt `module-graph` task --- .../sbt/graph/IvyGraphMLDependencies.scala | 55 ++++++++----------- .../net/virtualvoid/sbt/graph/Plugin.scala | 27 ++++----- 2 files changed, 36 insertions(+), 46 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 84e6dff7e..cec856fbe 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -33,6 +33,9 @@ object IvyGraphMLDependencies extends App { case class ModuleGraph(nodes: Seq[Module], edges: Seq[(Module, Module)]) + def graph(ivyReportFile: String): ModuleGraph = + buildGraph(buildDoc(ivyReportFile)) + def buildGraph(doc: Document): ModuleGraph = { val edges = for { mod <- doc \ "dependencies" \ "module" @@ -46,7 +49,23 @@ object IvyGraphMLDependencies extends App { ModuleGraph(nodes, edges) } - private def asciiGraph(moduleGraph: ModuleGraph): layout.Graph[String] = { + def asciiGraph(graph: ModuleGraph): String = + Layouter.renderGraph(buildAsciiGraph(graph)) + + def asciiTree(graph: ModuleGraph): String = { + val deps = { + val m = new HashMap[String, MSet[Module]] with MultiMap[String, Module] + graph.edges.foreach { case (from, to) => m.addBinding(from.id, to) } + m.toMap.mapValues(_.toSeq.sortBy(_.id)) + } + // there should only be one root node (the project itself) + val roots = graph.nodes.filter(n => !graph.edges.exists(_._2 == n)).sortBy(_.id) + roots.map { root => + Graph.toAscii[Module](root, node => deps.getOrElse(node.id, Seq.empty[Module]), x => x.id + x.error.map(" (error: "+_+")").getOrElse("")) + }.mkString("\n") + } + + private def buildAsciiGraph(moduleGraph: ModuleGraph): layout.Graph[String] = { def renderVertex(module: Module): String = { module.name + "\n" + module.organisation + "\n" + module.version } @@ -55,35 +74,9 @@ object IvyGraphMLDependencies extends App { layout.Graph(vertices, edges) } - def asciiGraph(ivyReportFile: String): String = { - val doc = buildDoc(ivyReportFile) - val graph = buildGraph(doc) - Layouter.renderGraph(asciiGraph(graph)) - } - - def asciiTree(ivyReportFile: String): String = { - val doc = buildDoc(ivyReportFile) - val graph = buildGraph(doc) - import graph._ - val deps = { - val m = new HashMap[String, MSet[Module]] with MultiMap[String, Module] - edges.foreach { case (from, to) => m.addBinding(from.id, to) } - m.toMap.mapValues(_.toSeq.sortBy(_.id)) - } - // there should only be one root node (the project itself) - val roots = nodes.filter(n => !edges.exists(_._2 == n)).sortBy(_.id) - roots.map(root => - Graph.toAscii[Module](root, node => deps.getOrElse(node.id, Seq.empty[Module]), x => x.id + x.error.map(" (error: "+_+")").getOrElse("")) - ).mkString("\n") - } - - def transform(ivyReportFile: String, outputFile: String) { - val doc = buildDoc(ivyReportFile) - val graph = buildGraph(doc) - import graph._ - + def saveAsGraphML(graph: ModuleGraph, outputFile: String) { val nodesXml = - for (n <- nodes) + for (n <- graph.nodes) yield @@ -92,7 +85,7 @@ object IvyGraphMLDependencies extends App { val edgesXml = - for (e <- edges) + for (e <- graph.edges) yield val xml = @@ -123,5 +116,5 @@ object IvyGraphMLDependencies extends App { val file = args.lift(0).filter(f => new File(f).exists).getOrElse(die(usage)) val inputFile = args.lift(1).getOrElse(die(usage)) - transform(file, inputFile) + saveAsGraphML(graph(file), inputFile) } \ No newline at end of file diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 2a56851af..81227c62b 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -25,6 +25,8 @@ object Plugin extends sbt.Plugin { "The location the graphml file should be generated at") val dependencyGraphML = TaskKey[File]("dependency-graph-ml", "Creates a graphml file containing the dependency-graph for a project") + val moduleGraph = TaskKey[IvyGraphMLDependencies.ModuleGraph]("module-graph", + "The dependency graph for a project") val asciiGraph = TaskKey[String]("dependency-graph-string", "Returns a string containing the ascii representation of the dependency graph for a project") val dependencyGraph = TaskKey[Unit]("dependency-graph", @@ -57,35 +59,30 @@ object Plugin extends sbt.Plugin { def ivyReportForConfig(config: Configuration) = inConfig(config)(seq( ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(ignoreMissingUpdate), - asciiGraph <<= asciiGraphTask, - dependencyGraph <<= printAsciiGraphTask, - asciiTree <<= asciiTreeTask, - dependencyTree <<= printAsciiTreeTask, + moduleGraph <<= ivyReport map (absoluteReportPath.andThen(IvyGraphMLDependencies.graph)), + asciiGraph <<= moduleGraph map IvyGraphMLDependencies.asciiGraph, + dependencyGraph <<= print(asciiGraph), + asciiTree <<= moduleGraph map IvyGraphMLDependencies.asciiTree, + dependencyTree <<= print(asciiTree), dependencyGraphMLFile <<= target / "dependencies-%s.graphml".format(config.toString), dependencyGraphML <<= dependencyGraphMLTask, Compat.ignoreMissingUpdateT )) - def asciiGraphTask = (ivyReport) map { report => - IvyGraphMLDependencies.asciiGraph(report.getAbsolutePath) - } - def printAsciiGraphTask = (streams, asciiGraph) map (_.log.info(_)) def dependencyGraphMLTask = - (ivyReport, dependencyGraphMLFile, streams) map { (report, resultFile, streams) => - IvyGraphMLDependencies.transform(report.getAbsolutePath, resultFile.getAbsolutePath) + (moduleGraph, dependencyGraphMLFile, streams) map { (graph, resultFile, streams) => + IvyGraphMLDependencies.saveAsGraphML(graph, resultFile.getAbsolutePath) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } - def asciiTreeTask = (ivyReport) map { report => - IvyGraphMLDependencies.asciiTree(report.getAbsolutePath) - } + def absoluteReportPath = (file: File) => file.getAbsolutePath - def printAsciiTreeTask = - (streams, asciiTree) map (_.log.info(_)) + def print(key: TaskKey[String]) = + (streams, key) map (_.log.info(_)) def crossName(ivyModule: IvySbt#Module) = ivyModule.moduleSettings match { From 2fe1989322447607d2021c75bdca3d38e8df41cb Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 21 Oct 2012 19:41:42 +0200 Subject: [PATCH 060/252] automatically use `dependency-tree` for `dependency-graph` if there are too many nodes --- .../net/virtualvoid/sbt/graph/Plugin.scala | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 81227c62b..a5ec1adc3 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -18,6 +18,8 @@ package net.virtualvoid.sbt.graph import sbt._ import Keys._ +import complete.Parser + import org.apache.ivy.core.resolve.ResolveOptions object Plugin extends sbt.Plugin { @@ -29,7 +31,7 @@ object Plugin extends sbt.Plugin { "The dependency graph for a project") val asciiGraph = TaskKey[String]("dependency-graph-string", "Returns a string containing the ascii representation of the dependency graph for a project") - val dependencyGraph = TaskKey[Unit]("dependency-graph", + val dependencyGraph = InputKey[Unit]("dependency-graph", "Prints the ascii graph to the console") val asciiTree = TaskKey[String]("dependency-tree-string", "Returns a string containing an ascii tree representation of the dependency graph for a project") @@ -61,7 +63,20 @@ object Plugin extends sbt.Plugin { ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(ignoreMissingUpdate), moduleGraph <<= ivyReport map (absoluteReportPath.andThen(IvyGraphMLDependencies.graph)), asciiGraph <<= moduleGraph map IvyGraphMLDependencies.asciiGraph, - dependencyGraph <<= print(asciiGraph), + dependencyGraph <<= InputTask(parser) { force => + (force, moduleGraph, streams) map { (force, graph, streams) => + if (force || graph.nodes.size < 15) { + streams.log.info(IvyGraphMLDependencies.asciiGraph(graph)) + } else { + streams.log.info(IvyGraphMLDependencies.asciiTree(graph)) + + if (!force) { + streams.log.info("\n") + streams.log.info("Note: The graph was estimated to be too big to display (> 15 nodes). Use `dependency-graph --force` to force graph display.") + } + } + } + }, asciiTree <<= moduleGraph map IvyGraphMLDependencies.asciiTree, dependencyTree <<= print(asciiTree), dependencyGraphMLFile <<= target / "dependencies-%s.graphml".format(config.toString), @@ -84,6 +99,13 @@ object Plugin extends sbt.Plugin { def print(key: TaskKey[String]) = (streams, key) map (_.log.info(_)) + import Project._ + val parser: State => Parser[Boolean] = { (state: State) => + import complete.DefaultParsers._ + + (Space ~> token("--force")).?.map(_.isDefined) + } + def crossName(ivyModule: IvySbt#Module) = ivyModule.moduleSettings match { case ic: InlineConfiguration => ic.module.name From b5de4e9683912d39b264fbbffd406c49a63d99e0 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 21 Oct 2012 19:42:04 +0200 Subject: [PATCH 061/252] fixes #8: show hint where to find the old `dependency-graph` implementation --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index a5ec1adc3..f96c35044 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -67,6 +67,8 @@ object Plugin extends sbt.Plugin { (force, moduleGraph, streams) map { (force, graph, streams) => if (force || graph.nodes.size < 15) { streams.log.info(IvyGraphMLDependencies.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(IvyGraphMLDependencies.asciiTree(graph)) From 4d705ed256b051b75ee6ab5a023f3b5368d61e4b Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 21 Oct 2012 19:45:11 +0200 Subject: [PATCH 062/252] refactoring --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index f96c35044..d3c831d48 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -63,7 +63,7 @@ object Plugin extends sbt.Plugin { ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(ignoreMissingUpdate), moduleGraph <<= ivyReport map (absoluteReportPath.andThen(IvyGraphMLDependencies.graph)), asciiGraph <<= moduleGraph map IvyGraphMLDependencies.asciiGraph, - dependencyGraph <<= InputTask(parser) { force => + dependencyGraph <<= InputTask(shouldForceParser) { force => (force, moduleGraph, streams) map { (force, graph, streams) => if (force || graph.nodes.size < 15) { streams.log.info(IvyGraphMLDependencies.asciiGraph(graph)) @@ -102,7 +102,7 @@ object Plugin extends sbt.Plugin { (streams, key) map (_.log.info(_)) import Project._ - val parser: State => Parser[Boolean] = { (state: State) => + val shouldForceParser: State => Parser[Boolean] = { (state: State) => import complete.DefaultParsers._ (Space ~> token("--force")).?.map(_.isDefined) From 5a051f6a3a68de29b3e2d1cc1318be63e4ea8e98 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Oct 2012 09:28:32 +0200 Subject: [PATCH 063/252] refs #7: add new `what-depends-on` task to find out the reverse dependencies of a module --- .../sbt/graph/IvyGraphMLDependencies.scala | 59 ++++++++++++++++--- .../net/virtualvoid/sbt/graph/Plugin.scala | 36 +++++++++++ 2 files changed, 87 insertions(+), 8 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index cec856fbe..45527b303 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -25,13 +25,31 @@ import sbt.Graph import xml.{Document, XML, Node} import com.github.mdr.ascii.layout import layout._ +import sbinary.{CollectionTypes, Format, DefaultProtocol} object IvyGraphMLDependencies extends App { case class Module(organisation: String, name: String, version: String, error: Option[String] = None) { def id: String = organisation+":"+name+":"+version + + override def hashCode(): Int = id.hashCode + override def equals(p1: Any): Boolean = p1 match { + case m: Module => id == m.id + case _ => false + } } - case class ModuleGraph(nodes: Seq[Module], edges: Seq[(Module, Module)]) + case class ModuleGraph(nodes: Seq[Module], edges: Seq[(Module, Module)]) { + lazy val dependencyMap: Map[Module, Seq[Module]] = { + val m = new HashMap[Module, MSet[Module]] with MultiMap[Module, Module] + edges.foreach { case (from, to) => m.addBinding(from, to) } + m.toMap.mapValues(_.toSeq.sortBy(_.id)) + } + lazy val reverseDependencyMap: Map[Module, Seq[Module]] = { + val m = new HashMap[Module, MSet[Module]] with MultiMap[Module, Module] + edges.foreach { case (from, to) => m.addBinding(to, from) } + m.toMap.mapValues(_.toSeq.sortBy(_.id)) + } + } def graph(ivyReportFile: String): ModuleGraph = buildGraph(buildDoc(ivyReportFile)) @@ -49,19 +67,36 @@ object IvyGraphMLDependencies extends App { ModuleGraph(nodes, edges) } + def reverseGraphStartingAt(graph: ModuleGraph, root: Module): ModuleGraph = { + val deps = graph.reverseDependencyMap + + def visit(module: Module, visited: Set[Module]): Seq[(Module, Module)] = + if (visited(module)) + Nil + else + deps.get(module) match { + case Some(deps) => + deps.flatMap { to => + (module, to) +: visit(to, visited + module) + } + case None => Nil + } + + val edges = visit(root, Set.empty) + val nodes = edges.foldLeft(Set.empty[Module])((set, edge) => set + edge._1 + edge._2) + ModuleGraph(nodes.toSeq, edges) + } + def asciiGraph(graph: ModuleGraph): String = Layouter.renderGraph(buildAsciiGraph(graph)) def asciiTree(graph: ModuleGraph): String = { - val deps = { - val m = new HashMap[String, MSet[Module]] with MultiMap[String, Module] - graph.edges.foreach { case (from, to) => m.addBinding(from.id, to) } - m.toMap.mapValues(_.toSeq.sortBy(_.id)) - } + val deps = graph.dependencyMap + // there should only be one root node (the project itself) val roots = graph.nodes.filter(n => !graph.edges.exists(_._2 == n)).sortBy(_.id) roots.map { root => - Graph.toAscii[Module](root, node => deps.getOrElse(node.id, Seq.empty[Module]), x => x.id + x.error.map(" (error: "+_+")").getOrElse("")) + Graph.toAscii[Module](root, node => deps.getOrElse(node, Seq.empty[Module]), x => x.id + x.error.map(" (error: "+_+")").getOrElse("")) }.mkString("\n") } @@ -117,4 +152,12 @@ object IvyGraphMLDependencies extends App { val file = args.lift(0).filter(f => new File(f).exists).getOrElse(die(usage)) val inputFile = args.lift(1).getOrElse(die(usage)) saveAsGraphML(graph(file), inputFile) -} \ No newline at end of file +} + +object ModuleGraphProtocol extends DefaultProtocol { + import IvyGraphMLDependencies._ + + implicit def seqFormat[T: Format]: Format[Seq[T]] = wrap[Seq[T], List[T]](_.toList, _.toSeq) + implicit val ModuleFormat: Format[Module] = asProduct4(Module)(Module.unapply(_).get) + implicit val ModuleGraphFormat: Format[ModuleGraph] = asProduct2(ModuleGraph)(ModuleGraph.unapply(_).get) +} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index d3c831d48..d516c4659 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -21,6 +21,7 @@ import Keys._ import complete.Parser import org.apache.ivy.core.resolve.ResolveOptions +import net.virtualvoid.sbt.graph.IvyGraphMLDependencies.ModuleGraph object Plugin extends sbt.Plugin { val dependencyGraphMLFile = SettingKey[File]("dependency-graph-ml-file", @@ -44,6 +45,12 @@ object Plugin extends sbt.Plugin { val ignoreMissingUpdate = TaskKey[UpdateReport]("update-ignore-missing", "A copy of the update task which ignores missing artifacts") + // internal + import ModuleGraphProtocol._ + val moduleGraphStore = TaskKey[IvyGraphMLDependencies.ModuleGraph]("module-graph-store", "The stored module-graph from the last run") + + val whatDependsOn = InputKey[Unit]("what-depends-on", "Shows information about what depends on the given module") + def graphSettings = seq( ivyReportFunction <<= (sbtVersion, target, projectID, ivyModule, appConfiguration, streams) map { (sbtV, target, projectID, ivyModule, config, streams) => sbtV match { @@ -62,6 +69,7 @@ object Plugin extends sbt.Plugin { def ivyReportForConfig(config: Configuration) = inConfig(config)(seq( ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(ignoreMissingUpdate), moduleGraph <<= ivyReport map (absoluteReportPath.andThen(IvyGraphMLDependencies.graph)), + moduleGraphStore <<= moduleGraph storeAs moduleGraphStore triggeredBy moduleGraph, asciiGraph <<= moduleGraph map IvyGraphMLDependencies.asciiGraph, dependencyGraph <<= InputTask(shouldForceParser) { force => (force, moduleGraph, streams) map { (force, graph, streams) => @@ -83,6 +91,11 @@ object Plugin extends sbt.Plugin { dependencyTree <<= print(asciiTree), dependencyGraphMLFile <<= target / "dependencies-%s.graphml".format(config.toString), dependencyGraphML <<= dependencyGraphMLTask, + whatDependsOn <<= InputTask(artifactIdParser) { module => + (module, streams, moduleGraph) map { (module, streams, graph) => + streams.log.info(IvyGraphMLDependencies.asciiTree(IvyGraphMLDependencies.reverseGraphStartingAt(graph, module))) + } + }, Compat.ignoreMissingUpdateT )) @@ -108,6 +121,29 @@ object Plugin extends sbt.Plugin { (Space ~> token("--force")).?.map(_.isDefined) } + import IvyGraphMLDependencies.Module + + val artifactIdParser: Initialize[State => Parser[Module]] = + resolvedScoped { ctx => (state: State) => + val graph = loadFromContext(moduleGraphStore, ctx, state) getOrElse ModuleGraph(Nil, Nil) + + import complete.DefaultParsers._ + + def moduleFrom(modules: Seq[Module]) = + modules.map { m => + (token(m.name) ~ Space ~ token(m.version)).map(_ => m) + }.reduce(_ | _) + + graph.nodes.groupBy(_.organisation).map { + case (org, modules) => + Space ~ token(org) ~ Space ~> moduleFrom(modules) + }.reduceOption(_ | _).getOrElse { + (Space ~> token(StringBasic, "organization") ~ Space ~ token(StringBasic, "module") ~ Space ~ token(StringBasic, "version") ).map { case ((((org, _), mod), _), version) => + Module(org, mod, version) + } + } + } + def crossName(ivyModule: IvySbt#Module) = ivyModule.moduleSettings match { case ic: InlineConfiguration => ic.module.name From cb3fc03dbc53a5faffc3c379503a7bf4d4769588 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Oct 2012 10:01:40 +0200 Subject: [PATCH 064/252] fix: correctly associated error with module revision --- .../net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 45527b303..41ae123b1 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -57,9 +57,10 @@ object IvyGraphMLDependencies extends App { def buildGraph(doc: Document): ModuleGraph = { val edges = for { mod <- doc \ "dependencies" \ "module" - caller <- mod \ "revision" \ "caller" + revision <- mod \ "revision" + caller <- revision \ "caller" callerModule = nodeFromElement(caller, caller.attribute("callerrev").get.text) - depModule = nodeFromElement(mod, caller.attribute("rev").get.text, (mod \ "revision").head.attribute("error").map(_.text)) + depModule = nodeFromElement(mod, revision.attribute("name").get.text, revision.attribute("error").map(_.text)) } yield (callerModule, depModule) val nodes = edges.flatMap(e => Seq(e._1, e._2)).distinct From 83ac2e62ab5bb81218c8fe1cd63c5963cc1f2e55 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Oct 2012 10:03:47 +0200 Subject: [PATCH 065/252] refs #17: color errors red in tree output --- .../sbt/graph/IvyGraphMLDependencies.scala | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 41ae123b1..844310f94 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -21,16 +21,18 @@ import java.io.File import collection.mutable.HashMap import collection.mutable.MultiMap import collection.mutable.{Set => MSet} -import sbt.Graph +import sbt.{ConsoleLogger, Graph} import xml.{Document, XML, Node} import com.github.mdr.ascii.layout import layout._ -import sbinary.{CollectionTypes, Format, DefaultProtocol} +import sbinary.{Format, DefaultProtocol} object IvyGraphMLDependencies extends App { case class Module(organisation: String, name: String, version: String, error: Option[String] = None) { def id: String = organisation+":"+name+":"+version + def hadError: Boolean = error.isDefined + override def hashCode(): Int = id.hashCode override def equals(p1: Any): Boolean = p1 match { case m: Module => id == m.id @@ -97,14 +99,17 @@ object IvyGraphMLDependencies extends App { // there should only be one root node (the project itself) val roots = graph.nodes.filter(n => !graph.edges.exists(_._2 == n)).sortBy(_.id) roots.map { root => - Graph.toAscii[Module](root, node => deps.getOrElse(node, Seq.empty[Module]), x => x.id + x.error.map(" (error: "+_+")").getOrElse("")) + Graph.toAscii[Module](root, node => deps.getOrElse(node, Seq.empty[Module]), displayModule) }.mkString("\n") } + def displayModule(module: Module): String = + red(module.id + module.error.map(" (error: "+_+")").getOrElse(""), module.hadError) + private def buildAsciiGraph(moduleGraph: ModuleGraph): layout.Graph[String] = { - def renderVertex(module: Module): String = { + def renderVertex(module: Module): String = module.name + "\n" + module.organisation + "\n" + module.version - } + val vertices = moduleGraph.nodes.map(renderVertex).toList val edges = moduleGraph.edges.toList.map { case (from, to) ⇒ (renderVertex(from), renderVertex(to)) } layout.Graph(vertices, edges) @@ -143,6 +148,12 @@ object IvyGraphMLDependencies extends App { private def buildDoc(ivyReportFile: String) = ConstructingParser.fromSource(io.Source.fromFile(ivyReportFile), false).document + def red(str: String, doRed: Boolean): String = + if (ConsoleLogger.formatEnabled && doRed) + Console.RED + str + Console.RESET + else + str + def die(msg: String): Nothing = { println(msg) sys.exit(1) From 9d1087347e4caf2f6e2c7433981e2cf104a0a8aa Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Oct 2012 10:07:37 +0200 Subject: [PATCH 066/252] refs #17: show errors in graph output as well --- .../net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 844310f94..6364a004f 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -108,7 +108,7 @@ object IvyGraphMLDependencies extends App { private def buildAsciiGraph(moduleGraph: ModuleGraph): layout.Graph[String] = { def renderVertex(module: Module): String = - module.name + "\n" + module.organisation + "\n" + module.version + module.name + "\n" + module.organisation + "\n" + module.version + module.error.map("\nerror: "+_).getOrElse("") val vertices = moduleGraph.nodes.map(renderVertex).toList val edges = moduleGraph.edges.toList.map { case (from, to) ⇒ (renderVertex(from), renderVertex(to)) } From 11f56d0d165f1df507c0747bf3f8fe4fa7059834 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Oct 2012 10:19:52 +0200 Subject: [PATCH 067/252] notes for upcoming 0.7.0 --- notes/0.7.0.markdown | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 notes/0.7.0.markdown diff --git a/notes/0.7.0.markdown b/notes/0.7.0.markdown new file mode 100644 index 000000000..ce1209d10 --- /dev/null +++ b/notes/0.7.0.markdown @@ -0,0 +1,9 @@ +New features in this version: + + * `dependency-graph` now renders a real graph. Many 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. + * Works with sbt 0.12.1. The ivy report files were moved to a new location making an update necessary. + From 13d57021239994fdf3a5853191c1018ef640819e Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Oct 2012 10:21:57 +0200 Subject: [PATCH 068/252] fix scripted test --- .../sbt-dependency-graph/showMissingUpdates/build.sbt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt index f610bcf02..213719040 100644 --- a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt +++ b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt @@ -7,13 +7,13 @@ scalaVersion := "2.9.2" libraryDependencies += "at.blub" % "blib" % "1.2.3" % "test" -TaskKey[Unit]("check") <<= (ivyReport in Test, asciiGraph in Test) map { (report, graph) => +TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, graph) => def sanitize(str: String): String = str.split('\n').drop(1).mkString("\n") val expectedGraph = """default:default-91180e_2.9.2:0.1-SNAPSHOT - | +-at.blub:blib:1.2.3 (error: not found) + | +-%sat.blub:blib:1.2.3 (error: not found)%s | +-org.scala-lang:scala-library:2.9.2 - | """.stripMargin + | """.stripMargin.format(scala.Console.RED, scala.Console.RESET) require(sanitize(graph) == sanitize(expectedGraph), "Graph for report %s was '\n%s' but should have been '\n%s'" format (report, sanitize(graph), sanitize(expectedGraph))) () } From 83fe4f296013fa8f14ee1f443fd3aa7b4ac5c0aa Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Oct 2012 10:30:10 +0200 Subject: [PATCH 069/252] better variable names --- .../net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 6364a004f..329cd2bdc 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -161,9 +161,9 @@ object IvyGraphMLDependencies extends App { def usage: String = "Usage: " - val file = args.lift(0).filter(f => new File(f).exists).getOrElse(die(usage)) - val inputFile = args.lift(1).getOrElse(die(usage)) - saveAsGraphML(graph(file), inputFile) + val reportFile = args.lift(0).filter(f => new File(f).exists).getOrElse(die(usage)) + val outputFile = args.lift(1).getOrElse(die(usage)) + saveAsGraphML(graph(reportFile), outputFile) } object ModuleGraphProtocol extends DefaultProtocol { From d7f18e053cce7ed91ce22ca99489b9871b1453e1 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Oct 2012 10:30:22 +0200 Subject: [PATCH 070/252] prepare readme for 0.7.0 --- README.md | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index fc5380845..f8eb74b2d 100644 --- a/README.md +++ b/README.md @@ -3,30 +3,23 @@ sbt-dependency-graph Visualize your project's dependencies. -Requirements ------------- - -* Simple Build Tool - How To Use ---------- -For sbt 0.11, add sbt-dependency-graph as a dependency in `project/plugins.sbt`: +For sbt 0.11/0.12, add sbt-dependency-graph as a dependency in `project/plugins.sbt`: ```scala -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.6.0") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.0") ``` -*Note*: The organization has recently been changed to `net.virtual-void`. - Then, add the following to your `/build.sbt` (that's not `project/build.sbt`!) as a standalone line: ```scala net.virtualvoid.sbt.graph.Plugin.graphSettings ``` -OR, alternatively, if you use the full configuration, i.e. you define your build definition in `project/build.scala`, for example, -to define a multi-module project, you should add +OR, alternatively, if you use the full configuration, i.e. you define your build definition in `project/build.scala`, for example, +to define a multi-module project, you should add ```scala .settings(net.virtualvoid.sbt.graph.Plugin.graphSettings: _*) @@ -37,7 +30,7 @@ look approximately this way: ```scala object MyBuild extends Build { - val proj = + val proj = Project("my-project", file("base")) .settings(net.virtualvoid.sbt.graph.Plugin.graphSettings: _*) } @@ -48,9 +41,12 @@ Check out the [example project] for a skeleton build setup. Tasks & Settings ---------------- - * `dependency-graph`: Shows an ASCII graph of your dependency on the sbt console - * `dependency-graph-ml`: Generates a .graphml file with your dependencies to `target/dependencies-.graphml`. + * `dependency-graph`: Shows an ASCII graph of the project's dependencies on the sbt console + * `dependency-graph-ml`: Generates a .graphml file with the project's dependencies to `target/dependencies-.graphml`. Use e.g. [yEd](http://www.yworks.com/en/products_yed_about.html) to format the graph to your needs. + * `dependency-tree`: Shows an ASCII tree representation of the project's dependencies + * `what-depends-on `: Find out what depends on an artifact. Shows a reverse dependency + tree for the selected module. * `dependency-graph-ml-file`: a setting which allows configuring the output path of `dependency-graph-ml`. * `ivy-report`: let's ivy generate the resolution report for you project. Use `show ivy-report` for the filename of the generated report @@ -63,19 +59,24 @@ Standalone usage ---------------- You can use the project without sbt as well by either depending on the library and calling -`IvyGraphMLDependencies.transfrom(sourceIvyReport, targetFile)` or by just getting the binary -and calling it like `scala sbt-dependency-graph-0.5.1.jar `. - +`IvyGraphMLDependencies.saveAsGraphML(IvyGraphMLDependencies.graph(reportFile), outputFile)` or by just getting the binary +and calling it like `scala sbt-dependency-graph-0.7.0.jar `. Inner Workings -------------- -sbt/Ivy's `update` task create ivy-report xml-files inside `.ivy2/cache`. You can +sbt/Ivy's `update` task create ivy-report xml-files inside `.ivy2/cache` (in sbt 0.12.1: +`/target/resolution-cache/reports/`. You can just open them with your browser to look at the dependency report for your project. This project takes the report xml of your project and creates a graphml file out of it. (BTW, ivy can create graphml files itself, but since I didn't want to spend to much time getting sbt to call into Ivy to create graphs, I went with the easy way here) +Credits +------- + + * Matt Russell (@mdr) for contributing the ASCII graph layout. + License ------- From bcd3f13a0d7db00194f45443ce9641405ca8bf0c Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Oct 2012 10:31:12 +0200 Subject: [PATCH 071/252] bump version to 0.7.0-RC1 --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index 908dea47b..56595b039 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.6.1-SNAPSHOT" +version := "0.7.0-RC1" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From 12fbac687f51cd051efa86056520d0070418c02e Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Oct 2012 10:38:37 +0200 Subject: [PATCH 072/252] need some compatibility parsing infrastructure for 0.11.x --- src/main/scala-sbt-0.11/net/virtualvoid/sbt/graph/Compat.scala | 3 +++ src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 1 + 2 files changed, 4 insertions(+) diff --git a/src/main/scala-sbt-0.11/net/virtualvoid/sbt/graph/Compat.scala b/src/main/scala-sbt-0.11/net/virtualvoid/sbt/graph/Compat.scala index d34e555f6..7b1a7e0f9 100644 --- a/src/main/scala-sbt-0.11/net/virtualvoid/sbt/graph/Compat.scala +++ b/src/main/scala-sbt-0.11/net/virtualvoid/sbt/graph/Compat.scala @@ -17,4 +17,7 @@ object Compat { Classpaths.cachedUpdate(cacheDirectory / "update", Project.display(ref), module, missingOkConfig, Some(si), depsUpdated, s.log) } + + import complete.DefaultParsers._ + lazy val StringBasic = NotSpaceClass.*.string } \ No newline at end of file diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index d516c4659..a43618473 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -128,6 +128,7 @@ object Plugin extends sbt.Plugin { val graph = loadFromContext(moduleGraphStore, ctx, state) getOrElse ModuleGraph(Nil, Nil) import complete.DefaultParsers._ + import Compat._ def moduleFrom(modules: Seq[Module]) = modules.map { m => From 6580fb59f3c80efdf39c5336d325ee84195133d9 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 23 Oct 2012 11:26:11 +0200 Subject: [PATCH 073/252] proper distinction between what is a moduleid and what is extra module info fixes #18: filter revisions per caller and evtl. display eviction info --- notes/0.7.0.markdown | 1 + .../sbt/graph/IvyGraphMLDependencies.scala | 110 +++++++++++------- .../net/virtualvoid/sbt/graph/Plugin.scala | 10 +- 3 files changed, 74 insertions(+), 47 deletions(-) diff --git a/notes/0.7.0.markdown b/notes/0.7.0.markdown index ce1209d10..a4e96c1a4 100644 --- a/notes/0.7.0.markdown +++ b/notes/0.7.0.markdown @@ -5,5 +5,6 @@ New features in this version: * 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. * Works with sbt 0.12.1. The ivy report files were moved to a new location making an update necessary. diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 329cd2bdc..b817da7db 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -22,34 +22,40 @@ import collection.mutable.HashMap import collection.mutable.MultiMap import collection.mutable.{Set => MSet} import sbt.{ConsoleLogger, Graph} -import xml.{Document, XML, Node} +import xml.{NodeSeq, Document, XML, Node} import com.github.mdr.ascii.layout import layout._ import sbinary.{Format, DefaultProtocol} object IvyGraphMLDependencies extends App { - case class Module(organisation: String, name: String, version: String, error: Option[String] = None) { - def id: String = organisation+":"+name+":"+version - + case class ModuleId(organisation: String, + name: String, + version: String) { + def idString: String = organisation+":"+name+":"+version + } + case class Module(id: ModuleId, + evictedByVersion: Option[String] = None, + error: Option[String] = None) { def hadError: Boolean = error.isDefined - - override def hashCode(): Int = id.hashCode - override def equals(p1: Any): Boolean = p1 match { - case m: Module => id == m.id - case _ => false - } } - case class ModuleGraph(nodes: Seq[Module], edges: Seq[(Module, Module)]) { - lazy val dependencyMap: Map[Module, Seq[Module]] = { - val m = new HashMap[Module, MSet[Module]] with MultiMap[Module, Module] - edges.foreach { case (from, to) => m.addBinding(from, to) } - m.toMap.mapValues(_.toSeq.sortBy(_.id)) + type Edge = (ModuleId, ModuleId) + + case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) { + lazy val modules: Map[ModuleId, Module] = + nodes.map(n => (n.id, n)).toMap + + def module(id: ModuleId): Module = modules(id) + + lazy val dependencyMap: Map[ModuleId, Seq[Module]] = { + val m = new HashMap[ModuleId, MSet[Module]] with MultiMap[ModuleId, Module] + edges.foreach { case (from, to) => m.addBinding(from, module(to)) } + m.toMap.mapValues(_.toSeq.sortBy(_.id.idString)) } - lazy val reverseDependencyMap: Map[Module, Seq[Module]] = { - val m = new HashMap[Module, MSet[Module]] with MultiMap[Module, Module] - edges.foreach { case (from, to) => m.addBinding(to, from) } - m.toMap.mapValues(_.toSeq.sortBy(_.id)) + lazy val reverseDependencyMap: Map[ModuleId, Seq[Module]] = { + val m = new HashMap[ModuleId, MSet[Module]] with MultiMap[ModuleId, Module] + edges.foreach { case (from, to) => m.addBinding(to, module(from)) } + m.toMap.mapValues(_.toSeq.sortBy(_.id.idString)) } } @@ -57,36 +63,49 @@ object IvyGraphMLDependencies extends App { buildGraph(buildDoc(ivyReportFile)) def buildGraph(doc: Document): ModuleGraph = { - val edges = for { - mod <- doc \ "dependencies" \ "module" + def edgesForModule(id: ModuleId, revision: NodeSeq, rev: String): Seq[Edge] = + for { + caller <- revision \ "caller" if caller.attribute("rev").get.text == rev + callerModule = moduleIdFromElement(caller, caller.attribute("callerrev").get.text) + } yield (moduleIdFromElement(caller, caller.attribute("callerrev").get.text), id) + + val moduleEdges: Seq[(Module, Seq[Edge])] = for { + mod <- doc \ "dependencies" \ "module" revision <- mod \ "revision" - caller <- revision \ "caller" - callerModule = nodeFromElement(caller, caller.attribute("callerrev").get.text) - depModule = nodeFromElement(mod, revision.attribute("name").get.text, revision.attribute("error").map(_.text)) - } yield (callerModule, depModule) + rev = revision.attribute("name").get.text + moduleId = moduleIdFromElement(mod, rev) + module = Module(moduleId, + evictedByVersion = (revision \ "evicted-by").headOption.flatMap(_.attribute("rev").map(_.text)), + error = revision.attribute("error").map(_.text)) + } yield (module, edgesForModule(moduleId, revision, rev)) - val nodes = edges.flatMap(e => Seq(e._1, e._2)).distinct + val (nodes, edges) = moduleEdges.unzip - ModuleGraph(nodes, edges) + val info = (doc \ "info").head + def infoAttr(name: String): String = + info.attribute(name).getOrElse(throw new IllegalArgumentException("Missing attribute "+name)).text + val rootModule = Module(ModuleId(infoAttr("organisation"), infoAttr("module"), infoAttr("revision"))) + + ModuleGraph(rootModule +: nodes, edges.flatten) } - def reverseGraphStartingAt(graph: ModuleGraph, root: Module): ModuleGraph = { + def reverseGraphStartingAt(graph: ModuleGraph, root: ModuleId): ModuleGraph = { val deps = graph.reverseDependencyMap - def visit(module: Module, visited: Set[Module]): Seq[(Module, Module)] = + def visit(module: ModuleId, visited: Set[ModuleId]): Seq[(ModuleId, ModuleId)] = if (visited(module)) Nil else deps.get(module) match { case Some(deps) => deps.flatMap { to => - (module, to) +: visit(to, visited + module) + (module, to.id) +: visit(to.id, visited + module) } case None => Nil } val edges = visit(root, Set.empty) - val nodes = edges.foldLeft(Set.empty[Module])((set, edge) => set + edge._1 + edge._2) + val nodes = edges.foldLeft(Set.empty[ModuleId])((set, edge) => set + edge._1 + edge._2).map(graph.module) ModuleGraph(nodes.toSeq, edges) } @@ -97,21 +116,27 @@ object IvyGraphMLDependencies extends App { val deps = graph.dependencyMap // there should only be one root node (the project itself) - val roots = graph.nodes.filter(n => !graph.edges.exists(_._2 == n)).sortBy(_.id) + val roots = graph.nodes.filter(n => !graph.edges.exists(_._2 == n.id)).sortBy(_.id.idString) roots.map { root => - Graph.toAscii[Module](root, node => deps.getOrElse(node, Seq.empty[Module]), displayModule) + Graph.toAscii[Module](root, node => deps.getOrElse(node.id, Seq.empty[Module]), displayModule) }.mkString("\n") } def displayModule(module: Module): String = - red(module.id + module.error.map(" (error: "+_+")").getOrElse(""), module.hadError) + red(module.id.idString + + module.error.map(" (error: "+_+")").getOrElse("") + + module.evictedByVersion.map(_ formatted " (evicted by: %s)").getOrElse(""), module.hadError) private def buildAsciiGraph(moduleGraph: ModuleGraph): layout.Graph[String] = { def renderVertex(module: Module): String = - module.name + "\n" + module.organisation + "\n" + module.version + module.error.map("\nerror: "+_).getOrElse("") + module.id.name + "\n" + + module.id.organisation + "\n" + + module.id.version + + module.error.map("\nerror: "+_).getOrElse("") + + module.evictedByVersion.map(_ formatted "\nevicted by: %s").getOrElse("") val vertices = moduleGraph.nodes.map(renderVertex).toList - val edges = moduleGraph.edges.toList.map { case (from, to) ⇒ (renderVertex(from), renderVertex(to)) } + val edges = moduleGraph.edges.toList.map { case (from, to) ⇒ (renderVertex(moduleGraph.module(from)), renderVertex(moduleGraph.module(to))) } layout.Graph(vertices, edges) } @@ -119,15 +144,15 @@ object IvyGraphMLDependencies extends App { val nodesXml = for (n <- graph.nodes) yield - + - {n.id} + {n.id.idString} val edgesXml = for (e <- graph.edges) - yield + yield val xml = token("--force")).?.map(_.isDefined) } - import IvyGraphMLDependencies.Module + import IvyGraphMLDependencies.ModuleId - val artifactIdParser: Initialize[State => Parser[Module]] = + val artifactIdParser: Initialize[State => Parser[ModuleId]] = resolvedScoped { ctx => (state: State) => val graph = loadFromContext(moduleGraphStore, ctx, state) getOrElse ModuleGraph(Nil, Nil) import complete.DefaultParsers._ import Compat._ - def moduleFrom(modules: Seq[Module]) = + def moduleFrom(modules: Seq[ModuleId]) = modules.map { m => (token(m.name) ~ Space ~ token(m.version)).map(_ => m) }.reduce(_ | _) - graph.nodes.groupBy(_.organisation).map { + graph.nodes.map(_.id).groupBy(_.organisation).map { case (org, modules) => Space ~ token(org) ~ Space ~> moduleFrom(modules) }.reduceOption(_ | _).getOrElse { (Space ~> token(StringBasic, "organization") ~ Space ~ token(StringBasic, "module") ~ Space ~ token(StringBasic, "version") ).map { case ((((org, _), mod), _), version) => - Module(org, mod, version) + ModuleId(org, mod, version) } } } From 1a20eee73cfecb46232a3cffff92e695ce061551 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 23 Oct 2012 11:37:50 +0200 Subject: [PATCH 074/252] bump version to 0.7.0-RC2 --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index 56595b039..41b84a546 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.7.0-RC1" +version := "0.7.0-RC2" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From eb54e20c562c146d95dde2a6ebe86aa4849fae58 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 10:37:06 +0200 Subject: [PATCH 075/252] whitespace --- .../net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index b817da7db..36c5819ef 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -29,8 +29,8 @@ import sbinary.{Format, DefaultProtocol} object IvyGraphMLDependencies extends App { case class ModuleId(organisation: String, - name: String, - version: String) { + name: String, + version: String) { def idString: String = organisation+":"+name+":"+version } case class Module(id: ModuleId, From ff4482064ce6587c70c66deb5749c86f5927055d Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 10:41:40 +0200 Subject: [PATCH 076/252] dry-up map creation --- .../sbt/graph/IvyGraphMLDependencies.scala | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 36c5819ef..bf368c6c9 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -47,14 +47,18 @@ object IvyGraphMLDependencies extends App { def module(id: ModuleId): Module = modules(id) - lazy val dependencyMap: Map[ModuleId, Seq[Module]] = { + lazy val dependencyMap: Map[ModuleId, Seq[Module]] = + createMap(identity) + + lazy val reverseDependencyMap: Map[ModuleId, Seq[Module]] = + createMap { case (a, b) => (b, a) } + + def createMap(bindingFor: ((ModuleId, ModuleId)) => (ModuleId, ModuleId)): Map[ModuleId, Seq[Module]] = { val m = new HashMap[ModuleId, MSet[Module]] with MultiMap[ModuleId, Module] - edges.foreach { case (from, to) => m.addBinding(from, module(to)) } - m.toMap.mapValues(_.toSeq.sortBy(_.id.idString)) - } - lazy val reverseDependencyMap: Map[ModuleId, Seq[Module]] = { - val m = new HashMap[ModuleId, MSet[Module]] with MultiMap[ModuleId, Module] - edges.foreach { case (from, to) => m.addBinding(to, module(from)) } + edges.foreach { entry => + val (f, t) = bindingFor(entry) + m.addBinding(f, module(t)) + } m.toMap.mapValues(_.toSeq.sortBy(_.id.idString)) } } From 7b88492ac70d38813045dafcd21cb4675654752b Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 11:08:28 +0200 Subject: [PATCH 077/252] fix: don't fail if a module has no dependencies --- .../net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index bf368c6c9..335345655 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -59,7 +59,7 @@ object IvyGraphMLDependencies extends App { val (f, t) = bindingFor(entry) m.addBinding(f, module(t)) } - m.toMap.mapValues(_.toSeq.sortBy(_.id.idString)) + m.toMap.mapValues(_.toSeq.sortBy(_.id.idString)).withDefaultValue(Nil) } } From 8a593a62b17cf68217d59a2cb0b3fed6e9c72148 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 11:10:22 +0200 Subject: [PATCH 078/252] fixes #20: ignore scala-library dependency by default. Reenable by setting `filter-scala-library` to false --- README.md | 3 +++ notes/0.7.0.markdown | 2 ++ .../sbt/graph/IvyGraphMLDependencies.scala | 24 +++++++++++++++++-- .../net/virtualvoid/sbt/graph/Plugin.scala | 12 +++++++++- 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f8eb74b2d..798dadee2 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,9 @@ Tasks & Settings * `dependency-tree`: Shows an ASCII tree representation of the project's dependencies * `what-depends-on `: Find out what depends on an artifact. Shows a reverse dependency tree for the selected module. + * `filter-scala-library`: Defines if the scala library should be excluded from the output of the dependency-* functions. + If `true`, instead of showing the dependency `"[S]"` is appended to the artifact name. Set to `false` if + you want the scala-library dependency to appear in the output. (default: true) * `dependency-graph-ml-file`: a setting which allows configuring the output path of `dependency-graph-ml`. * `ivy-report`: let's ivy generate the resolution report for you project. Use `show ivy-report` for the filename of the generated report diff --git a/notes/0.7.0.markdown b/notes/0.7.0.markdown index a4e96c1a4..dab5287a3 100644 --- a/notes/0.7.0.markdown +++ b/notes/0.7.0.markdown @@ -6,5 +6,7 @@ New features in this version: * 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. diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 335345655..efcb1d143 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -34,6 +34,7 @@ object IvyGraphMLDependencies extends App { def idString: String = organisation+":"+name+":"+version } case class Module(id: ModuleId, + extraInfo: String = "", evictedByVersion: Option[String] = None, error: Option[String] = None) { def hadError: Boolean = error.isDefined @@ -113,6 +114,24 @@ object IvyGraphMLDependencies extends App { ModuleGraph(nodes.toSeq, edges) } + def ignoreScalaLibrary(scalaVersion: String, graph: ModuleGraph): ModuleGraph = { + val scalaLibraryId = ModuleId("org.scala-lang", "scala-library", scalaVersion) + + def dependsOnScalaLibrary(m: Module): Boolean = + graph.dependencyMap(m.id).map(_.id).contains(scalaLibraryId) + + def addScalaLibraryAnnotation(m: Module): Module = { + if (dependsOnScalaLibrary(m)) + m.copy(extraInfo = m.extraInfo + " [S]") + else + m + } + + val newNodes = graph.nodes.map(addScalaLibraryAnnotation).filterNot(_.id == scalaLibraryId) + val newEdges = graph.edges.filterNot(_._2 == scalaLibraryId) + ModuleGraph(newNodes, newEdges) + } + def asciiGraph(graph: ModuleGraph): String = Layouter.renderGraph(buildAsciiGraph(graph)) @@ -128,12 +147,13 @@ object IvyGraphMLDependencies extends App { def displayModule(module: Module): String = red(module.id.idString + + module.extraInfo + module.error.map(" (error: "+_+")").getOrElse("") + module.evictedByVersion.map(_ formatted " (evicted by: %s)").getOrElse(""), module.hadError) private def buildAsciiGraph(moduleGraph: ModuleGraph): layout.Graph[String] = { def renderVertex(module: Module): String = - module.id.name + "\n" + + module.id.name + module.extraInfo + "\n" + module.id.organisation + "\n" + module.id.version + module.error.map("\nerror: "+_).getOrElse("") + @@ -200,6 +220,6 @@ object ModuleGraphProtocol extends 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] = asProduct3(Module)(Module.unapply(_).get) + implicit val ModuleFormat: Format[Module] = asProduct4(Module)(Module.unapply(_).get) implicit val ModuleGraphFormat: Format[ModuleGraph] = asProduct2(ModuleGraph)(ModuleGraph.unapply(_).get) } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 3d1547661..5dd18b33f 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -44,6 +44,9 @@ object Plugin extends sbt.Plugin { "A task which returns the location of the ivy report file for a given configuration (default `compile`).") val ignoreMissingUpdate = TaskKey[UpdateReport]("update-ignore-missing", "A copy of the update task which ignores missing artifacts") + val filterScalaLibrary = SettingKey[Boolean]("filter-scala-library", + "Specifies if scala dependency should be filtered in dependency-* output" + ) // internal import ModuleGraphProtocol._ @@ -63,12 +66,19 @@ object Plugin extends sbt.Plugin { val home = config.provider.scalaProvider.launcher.ivyHome (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c)) } - } + }, + filterScalaLibrary in Global := true ) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(ivyReportForConfig) def ivyReportForConfig(config: Configuration) = inConfig(config)(seq( ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(ignoreMissingUpdate), moduleGraph <<= ivyReport map (absoluteReportPath.andThen(IvyGraphMLDependencies.graph)), + moduleGraph <<= (scalaVersion, moduleGraph, filterScalaLibrary) map { (scalaV, graph, filter) => + if (filter) + IvyGraphMLDependencies.ignoreScalaLibrary(scalaV, graph) + else + graph + }, moduleGraphStore <<= moduleGraph storeAs moduleGraphStore triggeredBy moduleGraph, asciiGraph <<= moduleGraph map IvyGraphMLDependencies.asciiGraph, dependencyGraph <<= InputTask(shouldForceParser) { force => From 9f68bc9c9df7494fbf52a7d5e633def733ead30c Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 11:13:13 +0200 Subject: [PATCH 079/252] don't pollute namespace and reuse scoped update task --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 5dd18b33f..0decf9a72 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -42,8 +42,7 @@ object Plugin extends sbt.Plugin { "A function which returns the file containing the ivy report from the ivy cache for a given configuration") 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 = TaskKey[UpdateReport]("update-ignore-missing", - "A copy of the update task which ignores missing artifacts") + val ignoreMissingUpdate = update in ivyReport val filterScalaLibrary = SettingKey[Boolean]("filter-scala-library", "Specifies if scala dependency should be filtered in dependency-* output" ) @@ -67,6 +66,7 @@ object Plugin extends sbt.Plugin { (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c)) } }, + Compat.ignoreMissingUpdateT, filterScalaLibrary in Global := true ) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(ivyReportForConfig) @@ -105,8 +105,7 @@ object Plugin extends sbt.Plugin { (module, streams, moduleGraph) map { (module, streams, graph) => streams.log.info(IvyGraphMLDependencies.asciiTree(IvyGraphMLDependencies.reverseGraphStartingAt(graph, module))) } - }, - Compat.ignoreMissingUpdateT + } )) def printAsciiGraphTask = From d2cb35cb91c5df7b9eac4ff7988aedb1d188f61c Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 11:13:46 +0200 Subject: [PATCH 080/252] remove credentials declaration --- publish.sbt | 2 -- 1 file changed, 2 deletions(-) diff --git a/publish.sbt b/publish.sbt index 4b0fbca64..9d44a4f3a 100644 --- a/publish.sbt +++ b/publish.sbt @@ -10,8 +10,6 @@ publishArtifact in Test := false pomIncludeRepository := { _ => false } -credentials += Credentials(Path.userHome / ".ivy2" / ".credentials") - pomExtra := Helpers.generatePomExtra("git@github.com:jrudolph/sbt-dependency-graph.git", "scm:git:git@github.com:jrudolph/sbt-dependency-graph.git", From 81a204fe08ac46fc93dbe0d54c775cba785d854d Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 11:13:52 +0200 Subject: [PATCH 081/252] bump version --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index 41b84a546..6e49eb6de 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.7.0-RC2" +version := "0.7.0-RC3" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From 6119663e483f4548ea3dc1031374d3d948baa7cc Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 11:31:21 +0200 Subject: [PATCH 082/252] fix tests for ignoring scala by default refs #20 --- .../ignoreScalaLibrary/build.sbt | 29 +++++++++++++++++++ .../ignoreScalaLibrary/project/plugins.sbt | 1 + .../ignoreScalaLibrary/test | 1 + src/sbt-test/sbt-dependency-graph/plugins.sbt | 1 + .../showMissingUpdates/build.sbt | 1 - .../showMissingUpdates/project/plugins.sbt | 1 - 6 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt create mode 120000 src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/plugins.sbt create mode 100644 src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/test create mode 100644 src/sbt-test/sbt-dependency-graph/plugins.sbt delete mode 100644 src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt diff --git a/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt new file mode 100644 index 000000000..283f1ba13 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt @@ -0,0 +1,29 @@ +import net.virtualvoid.sbt.graph.Plugin._ + +graphSettings + +scalaVersion := "2.9.2" + +libraryDependencies ++= Seq( + "org.slf4j" % "slf4j-api" % "1.7.2", + "ch.qos.logback" % "logback-classic" % "1.0.7", + "com.typesafe.akka" % "akka-actor" % "2.0.3") + +TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, graph) => + 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] + | +-ch.qos.logback:logback-classic:1.0.7 + | | +-ch.qos.logback:logback-core:1.0.7 + | | +-org.slf4j:slf4j-api:1.6.6 (evicted by: 1.7.2) + | | + | +-com.typesafe.akka:akka-actor:2.0.3 [S] + | | +-com.typesafe:config:0.3.1 + | | + | +-org.slf4j:slf4j-api:1.7.2 + | """.stripMargin + IO.writeLines(file("/tmp/blib"), sanitize(graph).split("\n")) + IO.writeLines(file("/tmp/blub"), sanitize(expectedGraph).split("\n")) + require(sanitize(graph) == sanitize(expectedGraph), "Graph for report %s was '\n%s' but should have been '\n%s'" format (report, sanitize(graph), sanitize(expectedGraph))) + () +} diff --git a/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/plugins.sbt new file mode 120000 index 000000000..0caf1de77 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/plugins.sbt @@ -0,0 +1 @@ +../../plugins.sbt \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/test b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/test new file mode 100644 index 000000000..a5912a391 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/test @@ -0,0 +1 @@ +> check \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/plugins.sbt b/src/sbt-test/sbt-dependency-graph/plugins.sbt new file mode 100644 index 000000000..e25ce12a6 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.0-RC3") \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt index 213719040..232b18d22 100644 --- a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt +++ b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt @@ -12,7 +12,6 @@ TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, val expectedGraph = """default:default-91180e_2.9.2:0.1-SNAPSHOT | +-%sat.blub:blib:1.2.3 (error: not found)%s - | +-org.scala-lang:scala-library:2.9.2 | """.stripMargin.format(scala.Console.RED, scala.Console.RESET) require(sanitize(graph) == sanitize(expectedGraph), "Graph for report %s was '\n%s' but should have been '\n%s'" format (report, sanitize(graph), sanitize(expectedGraph))) () diff --git a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt deleted file mode 100644 index 08b3f3d0a..000000000 --- a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.6.1-SNAPSHOT") \ No newline at end of file From f18dac3fd1fa086296df7777058406601ee77c11 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 11:31:38 +0200 Subject: [PATCH 083/252] add missing test descriptor for tests --- .../sbt-dependency-graph/showMissingUpdates/project/plugins.sbt | 1 + 1 file changed, 1 insertion(+) create mode 120000 src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt diff --git a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt new file mode 120000 index 000000000..0caf1de77 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt @@ -0,0 +1 @@ +../../plugins.sbt \ No newline at end of file From 023c9c894def620aa749e0047cc967645479ac33 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 11:35:17 +0200 Subject: [PATCH 084/252] update readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 798dadee2..51d6a8556 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,12 @@ This project takes the report xml of your project and creates a graphml file out ivy can create graphml files itself, but since I didn't want to spend to much time getting sbt to call into Ivy to create graphs, I went with the easy way here) +Known issues +------------ + + * There's an unfixed bug with graph generation for particular layouts (#19). Workaround: + Use `dependency-tree` instead of `dependency-graph`. + Credits ------- From 8b38322ceb98c042162eb9fc53fc3b76396d8315 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 15:12:02 +0200 Subject: [PATCH 085/252] another README update --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 51d6a8556..89215283a 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,9 @@ sbt to call into Ivy to create graphs, I went with the easy way here) Known issues ------------ - * There's an unfixed bug with graph generation for particular layouts (#19). Workaround: + * #19: There's an unfixed bug with graph generation for particular layouts. Workaround: Use `dependency-tree` instead of `dependency-graph`. + * #12: Excluded dependencies will be shown in the graph in sbt < 0.12, works with later versions Credits ------- From e17df34b76041cacffac4c3543d02bd664ed9fc1 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 15:14:40 +0200 Subject: [PATCH 086/252] bump version --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index 6e49eb6de..82efd09b4 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.7.0-RC3" +version := "0.7.0" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From 6d492244c83519ad98d84ee11ec247ca4fb6f7c9 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 15:32:00 +0200 Subject: [PATCH 087/252] ls metadata for 0.7.0 --- src/main/ls/0.7.0.json | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/main/ls/0.7.0.json diff --git a/src/main/ls/0.7.0.json b/src/main/ls/0.7.0.json new file mode 100644 index 000000000..c28c87bcd --- /dev/null +++ b/src/main/ls/0.7.0.json @@ -0,0 +1,29 @@ +{ + "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 +} \ No newline at end of file From 8ed9eab3b2675657f5854877259ea2f420be9d9f Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 15:33:12 +0200 Subject: [PATCH 088/252] notes --- notes/0.7.0.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notes/0.7.0.markdown b/notes/0.7.0.markdown index dab5287a3..5ec96ae07 100644 --- a/notes/0.7.0.markdown +++ b/notes/0.7.0.markdown @@ -1,6 +1,6 @@ New features in this version: - * `dependency-graph` now renders a real graph. Many thanks go to [Matt Russell](https://github.com/mdr/) for + * `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) From ad46330cf7a9ba0a36ea6ddbf02ca31d108c8c0d Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Oct 2012 16:52:10 +0300 Subject: [PATCH 089/252] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 89215283a..9f0e106a2 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Inner Workings -------------- sbt/Ivy's `update` task create ivy-report xml-files inside `.ivy2/cache` (in sbt 0.12.1: -`/target/resolution-cache/reports/`. You can +`/target/resolution-cache/reports/`). You can just open them with your browser to look at the dependency report for your project. This project takes the report xml of your project and creates a graphml file out of it. (BTW, ivy can create graphml files itself, but since I didn't want to spend to much time getting From 334df398bcc055741a81cbdf61ccb6ff053d508d Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 27 Oct 2012 10:17:01 +0200 Subject: [PATCH 090/252] next version --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index 82efd09b4..c6ca6071d 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.7.0" +version := "0.7.1-SNAPSHOT" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From 7c90d09d82f7464a70a630bc87a8f10e0b6696b7 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 27 Oct 2012 12:28:40 +0200 Subject: [PATCH 091/252] refs #7: `dependency-license-info` show information about licenses --- README.md | 1 + notes/0.7.1.markdown | 3 +++ .../sbt/graph/IvyGraphMLDependencies.scala | 5 ++++- .../scala/net/virtualvoid/sbt/graph/Plugin.scala | 16 +++++++++++++++- 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 notes/0.7.1.markdown diff --git a/README.md b/README.md index 89215283a..2ab25c75b 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ Tasks & Settings * `dependency-tree`: Shows an ASCII tree representation of the project's dependencies * `what-depends-on `: Find out what depends on an artifact. Shows a reverse dependency tree for the selected module. + * `dependency-license-info`: show dependencies grouped by declared license * `filter-scala-library`: Defines if the scala library should be excluded from the output of the dependency-* functions. If `true`, instead of showing the dependency `"[S]"` is appended to the artifact name. Set to `false` if you want the scala-library dependency to appear in the output. (default: true) diff --git a/notes/0.7.1.markdown b/notes/0.7.1.markdown new file mode 100644 index 000000000..c12b0e21a --- /dev/null +++ b/notes/0.7.1.markdown @@ -0,0 +1,3 @@ +New features in this version: + + * `dependency-license-info`: show dependencies grouped by declared license diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index efcb1d143..8408d03be 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -34,10 +34,12 @@ object IvyGraphMLDependencies extends App { def idString: String = organisation+":"+name+":"+version } case class Module(id: ModuleId, + license: Option[String] = None, extraInfo: String = "", evictedByVersion: Option[String] = None, error: Option[String] = None) { def hadError: Boolean = error.isDefined + def isUsed: Boolean = !evictedByVersion.isDefined } type Edge = (ModuleId, ModuleId) @@ -80,6 +82,7 @@ object IvyGraphMLDependencies extends App { rev = revision.attribute("name").get.text moduleId = moduleIdFromElement(mod, rev) 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)) } yield (module, edgesForModule(moduleId, revision, rev)) @@ -220,6 +223,6 @@ object ModuleGraphProtocol extends 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] = asProduct4(Module)(Module.unapply(_).get) + implicit val ModuleFormat: Format[Module] = asProduct5(Module)(Module.unapply(_).get) implicit val ModuleGraphFormat: Format[ModuleGraph] = asProduct2(ModuleGraph)(ModuleGraph.unapply(_).get) } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 0decf9a72..a1a325bd0 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -47,6 +47,9 @@ object Plugin extends sbt.Plugin { "Specifies if scala dependency should be filtered in dependency-* output" ) + val licenseInfo = TaskKey[Unit]("dependency-license-info", + "Aggregates and shows information about the licenses of dependencies") + // internal import ModuleGraphProtocol._ val moduleGraphStore = TaskKey[IvyGraphMLDependencies.ModuleGraph]("module-graph-store", "The stored module-graph from the last run") @@ -105,7 +108,8 @@ object Plugin extends sbt.Plugin { (module, streams, moduleGraph) map { (module, streams, graph) => streams.log.info(IvyGraphMLDependencies.asciiTree(IvyGraphMLDependencies.reverseGraphStartingAt(graph, module))) } - } + }, + licenseInfo <<= (moduleGraph, streams) map showLicenseInfo )) def printAsciiGraphTask = @@ -123,6 +127,16 @@ object Plugin extends sbt.Plugin { def print(key: TaskKey[String]) = (streams, key) map (_.log.info(_)) + def showLicenseInfo(graph: ModuleGraph, streams: TaskStreams) { + val output = + graph.nodes.filter(_.isUsed).groupBy(_.license).toSeq.sortBy(_._1).map { + case (license, modules) => + license.getOrElse("No license specified")+"\n"+ + modules.map(_.id.idString formatted "\t %s").mkString("\n") + }.mkString("\n\n") + streams.log.info(output) + } + import Project._ val shouldForceParser: State => Parser[Boolean] = { (state: State) => import complete.DefaultParsers._ From 2f725bf16f15b67db2e58047a90c03458bfcdb0f Mon Sep 17 00:00:00 2001 From: Eric Bowman Date: Wed, 31 Oct 2012 10:52:38 +0000 Subject: [PATCH 092/252] Fix for version matching like 0.12.1-foo An organization that has had to fork sbt is likely to change the version slightly. The code is intended to match 0.12.1-foo as a 0.12.1 version, but in fact without this change does not. --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index a1a325bd0..77c63c973 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -59,7 +59,7 @@ object Plugin extends sbt.Plugin { def graphSettings = seq( ivyReportFunction <<= (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 >= 1) => + case Version(0, min, fix, _) if min > 12 || (min == 12 && fix >= 1) => 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)) From f4bd8a409b05aba66ee3437e4394fcd1ac232302 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 31 Oct 2012 15:09:47 +0100 Subject: [PATCH 093/252] refs #24: fix Version matching again now for matching normal 0.12.1 version --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 77c63c973..af76d17ca 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -177,9 +177,9 @@ object Plugin extends sbt.Plugin { val VersionPattern = """(\d+)\.(\d+)\.(\d+)(?:-(.*))?""".r object Version { - def unapplySeq(str: String): Option[(Int, Int, Int, Seq[String])] = str match { - case VersionPattern(major, minor, fix, appendix) => Some((major.toInt, minor.toInt, fix.toInt, Option(appendix).toSeq)) + def unapply(str: String): Option[(Int, Int, Int, Option[String])] = str match { + case VersionPattern(major, minor, fix, appendix) => Some((major.toInt, minor.toInt, fix.toInt, Option(appendix))) case _ => None } } -} \ No newline at end of file +} From 4bc9e3f7dfc88d988a424e20ae38e9b9455edf2a Mon Sep 17 00:00:00 2001 From: berleon Date: Tue, 18 Dec 2012 17:41:49 +0100 Subject: [PATCH 094/252] fixed Version unapply method --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 77c63c973..caca307c4 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -177,7 +177,7 @@ object Plugin extends sbt.Plugin { val VersionPattern = """(\d+)\.(\d+)\.(\d+)(?:-(.*))?""".r object Version { - def unapplySeq(str: String): Option[(Int, Int, Int, Seq[String])] = str match { + def unapply(str: String): Option[(Int, Int, Int, Seq[String])] = str match { case VersionPattern(major, minor, fix, appendix) => Some((major.toInt, minor.toInt, fix.toInt, Option(appendix).toSeq)) case _ => None } From b7ae7234238ca1eab31bde1fc71bb0a533537d24 Mon Sep 17 00:00:00 2001 From: berleon Date: Tue, 18 Dec 2012 17:43:57 +0100 Subject: [PATCH 095/252] added saveAsDot method to IvyGraphMLDependencies that generates a simple dot file --- .../sbt/graph/IvyGraphMLDependencies.scala | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 8408d03be..b709d25ce 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -195,6 +195,20 @@ object IvyGraphMLDependencies extends App { XML.save(outputFile, xml) } + def saveAsDot(graph : ModuleGraph, outputFile: File) : File = { + + val edges = { + for ( e <- graph.edges) + yield + "\t\"" + e._1.idString + "\" -> \"" + e._2.idString + "\"" + }.mkString("\n") + + val dot = "digraph \"dependency-graph\" {\n" + edges + "\n}" + + sbt.IO.write(outputFile, dot) + outputFile + } + def moduleIdFromElement(element: Node, version: String): ModuleId = ModuleId(element.attribute("organisation").get.text, element.attribute("name").get.text, version) From 2c771d58e66939f6a40f38f272389950ea391e30 Mon Sep 17 00:00:00 2001 From: berleon Date: Tue, 18 Dec 2012 17:45:24 +0100 Subject: [PATCH 096/252] added dependencyDotFile Setting and dependencyDotTask --- .../scala/net/virtualvoid/sbt/graph/Plugin.scala | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index caca307c4..500ba99d5 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -28,6 +28,10 @@ object Plugin extends sbt.Plugin { "The location the graphml file should be generated at") 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", + "The location the dot file should be generated at") + val dependencyDot = TaskKey[File]("dependency-dot", + "Creates a dot file containing the dpendency-graph for a project") val moduleGraph = TaskKey[IvyGraphMLDependencies.ModuleGraph]("module-graph", "The dependency graph for a project") val asciiGraph = TaskKey[String]("dependency-graph-string", @@ -104,6 +108,8 @@ object Plugin extends sbt.Plugin { dependencyTree <<= print(asciiTree), dependencyGraphMLFile <<= target / "dependencies-%s.graphml".format(config.toString), dependencyGraphML <<= dependencyGraphMLTask, + dependencyDotFile <<= target / "dependencies-%s.dot".format(config.toString), + dependencyDot <<= dependencyDotTask, whatDependsOn <<= InputTask(artifactIdParser) { module => (module, streams, moduleGraph) map { (module, streams, graph) => streams.log.info(IvyGraphMLDependencies.asciiTree(IvyGraphMLDependencies.reverseGraphStartingAt(graph, module))) @@ -121,7 +127,12 @@ object Plugin extends sbt.Plugin { streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } - + def dependencyDotTask = + (moduleGraph, dependencyDotFile, streams) map { (graph, outFile, streams) => + val resultFile = IvyGraphMLDependencies.saveAsDot(graph, outFile) + streams.log.info("Wrote dependency graph to '%s'" format resultFile) + resultFile + } def absoluteReportPath = (file: File) => file.getAbsolutePath def print(key: TaskKey[String]) = From 18e76737ecb8829e01d55240fa96619cd8a2b4a0 Mon Sep 17 00:00:00 2001 From: berleon Date: Fri, 21 Dec 2012 15:06:23 +0100 Subject: [PATCH 097/252] updatet to 0.7.1-SNAPSHOT --- src/sbt-test/sbt-dependency-graph/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sbt-test/sbt-dependency-graph/plugins.sbt b/src/sbt-test/sbt-dependency-graph/plugins.sbt index e25ce12a6..33a40a085 100644 --- a/src/sbt-test/sbt-dependency-graph/plugins.sbt +++ b/src/sbt-test/sbt-dependency-graph/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.0-RC3") \ No newline at end of file +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.1-SNAPSHOT") \ No newline at end of file From 25a996752c15950004970dfa290c7114dc93836a Mon Sep 17 00:00:00 2001 From: berleon Date: Fri, 21 Dec 2012 15:13:06 +0100 Subject: [PATCH 098/252] removed com.typesafe.akka:akka-actor from libaryDependencies there was a resolving problems so the test failed. --- .../sbt-dependency-graph/ignoreScalaLibrary/build.sbt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt index 283f1ba13..709304b44 100644 --- a/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt +++ b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt @@ -6,8 +6,8 @@ scalaVersion := "2.9.2" libraryDependencies ++= Seq( "org.slf4j" % "slf4j-api" % "1.7.2", - "ch.qos.logback" % "logback-classic" % "1.0.7", - "com.typesafe.akka" % "akka-actor" % "2.0.3") + "ch.qos.logback" % "logback-classic" % "1.0.7" + ) TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, graph) => def sanitize(str: String): String = str.split('\n').drop(1).map(_.trim).mkString("\n") @@ -17,9 +17,6 @@ TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, | | +-ch.qos.logback:logback-core:1.0.7 | | +-org.slf4j:slf4j-api:1.6.6 (evicted by: 1.7.2) | | - | +-com.typesafe.akka:akka-actor:2.0.3 [S] - | | +-com.typesafe:config:0.3.1 - | | | +-org.slf4j:slf4j-api:1.7.2 | """.stripMargin IO.writeLines(file("/tmp/blib"), sanitize(graph).split("\n")) From fd77497498ee3c73ddca547fed8f741f6e7e6586 Mon Sep 17 00:00:00 2001 From: berleon Date: Fri, 21 Dec 2012 15:14:25 +0100 Subject: [PATCH 099/252] added testDotFileGeneration it is a sbt-scripted project to test the dot generation process. --- .../testDotFileGeneration/project/build.scala | 75 +++++++++++++++++++ .../testDotFileGeneration/project/plugins.sbt | 1 + .../testDotFileGeneration/test | 1 + 3 files changed, 77 insertions(+) create mode 100644 src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.scala create mode 120000 src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/plugins.sbt create mode 100644 src/sbt-test/sbt-dependency-graph/testDotFileGeneration/test diff --git a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.scala b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.scala new file mode 100644 index 000000000..1d7e148ca --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.scala @@ -0,0 +1,75 @@ +import collection.mutable.ListBuffer +import net.virtualvoid.sbt.graph.Plugin._ + +import sbt._ +import sbt.Keys._ + +object Build extends sbt.Build { + + + lazy val justATransiviteDependencyEndpointProject = Project( + id = "just-a-transitive-dependency-endpoint", + base = file("."), + settings = Defaults.defaultSettings + ) + lazy val justATransitiveDependencyProject = Project( + id = "just-a-transitive-dependency", + base = file("."), + settings = Defaults.defaultSettings + ).dependsOn(justATransiviteDependencyEndpointProject) + + lazy val justADependencyProject = Project( + id = "just-a-dependency", + base = file("."), + settings = Defaults.defaultSettings + ) + + lazy val test_project = + Project( + id = "test-dot-file-generation", + base = file("."), + settings = Defaults.defaultSettings ++ + graphSettings ++ Seq( + sbtVersion := "0.12.1", + scalaVersion := "2.9.2", + resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/", + + TaskKey[Unit]("check") <<= (dependencyDot in Compile) map { (dotFile) => + def sanitize(str: String): String = str.split('\n').drop(1).mkString("\n") + val expectedGraph = + """digraph "dependency-graph" { + | graph[rankdir="LR"] + | node [ + | shape="record" + | ] + | edge [ + | arrowtail="none" + | ] + | "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 + } +} \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/plugins.sbt new file mode 120000 index 000000000..0caf1de77 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/plugins.sbt @@ -0,0 +1 @@ +../../plugins.sbt \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/test b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/test new file mode 100644 index 000000000..1461a7105 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/test @@ -0,0 +1 @@ +> test-dot-file-generation/check \ No newline at end of file From 0097df83789ea5d019deb7f3734a9f68a2b38d9c Mon Sep 17 00:00:00 2001 From: berleon Date: Fri, 21 Dec 2012 15:14:46 +0100 Subject: [PATCH 100/252] improved dot generation --- .../sbt/graph/IvyGraphMLDependencies.scala | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index b709d25ce..6803696fe 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -200,10 +200,19 @@ object IvyGraphMLDependencies extends App { val edges = { for ( e <- graph.edges) yield - "\t\"" + e._1.idString + "\" -> \"" + e._2.idString + "\"" + """ "%s" -> "%s"""".format(e._1.idString, e._2.idString) }.mkString("\n") - val dot = "digraph \"dependency-graph\" {\n" + edges + "\n}" + val dot = + """digraph "dependency-graph" { + | graph[rankdir="LR"] + | node [ + | shape="record" + | ] + | edge [ + | arrowtail="none" + | ] + |""".stripMargin + edges + "\n}" sbt.IO.write(outputFile, dot) outputFile From 24c614d568fcf78569666c1d41165ff8cfd0f54b Mon Sep 17 00:00:00 2001 From: berleon Date: Tue, 18 Dec 2012 17:41:49 +0100 Subject: [PATCH 101/252] added dot settings to README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 404d926c2..20eb2a260 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,8 @@ Tasks & Settings * `dependency-graph`: Shows an ASCII graph of the project's dependencies on the sbt console * `dependency-graph-ml`: Generates a .graphml file with the project's dependencies to `target/dependencies-.graphml`. Use e.g. [yEd](http://www.yworks.com/en/products_yed_about.html) to format the graph to your needs. + * `dependency-dot`: Generates a .dot file with the project's dependencies to `target/dependencies-.dot`. + Use [graphviz](http://www.graphviz.org/) to render it to your preferred graphic format. * `dependency-tree`: Shows an ASCII tree representation of the project's dependencies * `what-depends-on `: Find out what depends on an artifact. Shows a reverse dependency tree for the selected module. @@ -52,6 +54,7 @@ Tasks & Settings If `true`, instead of showing the dependency `"[S]"` is appended to the artifact name. Set to `false` if you want the scala-library dependency to appear in the output. (default: true) * `dependency-graph-ml-file`: a setting which allows configuring the output path of `dependency-graph-ml`. + * `dependency-dot-file`: a setting which allows configuring the output path of `dependency-dot`. * `ivy-report`: let's ivy generate the resolution report for you project. Use `show ivy-report` for the filename of the generated report From 2ea4470757a83d2bae2c1435da8357267e92ff77 Mon Sep 17 00:00:00 2001 From: Leon Sixt Date: Fri, 21 Dec 2012 18:48:39 +0100 Subject: [PATCH 102/252] more customisation for dot output with dependency-dot-head you can now define your own dot head. dependency-dot-node-label lets you customise the labels of the nodes --- README.md | 3 ++ .../sbt/graph/IvyGraphMLDependencies.scala | 23 ++++++----- .../net/virtualvoid/sbt/graph/Plugin.scala | 20 ++++++++- .../testDotFileGeneration/project/build.scala | 41 ++++++++++--------- .../testDotFileGeneration/test | 3 +- 5 files changed, 57 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 20eb2a260..76b648a64 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,9 @@ Tasks & Settings you want the scala-library dependency to appear in the output. (default: true) * `dependency-graph-ml-file`: a setting which allows configuring the output path of `dependency-graph-ml`. * `dependency-dot-file`: a setting which allows configuring the output path of `dependency-dot`. + * `dependency-dot-head`: a setting to customize the head of the dot file. (e.g. to set your preferred node shapes) + * `dependency-dot-nodes-label`: defines the formation of a node label + (default set to `[organisation]
[name]
[version]`) * `ivy-report`: let's ivy generate the resolution report for you project. Use `show ivy-report` for the filename of the generated report diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 6803696fe..3d75ac66d 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -195,7 +195,17 @@ object IvyGraphMLDependencies extends App { XML.save(outputFile, xml) } - def saveAsDot(graph : ModuleGraph, outputFile: File) : File = { + def saveAsDot(graph : ModuleGraph, + dotHead : String, + nodeFormation : Function3[String,String,String,String], + outputFile: File + ) : File = { + val nodes = { + for (n <- graph.nodes) + yield + """ "%s"[label=%s]""".format(n.id.idString, + nodeFormation(n.id.organisation, n.id.name, n.id.version)) + }.mkString("\n") val edges = { for ( e <- graph.edges) @@ -203,16 +213,7 @@ object IvyGraphMLDependencies extends App { """ "%s" -> "%s"""".format(e._1.idString, e._2.idString) }.mkString("\n") - val dot = - """digraph "dependency-graph" { - | graph[rankdir="LR"] - | node [ - | shape="record" - | ] - | edge [ - | arrowtail="none" - | ] - |""".stripMargin + edges + "\n}" + val dot = "%s\n%s\n%s\n}".format(dotHead, nodes, edges) sbt.IO.write(outputFile, dot) outputFile diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 500ba99d5..7707cae99 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -30,6 +30,10 @@ object Plugin extends sbt.Plugin { "Creates a graphml file containing the dependency-graph for a project") 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", + "Returns a formated string of a dependency. Takes organisation, name and version as parameters") + val dependencyDotHead = SettingKey[String]("dependency-dot-head", + "The head of the dot file. (e.g. to set your preferred node shapes)") val dependencyDot = TaskKey[File]("dependency-dot", "Creates a dot file containing the dpendency-graph for a project") val moduleGraph = TaskKey[IvyGraphMLDependencies.ModuleGraph]("module-graph", @@ -110,6 +114,17 @@ object Plugin extends sbt.Plugin { dependencyGraphML <<= dependencyGraphMLTask, dependencyDotFile <<= target / "dependencies-%s.dot".format(config.toString), dependencyDot <<= dependencyDotTask, + dependencyDotHead := """digraph "dependency-graph" { + | graph[rankdir="LR"] + | node [ + | shape="record" + | ] + | edge [ + | arrowtail="none" + | ]""".stripMargin, + dependencyDotNodeLabel := { (organisation : String, name : String, version : String) => + """<%s
%s
%s>""".format(organisation, name, version) + }, whatDependsOn <<= InputTask(artifactIdParser) { module => (module, streams, moduleGraph) map { (module, streams, graph) => streams.log.info(IvyGraphMLDependencies.asciiTree(IvyGraphMLDependencies.reverseGraphStartingAt(graph, module))) @@ -128,8 +143,9 @@ object Plugin extends sbt.Plugin { resultFile } def dependencyDotTask = - (moduleGraph, dependencyDotFile, streams) map { (graph, outFile, streams) => - val resultFile = IvyGraphMLDependencies.saveAsDot(graph, outFile) + (moduleGraph, dependencyDotHead, dependencyDotNodeLabel, dependencyDotFile, streams). + map { (graph, dotHead, nodeLabelFormation, outFile, streams) => + val resultFile = IvyGraphMLDependencies.saveAsDot(graph, dotHead, nodeLabelFormation, outFile) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } diff --git a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.scala b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.scala index 1d7e148ca..62a50047e 100644 --- a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.scala +++ b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.scala @@ -35,26 +35,29 @@ object Build extends sbt.Build { resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/", TaskKey[Unit]("check") <<= (dependencyDot in Compile) map { (dotFile) => - def sanitize(str: String): String = str.split('\n').drop(1).mkString("\n") - val expectedGraph = - """digraph "dependency-graph" { - | graph[rankdir="LR"] - | node [ - | shape="record" - | ] - | edge [ - | arrowtail="none" - | ] - | "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 expectedGraph = + """digraph "dependency-graph" { + | graph[rankdir="LR"] + | node [ + | shape="record" + | ] + | edge [ + | arrowtail="none" + | ] + | "test-dot-file-generation:test-dot-file-generation_2.9.2:0.1-SNAPSHOT"[label=test-dot-file-generation_2.9.2
0.1-SNAPSHOT>] + | "just-a-transitive-dependency:just-a-transitive-dependency_2.9.2:0.1-SNAPSHOT"[label=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"[label=just-a-transitive-dependency-endpoint_2.9.2
0.1-SNAPSHOT>] + | "just-a-dependency:just-a-dependency_2.9.2:0.1-SNAPSHOT"[label=just-a-dependency_2.9.2
0.1-SNAPSHOT>] + | "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")) - () + val graph : String = scala.io.Source.fromFile(dotFile.getAbsolutePath).mkString + val errors = compareByLine(graph, expectedGraph) + require(errors.isEmpty , errors.mkString("\n")) + () } ) ).dependsOn(justADependencyProject, justATransitiveDependencyProject) diff --git a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/test b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/test index 1461a7105..f9fa19e83 100644 --- a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/test +++ b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/test @@ -1 +1,2 @@ -> test-dot-file-generation/check \ No newline at end of file +> project test-dot-file-generation +> check From ed097ed2e21266c71b6aac3ff5190c01935975ac Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 22 Jan 2013 14:38:30 +0100 Subject: [PATCH 103/252] bump version --- README.md | 1 + notes/0.7.1.markdown | 2 ++ project.sbt | 2 +- project/plugins.sbt | 2 +- src/main/ls/0.7.1.json | 29 +++++++++++++++++++++++++++++ 5 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 src/main/ls/0.7.1.json diff --git a/README.md b/README.md index 67cbf820d..4497c98cf 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Credits ------- * Matt Russell (@mdr) for contributing the ASCII graph layout. + * berleon (@berleon) for contributing rendering to dot. License ------- diff --git a/notes/0.7.1.markdown b/notes/0.7.1.markdown index c12b0e21a..dd7a66315 100644 --- a/notes/0.7.1.markdown +++ b/notes/0.7.1.markdown @@ -1,3 +1,5 @@ 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). diff --git a/project.sbt b/project.sbt index c6ca6071d..f7800e769 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.7.1-SNAPSHOT" +version := "0.7.1" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) diff --git a/project/plugins.sbt b/project/plugins.sbt index 23bdc1cdb..80dd7f871 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,4 +4,4 @@ addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.2") resolvers += "Coda Hale's Repo" at "http://repo.codahale.com" -addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.7.0-RC2") +addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.7.0") diff --git a/src/main/ls/0.7.1.json b/src/main/ls/0.7.1.json new file mode 100644 index 000000000..846054dd4 --- /dev/null +++ b/src/main/ls/0.7.1.json @@ -0,0 +1,29 @@ +{ + "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 +} From b018454fae5c19a732c1489af7bbc4bdfc85efa2 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 25 Jan 2013 16:24:50 +0100 Subject: [PATCH 104/252] preparing next version --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index f7800e769..4153ae8fb 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.7.1" +version := "0.7.2-SNAPSHOT" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From 23b6dc86442e17b3822939dd0b1b1b9803487b04 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 2 Mar 2013 12:08:56 +0100 Subject: [PATCH 105/252] upgrade README instructions to recent version 0.7.1 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4497c98cf..e48facfe6 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ How To Use For sbt 0.11/0.12, add sbt-dependency-graph as a dependency in `project/plugins.sbt`: ```scala -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.0") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.1") ``` Then, add the following to your `/build.sbt` (that's not `project/build.sbt`!) as a standalone line: From 093b4782adf25ea87c616f3a001284476927b8a1 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 2 Mar 2013 12:32:57 +0100 Subject: [PATCH 106/252] fix #27: don't require caller[@rev] to be equal to outside revision Since the `caller` is already nested in a particular called module this should be sufficient. --- notes/0.7.2.markdown | 5 ++++ .../sbt/graph/IvyGraphMLDependencies.scala | 6 ++--- .../ignoreScalaLibrary/build.sbt | 1 + .../intervalRangedVersions/build.sbt | 24 +++++++++++++++++++ .../project/plugins.sbt | 1 + .../intervalRangedVersions/test | 1 + src/sbt-test/sbt-dependency-graph/plugins.sbt | 2 +- 7 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 notes/0.7.2.markdown create mode 100644 src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt create mode 100644 src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt create mode 100644 src/sbt-test/sbt-dependency-graph/intervalRangedVersions/test diff --git a/notes/0.7.2.markdown b/notes/0.7.2.markdown new file mode 100644 index 000000000..da96a4007 --- /dev/null +++ b/notes/0.7.2.markdown @@ -0,0 +1,5 @@ +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. + diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 88fabf91e..f9aa49eaa 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -70,9 +70,9 @@ object IvyGraphMLDependencies extends App { buildGraph(buildDoc(ivyReportFile)) def buildGraph(doc: Document): ModuleGraph = { - def edgesForModule(id: ModuleId, revision: NodeSeq, rev: String): Seq[Edge] = + def edgesForModule(id: ModuleId, revision: NodeSeq): Seq[Edge] = for { - caller <- revision \ "caller" if caller.attribute("rev").get.text == rev + caller <- revision \ "caller" callerModule = moduleIdFromElement(caller, caller.attribute("callerrev").get.text) } yield (moduleIdFromElement(caller, caller.attribute("callerrev").get.text), id) @@ -85,7 +85,7 @@ object IvyGraphMLDependencies extends App { (revision \ "license").headOption.flatMap(_.attribute("name")).map(_.text), evictedByVersion = (revision \ "evicted-by").headOption.flatMap(_.attribute("rev").map(_.text)), error = revision.attribute("error").map(_.text)) - } yield (module, edgesForModule(moduleId, revision, rev)) + } yield (module, edgesForModule(moduleId, revision)) val (nodes, edges) = moduleEdges.unzip diff --git a/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt index 8242b5850..025703043 100644 --- a/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt +++ b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt @@ -16,6 +16,7 @@ TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, | +-ch.qos.logback:logback-classic:1.0.7 | | +-ch.qos.logback:logback-core:1.0.7 | | +-org.slf4j:slf4j-api:1.6.6 (evicted by: 1.7.2) + | | +-org.slf4j:slf4j-api:1.7.2 | | | +-org.slf4j:slf4j-api:1.7.2 | """.stripMargin diff --git a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt new file mode 100644 index 000000000..19030bcf6 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt @@ -0,0 +1,24 @@ +import net.virtualvoid.sbt.graph.Plugin._ + +graphSettings + +scalaVersion := "2.9.2" + +libraryDependencies ++= Seq( + "com.codahale" % "jerkson_2.9.1" % "0.5.0" +) + +TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, graph) => + 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.12 + | +-org.codehaus.jackson:jackson-mapper-asl:1.9.12 + | +-org.codehaus.jackson:jackson-core-asl:1.9.12 + | """.stripMargin + IO.writeLines(file("/tmp/blib"), sanitize(graph).split("\n")) + IO.writeLines(file("/tmp/blub"), sanitize(expectedGraph).split("\n")) + require(sanitize(graph) == sanitize(expectedGraph), "Graph for report %s was '\n%s' but should have been '\n%s'" format (report, sanitize(graph), sanitize(expectedGraph))) + () +} diff --git a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt new file mode 100644 index 000000000..6edc33a27 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.2-SNAPSHOT") diff --git a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/test b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/test new file mode 100644 index 000000000..a5912a391 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/test @@ -0,0 +1 @@ +> check \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/plugins.sbt b/src/sbt-test/sbt-dependency-graph/plugins.sbt index 33a40a085..6edc33a27 100644 --- a/src/sbt-test/sbt-dependency-graph/plugins.sbt +++ b/src/sbt-test/sbt-dependency-graph/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.1-SNAPSHOT") \ No newline at end of file +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.2-SNAPSHOT") From 8ea9fa6fee1736010d25c10d83e9feaf3ad08a64 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 2 Mar 2013 12:39:23 +0100 Subject: [PATCH 107/252] bump version --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index 4153ae8fb..74acc9341 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.7.2-SNAPSHOT" +version := "0.7.2" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From 39cd1bdeaa7190e3ce055450cef00a16045eaa29 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 2 Mar 2013 12:43:06 +0100 Subject: [PATCH 108/252] 0.7.2 ls metadata --- src/main/ls/0.7.2.json | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/main/ls/0.7.2.json diff --git a/src/main/ls/0.7.2.json b/src/main/ls/0.7.2.json new file mode 100644 index 000000000..f004d3e82 --- /dev/null +++ b/src/main/ls/0.7.2.json @@ -0,0 +1,29 @@ +{ + "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 +} \ No newline at end of file From d5e4f04519b64956eda12ee3e89141fad40d091c Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 2 Mar 2013 12:43:12 +0100 Subject: [PATCH 109/252] publishing information --- PUBLISHING | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 PUBLISHING diff --git a/PUBLISHING b/PUBLISHING new file mode 100644 index 000000000..e68a4ff18 --- /dev/null +++ b/PUBLISHING @@ -0,0 +1,15 @@ +Before publishing: + + * update version in project.sbt + + * update plugins.sbt in scripted tests + * run `^ scripted` to run all tests + + * run `^ publish' + +After publishing: + * create tag (+ push) + * update infos in README + * update example project (+ push) + * use `ls-write-version` + * lsync From be59eee9a737ad17fb7448a12fb620919a78b7fa Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 2 Mar 2013 12:46:09 +0100 Subject: [PATCH 110/252] update README to version 0.7.2 --- PUBLISHING | 4 +++- README.md | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/PUBLISHING b/PUBLISHING index e68a4ff18..06008ee6d 100644 --- a/PUBLISHING +++ b/PUBLISHING @@ -9,7 +9,9 @@ Before publishing: After publishing: * create tag (+ push) - * update infos in README + * update versions in README (2 occurences currently) * update example project (+ push) * use `ls-write-version` * lsync + + * update to next snapshot version diff --git a/README.md b/README.md index e48facfe6..d9e27a5d5 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ How To Use For sbt 0.11/0.12, add sbt-dependency-graph as a dependency in `project/plugins.sbt`: ```scala -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.1") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.2") ``` Then, add the following to your `/build.sbt` (that's not `project/build.sbt`!) as a standalone line: @@ -70,7 +70,7 @@ Standalone usage You can use the project without sbt as well by either depending on the library and calling `IvyGraphMLDependencies.saveAsGraphML(IvyGraphMLDependencies.graph(reportFile), outputFile)` or by just getting the binary -and calling it like `scala sbt-dependency-graph-0.7.0.jar `. +and calling it like `scala sbt-dependency-graph-0.7.2.jar `. Inner Workings -------------- From bfbaed2f03bad6942733329f95c5bf2abf6e4fb2 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 28 Apr 2013 10:41:01 +0200 Subject: [PATCH 111/252] use sbt 0.12.3 for building --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 4474a03e1..9b860e23c 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.12.1 +sbt.version=0.12.3 From dfe76a2aeae9c23aec1cda6b355a83a08d088ca5 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 28 Apr 2013 10:49:47 +0200 Subject: [PATCH 112/252] fixes #30, #31: resolution report path changed in sbt 0.12.3 --- notes/0.7.3.markdown | 1 + src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 notes/0.7.3.markdown diff --git a/notes/0.7.3.markdown b/notes/0.7.3.markdown new file mode 100644 index 000000000..ac3efb880 --- /dev/null +++ b/notes/0.7.3.markdown @@ -0,0 +1 @@ +This is a maintenance release which fixes issues with sbt 0.12.3. Thanks [ebowman](https://github.com/ebowman) for the fix. diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 7b3b0b912..a54005acf 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -67,7 +67,9 @@ object Plugin extends sbt.Plugin { def graphSettings = seq( ivyReportFunction <<= (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 >= 1) => + 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)) From b1edfb4d5bf93a26066e4f5b9004a93655e2872a Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 28 Apr 2013 10:52:57 +0200 Subject: [PATCH 113/252] bump version --- project.sbt | 2 +- src/main/ls/0.7.3.json | 29 +++++++++++++++++++ .../project/plugins.sbt | 2 +- src/sbt-test/sbt-dependency-graph/plugins.sbt | 2 +- 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 src/main/ls/0.7.3.json diff --git a/project.sbt b/project.sbt index 74acc9341..1d1326501 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.7.2" +version := "0.7.3" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) diff --git a/src/main/ls/0.7.3.json b/src/main/ls/0.7.3.json new file mode 100644 index 000000000..dcc5f5fb5 --- /dev/null +++ b/src/main/ls/0.7.3.json @@ -0,0 +1,29 @@ +{ + "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 +} \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt index 6edc33a27..aa477166c 100644 --- a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt +++ b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.2-SNAPSHOT") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.3-SNAPSHOT") diff --git a/src/sbt-test/sbt-dependency-graph/plugins.sbt b/src/sbt-test/sbt-dependency-graph/plugins.sbt index 6edc33a27..aa477166c 100644 --- a/src/sbt-test/sbt-dependency-graph/plugins.sbt +++ b/src/sbt-test/sbt-dependency-graph/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.2-SNAPSHOT") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.3-SNAPSHOT") From b24c5538e4719d3f4f9ab4287a06fb4df82fe2c7 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 28 Apr 2013 11:06:39 +0200 Subject: [PATCH 114/252] update notes to include 0.7.2 notes (which was never officially released) --- notes/0.7.3.markdown | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/notes/0.7.3.markdown b/notes/0.7.3.markdown index ac3efb880..0eb52583a 100644 --- a/notes/0.7.3.markdown +++ b/notes/0.7.3.markdown @@ -1 +1,7 @@ -This is a maintenance release which fixes issues with sbt 0.12.3. Thanks [ebowman](https://github.com/ebowman) for the fix. +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. + * [#60](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. From f629ee79949ff57b19681f8d29438bc0533a7d3e Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 28 Apr 2013 11:07:36 +0200 Subject: [PATCH 115/252] update readme with new versions --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d9e27a5d5..b48ec2503 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ How To Use For sbt 0.11/0.12, add sbt-dependency-graph as a dependency in `project/plugins.sbt`: ```scala -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.2") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.3") ``` Then, add the following to your `/build.sbt` (that's not `project/build.sbt`!) as a standalone line: @@ -70,7 +70,7 @@ Standalone usage You can use the project without sbt as well by either depending on the library and calling `IvyGraphMLDependencies.saveAsGraphML(IvyGraphMLDependencies.graph(reportFile), outputFile)` or by just getting the binary -and calling it like `scala sbt-dependency-graph-0.7.2.jar `. +and calling it like `scala sbt-dependency-graph-0.7.3.jar `. Inner Workings -------------- From 4cc1309b18aa3dfedc95e8cdd64cfbb3d3653c23 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 25 Jun 2013 14:11:33 +0200 Subject: [PATCH 116/252] fix release notes --- notes/0.7.3.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notes/0.7.3.markdown b/notes/0.7.3.markdown index 0eb52583a..4fc8b1f75 100644 --- a/notes/0.7.3.markdown +++ b/notes/0.7.3.markdown @@ -2,6 +2,6 @@ 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. - * [#60](https://github.com/jrudolph/sbt-dependency-graph/issues/30) & [#31](https://github.com/jrudolph/sbt-dependency-graph/issues/31): + * [#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. From 3a8a08a2a20f7995bbb3d26710ab60d6fe12c6c9 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 25 Jun 2013 15:11:24 +0200 Subject: [PATCH 117/252] fix #32: provide Graph for all sbt versions and don't rely on jline terminal width being > 0 --- notes/0.7.4.markdown | 1 + .../SbtDependencyGraphCompat.scala} | 12 ++++++------ .../SbtDependencyGraphCompat.scala} | 12 ++++++------ .../net/virtualvoid/sbt/graph}/Graph.scala | 16 +++++++++++++--- .../sbt/graph/IvyGraphMLDependencies.scala | 2 +- .../scala/net/virtualvoid/sbt/graph/Plugin.scala | 4 ++-- 6 files changed, 29 insertions(+), 18 deletions(-) create mode 100644 notes/0.7.4.markdown rename src/main/scala-sbt-0.11/{net/virtualvoid/sbt/graph/Compat.scala => sbt/SbtDependencyGraphCompat.scala} (82%) rename src/main/scala-sbt-0.12/{net/virtualvoid/sbt/graph/Compat.scala => sbt/SbtDependencyGraphCompat.scala} (84%) rename src/main/{scala-sbt-0.11 => scala/net/virtualvoid/sbt/graph}/Graph.scala (73%) diff --git a/notes/0.7.4.markdown b/notes/0.7.4.markdown new file mode 100644 index 000000000..ac535986a --- /dev/null +++ b/notes/0.7.4.markdown @@ -0,0 +1 @@ +This is a maintenance release fixing an exception when generating graphs without a terminal [#32](https://github.com/jrudolph/sbt-dependency-graph/issues/32). diff --git a/src/main/scala-sbt-0.11/net/virtualvoid/sbt/graph/Compat.scala b/src/main/scala-sbt-0.11/sbt/SbtDependencyGraphCompat.scala similarity index 82% rename from src/main/scala-sbt-0.11/net/virtualvoid/sbt/graph/Compat.scala rename to src/main/scala-sbt-0.11/sbt/SbtDependencyGraphCompat.scala index 7b1a7e0f9..6a4bc3535 100644 --- a/src/main/scala-sbt-0.11/net/virtualvoid/sbt/graph/Compat.scala +++ b/src/main/scala-sbt-0.11/sbt/SbtDependencyGraphCompat.scala @@ -1,11 +1,9 @@ -package net.virtualvoid.sbt.graph +package sbt -import sbt._ +import net.virtualvoid.sbt.graph.Plugin._ import Keys._ -import Plugin.ignoreMissingUpdate - -object Compat { +object SbtDependencyGraphCompat { /** * This is copied directly from sbt/main/Defaults.java and then changed to update the UpdateConfiguration * to ignore missing artifacts. @@ -20,4 +18,6 @@ object Compat { import complete.DefaultParsers._ lazy val StringBasic = NotSpaceClass.*.string -} \ No newline at end of file + + def getTerminalWidth: Int = jline.Terminal.getTerminal.getTerminalWidth +} diff --git a/src/main/scala-sbt-0.12/net/virtualvoid/sbt/graph/Compat.scala b/src/main/scala-sbt-0.12/sbt/SbtDependencyGraphCompat.scala similarity index 84% rename from src/main/scala-sbt-0.12/net/virtualvoid/sbt/graph/Compat.scala rename to src/main/scala-sbt-0.12/sbt/SbtDependencyGraphCompat.scala index 5bc770217..72826e3f5 100644 --- a/src/main/scala-sbt-0.12/net/virtualvoid/sbt/graph/Compat.scala +++ b/src/main/scala-sbt-0.12/sbt/SbtDependencyGraphCompat.scala @@ -1,11 +1,9 @@ -package net.virtualvoid.sbt.graph +package sbt -import sbt._ +import net.virtualvoid.sbt.graph.Plugin._ import Keys._ -import Plugin.ignoreMissingUpdate - -object Compat { +object SbtDependencyGraphCompat { /** * This is copied directly from sbt/main/Defaults.java and then changed to update the UpdateConfiguration * to ignore missing artifacts. @@ -19,4 +17,6 @@ object Compat { Classpaths.cachedUpdate(cacheDirectory / "update", Project.display(ref), module, missingOkConfig, Some(si), skip = skip, force = isRoot, depsUpdated = depsUpdated, log = s.log) } tag(Tags.Update, Tags.Network) -} \ No newline at end of file + + def getTerminalWidth: Int = JLine.usingTerminal(_.getTerminalWidth) +} diff --git a/src/main/scala-sbt-0.11/Graph.scala b/src/main/scala/net/virtualvoid/sbt/graph/Graph.scala similarity index 73% rename from src/main/scala-sbt-0.11/Graph.scala rename to src/main/scala/net/virtualvoid/sbt/graph/Graph.scala index ce4b8da7f..c8cd76a48 100644 --- a/src/main/scala-sbt-0.11/Graph.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Graph.scala @@ -3,7 +3,9 @@ * * Copied from sbt 0.12 source code */ -package sbt +package net.virtualvoid.sbt.graph + +import sbt.SbtDependencyGraphCompat object Graph { @@ -12,8 +14,10 @@ object Graph // [info] | +-baz // [info] | // [info] +-quux - def toAscii[A](top: A, children: A => Seq[A], display: A => String): String = { - val maxColumn = jline.Terminal.getTerminal.getTerminalWidth - 8 + 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) + ".." @@ -40,4 +44,10 @@ object Graph toAsciiLines(top, 0).mkString("\n") } + + def defaultColumnSize: Int = { + val termWidth = SbtDependencyGraphCompat.getTerminalWidth + if (termWidth > 20) termWidth - 8 + else 80 // ignore termWidth + } } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index f9aa49eaa..ab80dced7 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -21,7 +21,7 @@ import java.io.File import collection.mutable.HashMap import collection.mutable.MultiMap import collection.mutable.{Set => MSet} -import sbt.{ConsoleLogger, Graph} +import sbt.ConsoleLogger import xml.{NodeSeq, Document, XML, Node} import com.github.mdr.ascii.layout import layout._ diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index a54005acf..4ca5fd38a 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -79,7 +79,7 @@ object Plugin extends sbt.Plugin { (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c)) } }, - Compat.ignoreMissingUpdateT, + SbtDependencyGraphCompat.ignoreMissingUpdateT, filterScalaLibrary in Global := true ) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(ivyReportForConfig) @@ -181,7 +181,7 @@ object Plugin extends sbt.Plugin { val graph = loadFromContext(moduleGraphStore, ctx, state) getOrElse ModuleGraph(Nil, Nil) import complete.DefaultParsers._ - import Compat._ + import SbtDependencyGraphCompat._ def moduleFrom(modules: Seq[ModuleId]) = modules.map { m => From 3325cdb833c5f430376bfce2d5a31e0bdff8d310 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 25 Jun 2013 15:11:32 +0200 Subject: [PATCH 118/252] bump version --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index 1d1326501..f630a008e 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.7.3" +version := "0.7.4" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From a724b92a5d5c88e941ea1004cf6c2e3f1d349631 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 26 Jun 2013 11:30:14 +0200 Subject: [PATCH 119/252] upgrade documentation + tests to 0.7.4 --- README.md | 4 +-- src/main/ls/0.7.4.json | 29 +++++++++++++++++++ .../project/plugins.sbt | 2 +- src/sbt-test/sbt-dependency-graph/plugins.sbt | 2 +- 4 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 src/main/ls/0.7.4.json diff --git a/README.md b/README.md index b48ec2503..e86656d92 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ How To Use For sbt 0.11/0.12, add sbt-dependency-graph as a dependency in `project/plugins.sbt`: ```scala -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.3") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.4") ``` Then, add the following to your `/build.sbt` (that's not `project/build.sbt`!) as a standalone line: @@ -70,7 +70,7 @@ Standalone usage You can use the project without sbt as well by either depending on the library and calling `IvyGraphMLDependencies.saveAsGraphML(IvyGraphMLDependencies.graph(reportFile), outputFile)` or by just getting the binary -and calling it like `scala sbt-dependency-graph-0.7.3.jar `. +and calling it like `scala sbt-dependency-graph-0.7.4.jar `. Inner Workings -------------- diff --git a/src/main/ls/0.7.4.json b/src/main/ls/0.7.4.json new file mode 100644 index 000000000..00fecdd84 --- /dev/null +++ b/src/main/ls/0.7.4.json @@ -0,0 +1,29 @@ +{ + "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 +} \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt index aa477166c..3c9aed76f 100644 --- a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt +++ b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.3-SNAPSHOT") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.4") diff --git a/src/sbt-test/sbt-dependency-graph/plugins.sbt b/src/sbt-test/sbt-dependency-graph/plugins.sbt index aa477166c..3c9aed76f 100644 --- a/src/sbt-test/sbt-dependency-graph/plugins.sbt +++ b/src/sbt-test/sbt-dependency-graph/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.3-SNAPSHOT") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.4") From 83c1f8cc8c89de690488aaf5ee2e3bfb89341c4f Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 26 Jun 2013 11:34:12 +0200 Subject: [PATCH 120/252] next version --- project.sbt | 2 +- .../intervalRangedVersions/project/plugins.sbt | 2 +- src/sbt-test/sbt-dependency-graph/plugins.sbt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) mode change 100644 => 120000 src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt diff --git a/project.sbt b/project.sbt index f630a008e..9d5e2e7ca 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.7.4" +version := "0.7.5-SNAPSHOT" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) diff --git a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt deleted file mode 100644 index 3c9aed76f..000000000 --- a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.4") diff --git a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt new file mode 120000 index 000000000..0caf1de77 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt @@ -0,0 +1 @@ +../../plugins.sbt \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/plugins.sbt b/src/sbt-test/sbt-dependency-graph/plugins.sbt index 3c9aed76f..7325de692 100644 --- a/src/sbt-test/sbt-dependency-graph/plugins.sbt +++ b/src/sbt-test/sbt-dependency-graph/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.4") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.5-SNAPSHOT") From be3c4631576e062db4db1522ea4e64f00df82a23 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 2 Jul 2013 13:56:00 +0200 Subject: [PATCH 121/252] upgrade to sbt 0.12.4 --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 9b860e23c..5e96e9672 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.12.3 +sbt.version=0.12.4 From 7acc3ac3f6431a71807f3538cc0bec7691cb99ae Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Jul 2013 16:02:49 +0200 Subject: [PATCH 122/252] use new sbt-cross-building plugin --- build.sbt | 2 ++ project/plugins.sbt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 5e74aa15e..3c1a62542 100644 --- a/build.sbt +++ b/build.sbt @@ -2,6 +2,8 @@ seq(lsSettings :_*) CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12") +crossBuildingSettings + CrossBuilding.scriptedSettings libraryDependencies += "com.github.mdr" %% "ascii-graphs" % "0.0.2" diff --git a/project/plugins.sbt b/project/plugins.sbt index 80dd7f871..fe876fa09 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,4 +4,4 @@ addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.2") resolvers += "Coda Hale's Repo" at "http://repo.codahale.com" -addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.7.0") +addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.8.0-RC1") From 0ff4284cb6ad6e88faffd98ed2bb805d204a577d Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Jul 2013 16:03:39 +0200 Subject: [PATCH 123/252] add sbt 0.13 to the cross building versions --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 3c1a62542..0079bca58 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ seq(lsSettings :_*) -CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12") +CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12", "0.13") crossBuildingSettings From 236ecf9e6beab1d5a3a1b9e4df884d51fc8a3162 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Jul 2013 16:04:58 +0200 Subject: [PATCH 124/252] fix dependencies to use versions which are available for scala 2.9 and 2.10 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 0079bca58..4d8645611 100644 --- a/build.sbt +++ b/build.sbt @@ -6,4 +6,4 @@ crossBuildingSettings CrossBuilding.scriptedSettings -libraryDependencies += "com.github.mdr" %% "ascii-graphs" % "0.0.2" +libraryDependencies += "com.github.mdr" %% "ascii-graphs" % "0.0.3" From 5817584e44e6347ca3423ae6d715047b1769854b Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Jul 2013 16:11:59 +0200 Subject: [PATCH 125/252] workaround for jrudolph/sbt-cross-building#24 --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 4d8645611..579a1c8ad 100644 --- a/build.sbt +++ b/build.sbt @@ -1,9 +1,9 @@ seq(lsSettings :_*) -CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12", "0.13") - crossBuildingSettings +CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12", "0.13") + CrossBuilding.scriptedSettings libraryDependencies += "com.github.mdr" %% "ascii-graphs" % "0.0.3" From 60aa77dc1030ab78318955b22fab4012fc87868d Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Jul 2013 16:12:10 +0200 Subject: [PATCH 126/252] more warnings --- build.sbt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.sbt b/build.sbt index 579a1c8ad..308327c27 100644 --- a/build.sbt +++ b/build.sbt @@ -7,3 +7,5 @@ CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12", "0.1 CrossBuilding.scriptedSettings libraryDependencies += "com.github.mdr" %% "ascii-graphs" % "0.0.3" + +scalacOptions ++= Seq("-deprecation", "-unchecked") From 8836c5e174b5d1438143cf98aa5d7c11b0f5d395 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Jul 2013 16:12:44 +0200 Subject: [PATCH 127/252] use linked plugins.sbt for all scripted tests --- .../intervalRangedVersions/project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 120000 src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt diff --git a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt deleted file mode 100644 index aa477166c..000000000 --- a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.3-SNAPSHOT") diff --git a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt new file mode 120000 index 000000000..0caf1de77 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt @@ -0,0 +1 @@ +../../plugins.sbt \ No newline at end of file From f8b00e65119f9f5d80b95f6e5f18f95d583b8cf8 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Jul 2013 16:13:06 +0200 Subject: [PATCH 128/252] give every sub-project its own directory in scripted test --- .../testDotFileGeneration/project/Build.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala index 2becd0917..a4a1622ba 100644 --- a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala +++ b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala @@ -10,20 +10,20 @@ object Build extends sbt.Build { seq(scalaVersion := "2.9.2") lazy val justATransiviteDependencyEndpointProject = - Project("just-a-transitive-dependency-endpoint", file(".")) + Project("just-a-transitive-dependency-endpoint", file("a")) .settings(defaultSettings: _*) lazy val justATransitiveDependencyProject = - Project("just-a-transitive-dependency", file(".")) + Project("just-a-transitive-dependency", file("b")) .settings(defaultSettings: _*) .dependsOn(justATransiviteDependencyEndpointProject) lazy val justADependencyProject = - Project("just-a-dependency", file(".")) + Project("just-a-dependency", file("c")) .settings(defaultSettings: _*) lazy val test_project = - Project("test-dot-file-generation", file(".")) + Project("test-dot-file-generation", file("d")) .settings(graphSettings: _*) .settings(defaultSettings: _*) .settings( From 2b20d7fa4190e377d3be4fd39112abbbe5d1383c Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Jul 2013 16:13:58 +0200 Subject: [PATCH 129/252] fix test to use scala version known to have no conflicts --- .../sbt-dependency-graph/intervalRangedVersions/build.sbt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt index 19030bcf6..0ef12f58a 100644 --- a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt +++ b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt @@ -2,7 +2,7 @@ import net.virtualvoid.sbt.graph.Plugin._ graphSettings -scalaVersion := "2.9.2" +scalaVersion := "2.9.1" libraryDependencies ++= Seq( "com.codahale" % "jerkson_2.9.1" % "0.5.0" @@ -13,9 +13,9 @@ TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, 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.12 - | +-org.codehaus.jackson:jackson-mapper-asl:1.9.12 - | +-org.codehaus.jackson:jackson-core-asl:1.9.12 + | +-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 | """.stripMargin IO.writeLines(file("/tmp/blib"), sanitize(graph).split("\n")) IO.writeLines(file("/tmp/blub"), sanitize(expectedGraph).split("\n")) From 9d373bee73b65b04055dfd0fb2356363da20dd7a Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Jul 2013 16:20:56 +0200 Subject: [PATCH 130/252] reorganize ignoreMissingUpdate to rely on `updateConfiguration in ignoreMissingUpdate` --- src/main/scala-sbt-0.11/sbt/SbtDependencyGraphCompat.scala | 5 ++--- src/main/scala-sbt-0.12/sbt/SbtDependencyGraphCompat.scala | 5 ++--- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 1 + 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/scala-sbt-0.11/sbt/SbtDependencyGraphCompat.scala b/src/main/scala-sbt-0.11/sbt/SbtDependencyGraphCompat.scala index 6a4bc3535..e6ff9bb49 100644 --- a/src/main/scala-sbt-0.11/sbt/SbtDependencyGraphCompat.scala +++ b/src/main/scala-sbt-0.11/sbt/SbtDependencyGraphCompat.scala @@ -9,11 +9,10 @@ object SbtDependencyGraphCompat { * to ignore missing artifacts. */ def ignoreMissingUpdateT = - ignoreMissingUpdate <<= (ivyModule, thisProjectRef, updateConfiguration, cacheDirectory, scalaInstance, transitiveUpdate, streams) map { (module, ref, config, cacheDirectory, si, reports, s) => + ignoreMissingUpdate <<= (ivyModule, thisProjectRef, updateConfiguration in ignoreMissingUpdate, cacheDirectory, scalaInstance, transitiveUpdate, streams) map { (module, ref, config, cacheDirectory, si, reports, s) => val depsUpdated = reports.exists(!_.stats.cached) - val missingOkConfig = new UpdateConfiguration(config.retrieve, true, config.logging) - Classpaths.cachedUpdate(cacheDirectory / "update", Project.display(ref), module, missingOkConfig, Some(si), depsUpdated, s.log) + Classpaths.cachedUpdate(cacheDirectory / "update", Project.display(ref), module, config, Some(si), depsUpdated, s.log) } import complete.DefaultParsers._ diff --git a/src/main/scala-sbt-0.12/sbt/SbtDependencyGraphCompat.scala b/src/main/scala-sbt-0.12/sbt/SbtDependencyGraphCompat.scala index 72826e3f5..56df72740 100644 --- a/src/main/scala-sbt-0.12/sbt/SbtDependencyGraphCompat.scala +++ b/src/main/scala-sbt-0.12/sbt/SbtDependencyGraphCompat.scala @@ -9,13 +9,12 @@ object SbtDependencyGraphCompat { * to ignore missing artifacts. */ def ignoreMissingUpdateT = - ignoreMissingUpdate <<= (ivyModule, thisProjectRef, updateConfiguration, cacheDirectory, scalaInstance, transitiveUpdate, executionRoots, resolvedScoped, skip in update, streams) map { + ignoreMissingUpdate <<= (ivyModule, thisProjectRef, updateConfiguration in ignoreMissingUpdate, cacheDirectory, scalaInstance, transitiveUpdate, executionRoots, resolvedScoped, skip in update, streams) map { (module, ref, config, cacheDirectory, si, reports, roots, resolved, skip, s) => val depsUpdated = reports.exists(!_.stats.cached) val isRoot = roots contains resolved - val missingOkConfig = new UpdateConfiguration(config.retrieve, true, config.logging) - Classpaths.cachedUpdate(cacheDirectory / "update", Project.display(ref), module, missingOkConfig, Some(si), skip = skip, force = isRoot, depsUpdated = depsUpdated, log = s.log) + Classpaths.cachedUpdate(cacheDirectory / "update", Project.display(ref), module, config, Some(si), skip = skip, force = isRoot, depsUpdated = depsUpdated, log = s.log) } tag(Tags.Update, Tags.Network) def getTerminalWidth: Int = JLine.usingTerminal(_.getTerminalWidth) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 4ca5fd38a..24f6cca6a 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -79,6 +79,7 @@ object Plugin extends sbt.Plugin { (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c)) } }, + updateConfiguration in ignoreMissingUpdate <<= updateConfiguration(config => new UpdateConfiguration(config.retrieve, true, config.logging)), SbtDependencyGraphCompat.ignoreMissingUpdateT, filterScalaLibrary in Global := true ) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(ivyReportForConfig) From f7c66f5cd174280845cd5b8ec1d267c833ecfcf7 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Jul 2013 16:24:15 +0200 Subject: [PATCH 131/252] add support for sbt 0.13, fixes #35 --- build.sbt | 5 +++ .../sbt/SbtDependencyGraphCompat.scala | 39 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/main/scala-sbt-0.13/sbt/SbtDependencyGraphCompat.scala diff --git a/build.sbt b/build.sbt index 308327c27..5000fd925 100644 --- a/build.sbt +++ b/build.sbt @@ -8,4 +8,9 @@ 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 +} + scalacOptions ++= Seq("-deprecation", "-unchecked") diff --git a/src/main/scala-sbt-0.13/sbt/SbtDependencyGraphCompat.scala b/src/main/scala-sbt-0.13/sbt/SbtDependencyGraphCompat.scala new file mode 100644 index 000000000..a75305639 --- /dev/null +++ b/src/main/scala-sbt-0.13/sbt/SbtDependencyGraphCompat.scala @@ -0,0 +1,39 @@ +package sbt + +import net.virtualvoid.sbt.graph.Plugin._ +import Keys._ +import CrossVersion._ + +object SbtDependencyGraphCompat { + /** + * 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] = 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 => 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) + } + + def getTerminalWidth: Int = JLine.usingTerminal(_.getWidth) +} From 0bcd2e03f49f6c7133e9ef9e40b95d40970e4a29 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 31 Jul 2013 15:22:45 +0200 Subject: [PATCH 132/252] fixes #36: Graph.insertBar doesn't take maxColumn into account leading to StringIndexOutOfBoundsException --- build.sbt | 5 ++ .../net/virtualvoid/sbt/graph/Graph.scala | 14 +++-- .../virtualvoid/sbt/graph/GraphSpecs.scala | 55 +++++++++++++++++++ 3 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 src/test/scala/net/virtualvoid/sbt/graph/GraphSpecs.scala diff --git a/build.sbt b/build.sbt index 5000fd925..7401e1f27 100644 --- a/build.sbt +++ b/build.sbt @@ -13,4 +13,9 @@ libraryDependencies <++= scalaVersion { version => 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.1.1" % "test" +} + scalacOptions ++= Seq("-deprecation", "-unchecked") diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Graph.scala b/src/main/scala/net/virtualvoid/sbt/graph/Graph.scala index c8cd76a48..c351fa71a 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Graph.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Graph.scala @@ -23,12 +23,14 @@ object Graph if (s.length > maxColumn) s.slice(0, maxColumn - 2) + ".." else s def insertBar(s: String, at: Int): String = - s.slice(0, at) + - (s(at).toString match { - case " " => "|" - case x => x - }) + - s.slice(at + 1, s.length) + if (at < s.length) + s.slice(0, at) + + (s(at).toString match { + case " " => "|" + case x => x + }) + + s.slice(at + 1, s.length) + else s def toAsciiLines(node: A, level: Int): Vector[String] = { val line = limitLine((twoSpaces * level) + (if (level == 0) "" else "+-") + display(node)) val cs = Vector(children(node): _*) diff --git a/src/test/scala/net/virtualvoid/sbt/graph/GraphSpecs.scala b/src/test/scala/net/virtualvoid/sbt/graph/GraphSpecs.scala new file mode 100644 index 000000000..208ff5227 --- /dev/null +++ b/src/test/scala/net/virtualvoid/sbt/graph/GraphSpecs.scala @@ -0,0 +1,55 @@ +package net.virtualvoid.sbt.graph + +import org.specs2.mutable.Specification + +class GraphSpecs extends Specification { + sealed trait Tree + case class Branch(left: Tree, right: Tree) extends Tree + case class Leaf(i: Int) extends Tree + + def children(t: Tree): Seq[Tree] = t match { + case Branch(left, right) => Seq(left, right) + case _: Leaf => Nil + } + def display(t: Tree): String = t match { + case Branch(left, right) => "Branch" + case Leaf(value) => value.toString * value + } + + "Graph" should { + "layout simple graphs" in { + val simple = Branch(Branch(Leaf(1), Leaf(2)), Leaf(3)) + Graph.toAscii(simple, children, display, 20) === + """Branch + | +-Branch + | | +-1 + | | +-22 + | |\u0020 + | +-333 + | """.stripMargin + } + "layout deep graphs" in { + val simple = Branch(Branch(Branch(Branch(Branch(Branch(Leaf(1), Leaf(1)), Leaf(1)), Leaf(1)), Leaf(2)), Leaf(3)), Leaf(4)) + Graph.toAscii(simple, children, display, 10) === + """Branch + | +-Branch + | | +-Br.. + | | | +-.. + | | | | .. + | | | | .. + | | | | .. + | | | | .. + | | | | | |\u0020 + | | | | .. + | | | | |\u0020 + | | | | .. + | | | |\u0020 + | | | +-22 + | | |\u0020 + | | +-333 + | |\u0020 + | +-4444 + | """.stripMargin + } + } +} From ff8d9b82b02295a437ec39469efeaab375228fe5 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 26 Aug 2013 12:53:03 +0200 Subject: [PATCH 133/252] README: separate tasks & settings and add configuration example, fixes #37 Also setting names were converted to Scala syntax. --- README.md | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e86656d92..bfdfde268 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,8 @@ object MyBuild extends Build { Check out the [example project] for a skeleton build setup. -Tasks & Settings ----------------- +Tasks +----- * `dependency-graph`: Shows an ASCII graph of the project's dependencies on the sbt console * `dependency-graph-ml`: Generates a .graphml file with the project's dependencies to `target/dependencies-.graphml`. @@ -50,14 +50,6 @@ Tasks & Settings * `what-depends-on `: Find out what depends on an artifact. Shows a reverse dependency tree for the selected module. * `dependency-license-info`: show dependencies grouped by declared license - * `filter-scala-library`: Defines if the scala library should be excluded from the output of the dependency-* functions. - If `true`, instead of showing the dependency `"[S]"` is appended to the artifact name. Set to `false` if - you want the scala-library dependency to appear in the output. (default: true) - * `dependency-graph-ml-file`: a setting which allows configuring the output path of `dependency-graph-ml`. - * `dependency-dot-file`: a setting which allows configuring the output path of `dependency-dot`. - * `dependency-dot-header`: a setting to customize the header of the dot file (e.g. to set your preferred node shapes). - * `dependency-dot-nodes-label`: defines the formation of a node label - (default set to `[organisation]
[name]
[version]`) * `ivy-report`: let's ivy generate the resolution report for you project. Use `show ivy-report` for the filename of the generated report @@ -65,6 +57,27 @@ All tasks can be scoped to a configuration to get the report for a specific conf for example, prints the dependencies in the `test` configuration. If you don't specify any configuration, `compile` is assumed as usual. + +Configuration settings +---------------------- + + * `filterScalaLibrary`: Defines if the scala library should be excluded from the output of the dependency-* functions. + If `true`, instead of showing the dependency `"[S]"` is appended to the artifact name. Set to `false` if + you want the scala-library dependency to appear in the output. (default: true) + * `dependencyGraphMLFile`: a setting which allows configuring the output path of `dependency-graph-ml`. + * `dependencyDotFile`: a setting which allows configuring the output path of `dependency-dot`. + * `dependencyDotHeader`: a setting to customize the header of the dot file (e.g. to set your preferred node shapes). + * `dependencyDotNodeLabel`: defines the format of a node label + (default set to `[organisation]
[name]
[version]`) + +E.g. in `build.sbt` you can change configuration settings like this: + +```scala +filterScalaLibrary := false // include scala library in output + +dependencyDotFile := file("dependencies.dot") //render dot file to `./dependencies.dot` +``` + Standalone usage ---------------- From 90500a9f9b9775debdc4f07adb503d5edb39cdc3 Mon Sep 17 00:00:00 2001 From: "Paolo G. Giarrusso" Date: Tue, 27 Aug 2013 15:21:37 +0200 Subject: [PATCH 134/252] Also mention 0.13 0.13 release announcement mentions this plugin, in this version: https://groups.google.com/d/msg/simple-build-tool/0AGST5qPbzw/CrN1sJ6ut-AJ Hence, the README should be updated as well. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bfdfde268..def8eb3d0 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Visualize your project's dependencies. How To Use ---------- -For sbt 0.11/0.12, add sbt-dependency-graph as a dependency in `project/plugins.sbt`: +For sbt 0.11/0.12/0.13, add sbt-dependency-graph as a dependency in `project/plugins.sbt`: ```scala addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.4") From 1f65c0c86bafac769a97b73a5d1c4cc43523f120 Mon Sep 17 00:00:00 2001 From: 2beaucoup Date: Wed, 15 Jan 2014 17:07:50 +0100 Subject: [PATCH 135/252] only match scala lib by org/name --- .../virtualvoid/sbt/graph/IvyGraphMLDependencies.scala | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index ab80dced7..3044b13c0 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -118,10 +118,11 @@ object IvyGraphMLDependencies extends App { } def ignoreScalaLibrary(scalaVersion: String, graph: ModuleGraph): ModuleGraph = { - val scalaLibraryId = ModuleId("org.scala-lang", "scala-library", scalaVersion) + def isScalaLibrary(m: Module) = isScalaLibraryId(m.id) + def isScalaLibraryId(id: ModuleId) = id.organisation == "org.scala-lang" && id.name == "scala-library" def dependsOnScalaLibrary(m: Module): Boolean = - graph.dependencyMap(m.id).map(_.id).contains(scalaLibraryId) + graph.dependencyMap(m.id).exists(isScalaLibrary) def addScalaLibraryAnnotation(m: Module): Module = { if (dependsOnScalaLibrary(m)) @@ -130,8 +131,8 @@ object IvyGraphMLDependencies extends App { m } - val newNodes = graph.nodes.map(addScalaLibraryAnnotation).filterNot(_.id == scalaLibraryId) - val newEdges = graph.edges.filterNot(_._2 == scalaLibraryId) + val newNodes = graph.nodes.map(addScalaLibraryAnnotation).filterNot(isScalaLibrary) + val newEdges = graph.edges.filterNot(e => isScalaLibraryId(e._2)) ModuleGraph(newNodes, newEdges) } From dfdba572483f8896813ac76395091efd9078242d Mon Sep 17 00:00:00 2001 From: Jay Taylor Date: Tue, 26 Aug 2014 20:26:08 -0700 Subject: [PATCH 136/252] Clearer messaging for `sbt 'dependency-graph --force'` command. --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 24f6cca6a..4dcb85b68 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -106,7 +106,7 @@ object Plugin extends sbt.Plugin { if (!force) { streams.log.info("\n") - streams.log.info("Note: The graph was estimated to be too big to display (> 15 nodes). Use `dependency-graph --force` to force graph display.") + 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.") } } } From b976fa68a529e36619bddfcad5e3683f2a0d4d3f Mon Sep 17 00:00:00 2001 From: Ches Martin Date: Sat, 13 Dec 2014 00:01:24 +0700 Subject: [PATCH 137/252] Describe how to configure the plugin globally Closes #41 --- README.md | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index def8eb3d0..91320112e 100644 --- a/README.md +++ b/README.md @@ -6,37 +6,23 @@ Visualize your project's dependencies. How To Use ---------- -For sbt 0.11/0.12/0.13, add sbt-dependency-graph as a dependency in `project/plugins.sbt`: +Since sbt-dependency-graph is an informational tool rather than one that changes your build, 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`: ```scala addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.4") ``` -Then, add the following to your `/build.sbt` (that's not `project/build.sbt`!) as a standalone line: +Then, apply the plugin's settings in `~/.sbt/0.13/global.sbt`, the [global build configuration]: ```scala net.virtualvoid.sbt.graph.Plugin.graphSettings ``` -OR, alternatively, if you use the full configuration, i.e. you define your build definition in `project/build.scala`, for example, -to define a multi-module project, you should add - -```scala -.settings(net.virtualvoid.sbt.graph.Plugin.graphSettings: _*) -``` - -to each of the project definitions for which you want to use the plugin. The definition of your project should then -look approximately this way: - -```scala -object MyBuild extends Build { - val proj = - Project("my-project", file("base")) - .settings(net.virtualvoid.sbt.graph.Plugin.graphSettings: _*) -} -``` - -Check out the [example project] for a skeleton build setup. +For both of the above, be sure to use the version directory matching your version of SBT (e.g. 0.12 or 0.13). Be aware that +different projects using SBT may declare particular versions for their builds, so you may need to set up the plugin for an older +version if you encounter a project using one. Tasks ----- @@ -115,4 +101,5 @@ Copyright (c) 2011, 2012 Johannes Rudolph Published under the [Apache License 2.0](http://en.wikipedia.org/wiki/Apache_license). -[example project]: https://gist.github.com/3106492 +[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 From 69946f3e2ca91ff64f296e65c1ec73e9317a6652 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 22 Dec 2014 12:17:52 +0100 Subject: [PATCH 138/252] modernize build --- build.sbt | 4 +--- project.sbt | 7 ------- project/ScalariformSupport.scala | 20 ++++++++++++++++++++ project/build.properties | 2 +- project/gpg.sbt | 3 --- project/pgp.sbt | 1 + project/plugins.sbt | 8 ++------ 7 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 project/ScalariformSupport.scala delete mode 100644 project/gpg.sbt create mode 100644 project/pgp.sbt diff --git a/build.sbt b/build.sbt index 7401e1f27..e3db9eed3 100644 --- a/build.sbt +++ b/build.sbt @@ -1,5 +1,3 @@ -seq(lsSettings :_*) - crossBuildingSettings CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12", "0.13") @@ -15,7 +13,7 @@ libraryDependencies <++= scalaVersion { version => libraryDependencies <+= scalaVersion { version => if (version startsWith "2.9") "org.specs2" % "specs2_2.9.3" % "1.12.4.1" % "test" - else "org.specs2" %% "specs2" % "2.1.1" % "test" + else "org.specs2" %% "specs2" % "2.3.11" % "test" } scalacOptions ++= Seq("-deprecation", "-unchecked") diff --git a/project.sbt b/project.sbt index 9d5e2e7ca..6320ebf46 100644 --- a/project.sbt +++ b/project.sbt @@ -9,10 +9,3 @@ version := "0.7.5-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") - -(LsKeys.tags in LsKeys.lsync) := Seq("dependency", "graph", "sbt-plugin", "sbt") - -(LsKeys.docsUrl in LsKeys.lsync) <<= homepage - -(description in LsKeys.lsync) := - "An sbt plugin to visualize dependencies of your build." diff --git a/project/ScalariformSupport.scala b/project/ScalariformSupport.scala new file mode 100644 index 000000000..665a9e6fe --- /dev/null +++ b/project/ScalariformSupport.scala @@ -0,0 +1,20 @@ +import sbt._ + +import com.typesafe.sbt.SbtScalariform +import com.typesafe.sbt.SbtScalariform.ScalariformKeys + +object ScalariformSupport { + lazy val formatSettings = SbtScalariform.scalariformSettings ++ Seq( + ScalariformKeys.preferences in Compile := formattingPreferences, + ScalariformKeys.preferences in Test := formattingPreferences + ) + + import scalariform.formatter.preferences._ + def formattingPreferences = + FormattingPreferences() + .setPreference(RewriteArrowSymbols, true) + .setPreference(AlignParameters, true) + .setPreference(AlignSingleLineCaseStatements, true) + .setPreference(DoubleIndentClassDeclaration, true) + +} diff --git a/project/build.properties b/project/build.properties index 5e96e9672..748703f77 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.12.4 +sbt.version=0.13.7 diff --git a/project/gpg.sbt b/project/gpg.sbt deleted file mode 100644 index d78507cdd..000000000 --- a/project/gpg.sbt +++ /dev/null @@ -1,3 +0,0 @@ -resolvers += Resolver.url("scalasbt", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases"))(Resolver.ivyStylePatterns) - -addSbtPlugin("com.jsuereth" % "xsbt-gpg-plugin" % "0.6") \ No newline at end of file diff --git a/project/pgp.sbt b/project/pgp.sbt new file mode 100644 index 000000000..4ce4d9ed4 --- /dev/null +++ b/project/pgp.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") diff --git a/project/plugins.sbt b/project/plugins.sbt index fe876fa09..df57f0cef 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,7 +1,3 @@ -resolvers += "less is" at "http://repo.lessis.me" +addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.8.1") -addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.2") - -resolvers += "Coda Hale's Repo" at "http://repo.codahale.com" - -addSbtPlugin("net.virtual-void" % "sbt-cross-building" % "0.8.0-RC1") +addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.2.1") \ No newline at end of file From 25069139bec63ba69169e129df4b41dc3bc3023b Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Fri, 30 Jan 2015 19:55:29 +0000 Subject: [PATCH 139/252] Added Gitter badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 91320112e..ff83beeaa 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ 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. How To Use From ca25facd174089cfede01e984305b1f77ad63c90 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sat, 21 Mar 2015 21:17:12 -0400 Subject: [PATCH 140/252] Fixes #67. Adds InlineConfigurationWithExcludes handling --- src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala index 4dcb85b68..3fcafffa9 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala @@ -199,9 +199,14 @@ object Plugin extends sbt.Plugin { } } + // This is to support 0.13.8's InlineConfigurationWithExcludes while not forcing 0.13.8 + type HasModule = { + val module: ModuleID + } def crossName(ivyModule: IvySbt#Module) = ivyModule.moduleSettings match { case ic: InlineConfiguration => ic.module.name + case hm: HasModule if hm.getClass.getName == "sbt.InlineConfigurationWithExcludes" => hm.module.name case _ => throw new IllegalStateException("sbt-dependency-graph plugin currently only supports InlineConfiguration of ivy settings (the default in sbt)") } From 76fed827f69950152c20ad85d1d13a60742258fa Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 30 Mar 2015 08:00:08 +0200 Subject: [PATCH 141/252] update build to 0.13.8 --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 748703f77..a6e117b61 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.7 +sbt.version=0.13.8 From 2e3a8fa168b57004ef867481a5974c1f734484f1 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 30 Mar 2015 08:12:31 +0200 Subject: [PATCH 142/252] bump version --- README.md | 4 ++-- notes/0.7.5.markdown | 10 ++++++++++ project.sbt | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 notes/0.7.5.markdown diff --git a/README.md b/README.md index 91320112e..2ca1beec6 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ install it as a [global plugin] so that you can use it in any SBT project withou this, add the plugin dependency to `~/.sbt/0.13/plugins/plugins.sbt`: ```scala -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.4") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.5") ``` Then, apply the plugin's settings in `~/.sbt/0.13/global.sbt`, the [global build configuration]: @@ -69,7 +69,7 @@ Standalone usage You can use the project without sbt as well by either depending on the library and calling `IvyGraphMLDependencies.saveAsGraphML(IvyGraphMLDependencies.graph(reportFile), outputFile)` or by just getting the binary -and calling it like `scala sbt-dependency-graph-0.7.4.jar `. +and calling it like `scala sbt-dependency-graph-0.7.5.jar `. Inner Workings -------------- diff --git a/notes/0.7.5.markdown b/notes/0.7.5.markdown new file mode 100644 index 000000000..fbb41457a --- /dev/null +++ b/notes/0.7.5.markdown @@ -0,0 +1,10 @@ +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. diff --git a/project.sbt b/project.sbt index 6320ebf46..8f3b981ab 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.7.5-SNAPSHOT" +version := "0.7.5" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From aebf329d8ce4042bde06f872bfd414c543c34d14 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 8 Jul 2015 09:05:56 +0200 Subject: [PATCH 143/252] Clarify use. Fixes #75. --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2ca1beec6..bb0b41e1f 100644 --- a/README.md +++ b/README.md @@ -14,15 +14,13 @@ this, add the plugin dependency to `~/.sbt/0.13/plugins/plugins.sbt`: addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.5") ``` -Then, apply the plugin's settings in `~/.sbt/0.13/global.sbt`, the [global build configuration]: +Then, apply the plugin's settings in `~/.sbt/0.13/global.sbt`, the [global build configuration], by adding the following line: ```scala net.virtualvoid.sbt.graph.Plugin.graphSettings ``` -For both of the above, be sure to use the version directory matching your version of SBT (e.g. 0.12 or 0.13). Be aware that -different projects using SBT may declare particular versions for their builds, so you may need to set up the plugin for an older -version if you encounter a project using one. +Note, that sbt-dependency-graph is not an [AutoPlugin](http://www.scala-sbt.org/0.13/docs/Plugins.html#Creating+an+auto+plugin) yet (until [#51](https://github.com/jrudolph/sbt-dependency-graph/issues/51) is fixed), so adding the above line to your global or project configuration is mandatory. Tasks ----- From 827a896e3c096a369f28f021a03b99cf0209819c Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 14 Nov 2015 16:23:39 +0100 Subject: [PATCH 144/252] bump version --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index 8f3b981ab..c61f29c46 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.7.5" +version := "0.8.0-SNAPSHOT" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From 7b0e090662300e03f746aeb6771f9fe94a9b2520 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 14 Nov 2015 16:25:13 +0100 Subject: [PATCH 145/252] remove support for sbt 0.11 + 0.12 --- build.sbt | 9 +++++++- .../sbt/SbtDependencyGraphCompat.scala | 22 ------------------- .../sbt/SbtDependencyGraphCompat.scala | 21 ------------------ 3 files changed, 8 insertions(+), 44 deletions(-) delete mode 100644 src/main/scala-sbt-0.11/sbt/SbtDependencyGraphCompat.scala delete mode 100644 src/main/scala-sbt-0.12/sbt/SbtDependencyGraphCompat.scala diff --git a/build.sbt b/build.sbt index e3db9eed3..201ba01c7 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ crossBuildingSettings -CrossBuilding.crossSbtVersions := Seq("0.11.1", "0.11.2", "0.11.3", "0.12", "0.13") +CrossBuilding.crossSbtVersions := Seq("0.13") CrossBuilding.scriptedSettings @@ -17,3 +17,10 @@ libraryDependencies <+= scalaVersion { version => } scalacOptions ++= Seq("-deprecation", "-unchecked") + +sbt.CrossBuilding.latestCompatibleVersionMapper ~= { + original => { + case "0.13" => "0.13.8" + case x => original(x) + } +} diff --git a/src/main/scala-sbt-0.11/sbt/SbtDependencyGraphCompat.scala b/src/main/scala-sbt-0.11/sbt/SbtDependencyGraphCompat.scala deleted file mode 100644 index e6ff9bb49..000000000 --- a/src/main/scala-sbt-0.11/sbt/SbtDependencyGraphCompat.scala +++ /dev/null @@ -1,22 +0,0 @@ -package sbt - -import net.virtualvoid.sbt.graph.Plugin._ -import Keys._ - -object SbtDependencyGraphCompat { - /** - * This is copied directly from sbt/main/Defaults.java and then changed to update the UpdateConfiguration - * to ignore missing artifacts. - */ - def ignoreMissingUpdateT = - ignoreMissingUpdate <<= (ivyModule, thisProjectRef, updateConfiguration in ignoreMissingUpdate, cacheDirectory, scalaInstance, transitiveUpdate, streams) map { (module, ref, config, cacheDirectory, si, reports, s) => - val depsUpdated = reports.exists(!_.stats.cached) - - Classpaths.cachedUpdate(cacheDirectory / "update", Project.display(ref), module, config, Some(si), depsUpdated, s.log) - } - - import complete.DefaultParsers._ - lazy val StringBasic = NotSpaceClass.*.string - - def getTerminalWidth: Int = jline.Terminal.getTerminal.getTerminalWidth -} diff --git a/src/main/scala-sbt-0.12/sbt/SbtDependencyGraphCompat.scala b/src/main/scala-sbt-0.12/sbt/SbtDependencyGraphCompat.scala deleted file mode 100644 index 56df72740..000000000 --- a/src/main/scala-sbt-0.12/sbt/SbtDependencyGraphCompat.scala +++ /dev/null @@ -1,21 +0,0 @@ -package sbt - -import net.virtualvoid.sbt.graph.Plugin._ -import Keys._ - -object SbtDependencyGraphCompat { - /** - * This is copied directly from sbt/main/Defaults.java and then changed to update the UpdateConfiguration - * to ignore missing artifacts. - */ - def ignoreMissingUpdateT = - ignoreMissingUpdate <<= (ivyModule, thisProjectRef, updateConfiguration in ignoreMissingUpdate, cacheDirectory, scalaInstance, transitiveUpdate, executionRoots, resolvedScoped, skip in update, streams) map { - (module, ref, config, cacheDirectory, si, reports, roots, resolved, skip, s) => - val depsUpdated = reports.exists(!_.stats.cached) - val isRoot = roots contains resolved - - Classpaths.cachedUpdate(cacheDirectory / "update", Project.display(ref), module, config, Some(si), skip = skip, force = isRoot, depsUpdated = depsUpdated, log = s.log) - } tag(Tags.Update, Tags.Network) - - def getTerminalWidth: Int = JLine.usingTerminal(_.getTerminalWidth) -} From adc55e31a72fed0fa630c70c8f3b731c80516066 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 14 Nov 2015 16:26:43 +0100 Subject: [PATCH 146/252] reorganize plugin sources and make this an AutoPlugin --- .../sbt/SbtDependencyGraphCompat.scala | 39 ------ .../sbt/graph/DependencyGraphKeys.scala | 61 +++++++++ .../sbt/graph/DependencyGraphPlugin.scala | 26 ++++ ...in.scala => DependencyGraphSettings.scala} | 116 +++++++++--------- .../net/virtualvoid/sbt/graph/Graph.scala | 4 +- src/main/scala/sbt/SbtAccess.scala | 23 ++++ 6 files changed, 167 insertions(+), 102 deletions(-) delete mode 100644 src/main/scala-sbt-0.13/sbt/SbtDependencyGraphCompat.scala create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala create mode 100755 src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphPlugin.scala rename src/main/scala/net/virtualvoid/sbt/graph/{Plugin.scala => DependencyGraphSettings.scala} (67%) mode change 100755 => 100644 create mode 100644 src/main/scala/sbt/SbtAccess.scala diff --git a/src/main/scala-sbt-0.13/sbt/SbtDependencyGraphCompat.scala b/src/main/scala-sbt-0.13/sbt/SbtDependencyGraphCompat.scala deleted file mode 100644 index a75305639..000000000 --- a/src/main/scala-sbt-0.13/sbt/SbtDependencyGraphCompat.scala +++ /dev/null @@ -1,39 +0,0 @@ -package sbt - -import net.virtualvoid.sbt.graph.Plugin._ -import Keys._ -import CrossVersion._ - -object SbtDependencyGraphCompat { - /** - * 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] = 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 => 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) - } - - def getTerminalWidth: Int = JLine.usingTerminal(_.getWidth) -} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala new file mode 100644 index 000000000..1d8ef8a8a --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -0,0 +1,61 @@ +/* + * Copyright 2014 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 + +import sbt._ + +trait DependencyGraphKeys { + val dependencyGraphMLFile = SettingKey[File]("dependency-graph-ml-file", + "The location the graphml file should be generated at") + 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", + "The location the dot file should be generated at") + 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", + "The header of the dot file. (e.g. to set your preferred node shapes)") + val dependencyDot = TaskKey[File]("dependency-dot", + "Creates a dot file containing the dpendency-graph for a project") + val moduleGraph = TaskKey[IvyGraphMLDependencies.ModuleGraph]("module-graph", + "The dependency graph for a project") + 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", + "Prints the ascii graph to the console") + 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", + "Prints the ascii tree to the console") + 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", + "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", + "Specifies if scala dependency should be filtered in dependency-* output" + ) + + val licenseInfo = TaskKey[Unit]("dependency-license-info", + "Aggregates and shows information about the licenses of dependencies") + + // internal + private[graph] val moduleGraphStore = TaskKey[IvyGraphMLDependencies.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") +} + +object DependencyGraphKeys extends DependencyGraphKeys \ No newline at end of file diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphPlugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphPlugin.scala new file mode 100755 index 000000000..9389fe8f9 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphPlugin.scala @@ -0,0 +1,26 @@ +/* + * Copyright 2011, 2012 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 + +import sbt._ +import Keys._ + +object DependencyGraphPlugin extends AutoPlugin { + object autoImport extends DependencyGraphKeys + + override def projectSettings: Seq[Def.Setting[_]] = DependencyGraphSettings.graphSettings +} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala old mode 100755 new mode 100644 similarity index 67% rename from src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala rename to src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index 3fcafffa9..f943e2d96 --- a/src/main/scala/net/virtualvoid/sbt/graph/Plugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -1,5 +1,5 @@ /* - * Copyright 2011, 2012 Johannes Rudolph + * Copyright 2015 Johannes Rudolph * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,53 +18,21 @@ package net.virtualvoid.sbt.graph import sbt._ import Keys._ -import complete.Parser + +import CrossVersion._ + +import sbt.complete.DefaultParsers._ +import sbt.complete.Parser import org.apache.ivy.core.resolve.ResolveOptions -import net.virtualvoid.sbt.graph.IvyGraphMLDependencies.ModuleGraph -object Plugin extends sbt.Plugin { - val dependencyGraphMLFile = SettingKey[File]("dependency-graph-ml-file", - "The location the graphml file should be generated at") - 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", - "The location the dot file should be generated at") - 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", - "The header of the dot file. (e.g. to set your preferred node shapes)") - val dependencyDot = TaskKey[File]("dependency-dot", - "Creates a dot file containing the dpendency-graph for a project") - val moduleGraph = TaskKey[IvyGraphMLDependencies.ModuleGraph]("module-graph", - "The dependency graph for a project") - 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", - "Prints the ascii graph to the console") - 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", - "Prints the ascii tree to the console") - 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", - "A task which returns the location of the ivy report file for a given configuration (default `compile`).") - val ignoreMissingUpdate = update in ivyReport - val filterScalaLibrary = SettingKey[Boolean]("filter-scala-library", - "Specifies if scala dependency should be filtered in dependency-* output" - ) +import IvyGraphMLDependencies.ModuleGraph - val licenseInfo = TaskKey[Unit]("dependency-license-info", - "Aggregates and shows information about the licenses of dependencies") - - // internal +object DependencyGraphSettings { + import DependencyGraphKeys._ import ModuleGraphProtocol._ - val moduleGraphStore = TaskKey[IvyGraphMLDependencies.ModuleGraph]("module-graph-store", "The stored module-graph from the last run") - val whatDependsOn = InputKey[Unit]("what-depends-on", "Shows information about what depends on the given module") - - def graphSettings = seq( + def graphSettings = Seq( ivyReportFunction <<= (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) => @@ -80,11 +48,11 @@ object Plugin extends sbt.Plugin { } }, updateConfiguration in ignoreMissingUpdate <<= updateConfiguration(config => new UpdateConfiguration(config.retrieve, true, config.logging)), - SbtDependencyGraphCompat.ignoreMissingUpdateT, + ignoreMissingUpdateT, filterScalaLibrary in Global := true ) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(ivyReportForConfig) - def ivyReportForConfig(config: Configuration) = inConfig(config)(seq( + def ivyReportForConfig(config: Configuration) = inConfig(config)(Seq( ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(ignoreMissingUpdate), moduleGraph <<= ivyReport map (absoluteReportPath.andThen(IvyGraphMLDependencies.graph)), moduleGraph <<= (scalaVersion, moduleGraph, filterScalaLibrary) map { (scalaV, graph, filter) => @@ -118,15 +86,15 @@ object Plugin extends sbt.Plugin { dependencyDotFile <<= target / "dependencies-%s.dot".format(config.toString), dependencyDot <<= dependencyDotTask, dependencyDotHeader := """digraph "dependency-graph" { - | graph[rankdir="LR"] - | node [ - | shape="record" - | ] - | edge [ - | arrowtail="none" - | ]""".stripMargin, + | graph[rankdir="LR"] + | node [ + | shape="record" + | ] + | edge [ + | arrowtail="none" + | ]""".stripMargin, dependencyDotNodeLabel := { (organisation: String, name: String, version: String) => - """<%s
%s
%s>""".format(organisation, name, version) + """<%s
%s
%s>""".format(organisation, name, version) }, whatDependsOn <<= InputTask(artifactIdParser) { module => (module, streams, moduleGraph) map { (module, streams, graph) => @@ -149,9 +117,9 @@ object Plugin extends sbt.Plugin { (moduleGraph, dependencyDotHeader, dependencyDotNodeLabel, dependencyDotFile, streams).map { (graph, dotHead, nodeLabel, outFile, streams) => - val resultFile = IvyGraphMLDependencies.saveAsDot(graph, dotHead, nodeLabel, outFile) - streams.log.info("Wrote dependency graph to '%s'" format resultFile) - resultFile + val resultFile = IvyGraphMLDependencies.saveAsDot(graph, dotHead, nodeLabel, outFile) + streams.log.info("Wrote dependency graph to '%s'" format resultFile) + resultFile } def absoluteReportPath = (file: File) => file.getAbsolutePath @@ -163,14 +131,14 @@ object Plugin extends sbt.Plugin { graph.nodes.filter(_.isUsed).groupBy(_.license).toSeq.sortBy(_._1).map { case (license, modules) => license.getOrElse("No license specified")+"\n"+ - modules.map(_.id.idString formatted "\t %s").mkString("\n") + modules.map(_.id.idString formatted "\t %s").mkString("\n") }.mkString("\n\n") streams.log.info(output) } import Project._ val shouldForceParser: State => Parser[Boolean] = { (state: State) => - import complete.DefaultParsers._ + import sbt.complete.DefaultParsers._ (Space ~> token("--force")).?.map(_.isDefined) } @@ -181,9 +149,7 @@ object Plugin extends sbt.Plugin { resolvedScoped { ctx => (state: State) => val graph = loadFromContext(moduleGraphStore, ctx, state) getOrElse ModuleGraph(Nil, Nil) - import complete.DefaultParsers._ - import SbtDependencyGraphCompat._ - + import sbt.complete.DefaultParsers._ def moduleFrom(modules: Seq[ModuleId]) = modules.map { m => (token(m.name) ~ Space ~ token(m.version)).map(_ => m) @@ -218,4 +184,34 @@ object Plugin extends sbt.Plugin { 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) + } } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Graph.scala b/src/main/scala/net/virtualvoid/sbt/graph/Graph.scala index c351fa71a..30799e129 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Graph.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Graph.scala @@ -5,8 +5,6 @@ */ package net.virtualvoid.sbt.graph -import sbt.SbtDependencyGraphCompat - object Graph { // [info] foo @@ -48,7 +46,7 @@ object Graph } def defaultColumnSize: Int = { - val termWidth = SbtDependencyGraphCompat.getTerminalWidth + val termWidth = sbt.SbtAccess.getTerminalWidth if (termWidth > 20) termWidth - 8 else 80 // ignore termWidth } diff --git a/src/main/scala/sbt/SbtAccess.scala b/src/main/scala/sbt/SbtAccess.scala new file mode 100644 index 000000000..eb9113300 --- /dev/null +++ b/src/main/scala/sbt/SbtAccess.scala @@ -0,0 +1,23 @@ +/* + * Copyright 2015 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 sbt + +object SbtAccess { + val unmanagedScalaInstanceOnly = Defaults.unmanagedScalaInstanceOnly + + def getTerminalWidth: Int = JLine.usingTerminal(_.getWidth) +} From 42ec040ccca521b71e6f9dc15a110f1d37e4518a Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 14 Nov 2015 17:11:35 +0100 Subject: [PATCH 147/252] bump version in scripted tests --- src/sbt-test/sbt-dependency-graph/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sbt-test/sbt-dependency-graph/plugins.sbt b/src/sbt-test/sbt-dependency-graph/plugins.sbt index 7325de692..fe656e183 100644 --- a/src/sbt-test/sbt-dependency-graph/plugins.sbt +++ b/src/sbt-test/sbt-dependency-graph/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.5-SNAPSHOT") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.0-SNAPSHOT") From 045aff16f5f825728bd2326b16a020e1c628f7e6 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 14 Nov 2015 17:12:54 +0100 Subject: [PATCH 148/252] rename Graph => AsciiTreeLayout --- .../virtualvoid/sbt/graph/IvyGraphMLDependencies.scala | 2 +- .../sbt/graph/{Graph.scala => util/AsciiTreeLayout.scala} | 5 ++--- .../{GraphSpecs.scala => util/AsciiTreeLayoutSpecs.scala} | 8 ++++---- 3 files changed, 7 insertions(+), 8 deletions(-) rename src/main/scala/net/virtualvoid/sbt/graph/{Graph.scala => util/AsciiTreeLayout.scala} (95%) rename src/test/scala/net/virtualvoid/sbt/graph/{GraphSpecs.scala => util/AsciiTreeLayoutSpecs.scala} (85%) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala index 3044b13c0..fd84b63f9 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala @@ -145,7 +145,7 @@ object IvyGraphMLDependencies extends App { // there should only be one root node (the project itself) val roots = graph.nodes.filter(n => !graph.edges.exists(_._2 == n.id)).sortBy(_.id.idString) roots.map { root => - Graph.toAscii[Module](root, node => deps.getOrElse(node.id, Seq.empty[Module]), displayModule) + util.AsciiTreeLayout.toAscii[Module](root, node => deps.getOrElse(node.id, Seq.empty[Module]), displayModule) }.mkString("\n") } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Graph.scala b/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala similarity index 95% rename from src/main/scala/net/virtualvoid/sbt/graph/Graph.scala rename to src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala index 30799e129..f9f0125f7 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Graph.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala @@ -3,10 +3,9 @@ * * Copied from sbt 0.12 source code */ -package net.virtualvoid.sbt.graph +package net.virtualvoid.sbt.graph.util -object Graph -{ +object AsciiTreeLayout { // [info] foo // [info] +-bar // [info] | +-baz diff --git a/src/test/scala/net/virtualvoid/sbt/graph/GraphSpecs.scala b/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala similarity index 85% rename from src/test/scala/net/virtualvoid/sbt/graph/GraphSpecs.scala rename to src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala index 208ff5227..4f0d8a836 100644 --- a/src/test/scala/net/virtualvoid/sbt/graph/GraphSpecs.scala +++ b/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala @@ -1,8 +1,8 @@ -package net.virtualvoid.sbt.graph +package net.virtualvoid.sbt.graph.util import org.specs2.mutable.Specification -class GraphSpecs extends Specification { +class AsciiTreeLayoutSpecs extends Specification { sealed trait Tree case class Branch(left: Tree, right: Tree) extends Tree case class Leaf(i: Int) extends Tree @@ -19,7 +19,7 @@ class GraphSpecs extends Specification { "Graph" should { "layout simple graphs" in { val simple = Branch(Branch(Leaf(1), Leaf(2)), Leaf(3)) - Graph.toAscii(simple, children, display, 20) === + AsciiTreeLayout.toAscii(simple, children, display, 20) === """Branch | +-Branch | | +-1 @@ -30,7 +30,7 @@ class GraphSpecs extends Specification { } "layout deep graphs" in { val simple = Branch(Branch(Branch(Branch(Branch(Branch(Leaf(1), Leaf(1)), Leaf(1)), Leaf(1)), Leaf(2)), Leaf(3)), Leaf(4)) - Graph.toAscii(simple, children, display, 10) === + AsciiTreeLayout.toAscii(simple, children, display, 10) === """Branch | +-Branch | | +-Br.. From 7a5126ef875ee24f364c7b0be591893fd5d80d4a Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 14 Nov 2015 17:14:47 +0100 Subject: [PATCH 149/252] big refactoring: split up the mess in IvyGraphMLDependencies into various subfiles --- .../sbt/graph/DependencyGraphKeys.scala | 4 +- .../sbt/graph/DependencyGraphSettings.scala | 22 +- .../sbt/graph/GraphTransformations.scala | 58 ++++ .../sbt/graph/IvyGraphMLDependencies.scala | 252 ------------------ .../net/virtualvoid/sbt/graph/Main.scala | 33 +++ .../sbt/graph/frontend/IvyReport.scala | 61 +++++ .../net/virtualvoid/sbt/graph/model.scala | 63 +++++ .../net/virtualvoid/sbt/graph/package.scala | 21 ++ .../sbt/graph/rendering/AsciiGraph.scala | 38 +++ .../sbt/graph/rendering/AsciiTree.scala | 39 +++ .../virtualvoid/sbt/graph/rendering/DOT.scala | 46 ++++ .../sbt/graph/rendering/GraphML.scala | 52 ++++ .../sbt/graph/util/ConsoleUtils.scala | 27 ++ src/main/scala/sbt/SbtAccess.scala | 1 + 14 files changed, 450 insertions(+), 267 deletions(-) create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/GraphTransformations.scala delete mode 100644 src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/Main.scala create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/frontend/IvyReport.scala create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/model.scala create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/package.scala create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/rendering/GraphML.scala create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/util/ConsoleUtils.scala diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index 1d8ef8a8a..a33f347f2 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -31,7 +31,7 @@ trait DependencyGraphKeys { "The header of the dot file. (e.g. to set your preferred node shapes)") val dependencyDot = TaskKey[File]("dependency-dot", "Creates a dot file containing the dpendency-graph for a project") - val moduleGraph = TaskKey[IvyGraphMLDependencies.ModuleGraph]("module-graph", + val moduleGraph = TaskKey[ModuleGraph]("module-graph", "The dependency graph for a project") val asciiGraph = TaskKey[String]("dependency-graph-string", "Returns a string containing the ascii representation of the dependency graph for a project") @@ -54,7 +54,7 @@ trait DependencyGraphKeys { "Aggregates and shows information about the licenses of dependencies") // internal - private[graph] val moduleGraphStore = TaskKey[IvyGraphMLDependencies.ModuleGraph]("module-graph-store", "The stored module-graph from the last run") + 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") } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index f943e2d96..9f8bffce5 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -26,8 +26,6 @@ import sbt.complete.Parser import org.apache.ivy.core.resolve.ResolveOptions -import IvyGraphMLDependencies.ModuleGraph - object DependencyGraphSettings { import DependencyGraphKeys._ import ModuleGraphProtocol._ @@ -54,23 +52,23 @@ object DependencyGraphSettings { def ivyReportForConfig(config: Configuration) = inConfig(config)(Seq( ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(ignoreMissingUpdate), - moduleGraph <<= ivyReport map (absoluteReportPath.andThen(IvyGraphMLDependencies.graph)), + moduleGraph <<= ivyReport map (absoluteReportPath.andThen(frontend.IvyReport.fromReportFile)), moduleGraph <<= (scalaVersion, moduleGraph, filterScalaLibrary) map { (scalaV, graph, filter) => if (filter) - IvyGraphMLDependencies.ignoreScalaLibrary(scalaV, graph) + GraphTransformations.ignoreScalaLibrary(scalaV, graph) else graph }, moduleGraphStore <<= moduleGraph storeAs moduleGraphStore triggeredBy moduleGraph, - asciiGraph <<= moduleGraph map IvyGraphMLDependencies.asciiGraph, + 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(IvyGraphMLDependencies.asciiGraph(graph)) + 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(IvyGraphMLDependencies.asciiTree(graph)) + streams.log.info(rendering.AsciiTree.asciiTree(graph)) if (!force) { streams.log.info("\n") @@ -79,7 +77,7 @@ object DependencyGraphSettings { } } }, - asciiTree <<= moduleGraph map IvyGraphMLDependencies.asciiTree, + asciiTree <<= moduleGraph map rendering.AsciiTree.asciiTree, dependencyTree <<= print(asciiTree), dependencyGraphMLFile <<= target / "dependencies-%s.graphml".format(config.toString), dependencyGraphML <<= dependencyGraphMLTask, @@ -98,7 +96,7 @@ object DependencyGraphSettings { }, whatDependsOn <<= InputTask(artifactIdParser) { module => (module, streams, moduleGraph) map { (module, streams, graph) => - streams.log.info(IvyGraphMLDependencies.asciiTree(IvyGraphMLDependencies.reverseGraphStartingAt(graph, module))) + streams.log.info(rendering.AsciiTree.asciiTree(GraphTransformations.reverseGraphStartingAt(graph, module))) } }, licenseInfo <<= (moduleGraph, streams) map showLicenseInfo @@ -109,7 +107,7 @@ object DependencyGraphSettings { def dependencyGraphMLTask = (moduleGraph, dependencyGraphMLFile, streams) map { (graph, resultFile, streams) => - IvyGraphMLDependencies.saveAsGraphML(graph, resultFile.getAbsolutePath) + rendering.GraphML.saveAsGraphML(graph, resultFile.getAbsolutePath) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } @@ -117,7 +115,7 @@ object DependencyGraphSettings { (moduleGraph, dependencyDotHeader, dependencyDotNodeLabel, dependencyDotFile, streams).map { (graph, dotHead, nodeLabel, outFile, streams) => - val resultFile = IvyGraphMLDependencies.saveAsDot(graph, dotHead, nodeLabel, outFile) + val resultFile = rendering.DOT.saveAsDot(graph, dotHead, nodeLabel, outFile) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } @@ -143,8 +141,6 @@ object DependencyGraphSettings { (Space ~> token("--force")).?.map(_.isDefined) } - import IvyGraphMLDependencies.ModuleId - val artifactIdParser: Initialize[State => Parser[ModuleId]] = resolvedScoped { ctx => (state: State) => val graph = loadFromContext(moduleGraphStore, ctx, state) getOrElse ModuleGraph(Nil, Nil) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/GraphTransformations.scala b/src/main/scala/net/virtualvoid/sbt/graph/GraphTransformations.scala new file mode 100644 index 000000000..dc4e976c2 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/GraphTransformations.scala @@ -0,0 +1,58 @@ +/* + * Copyright 2011, 2012 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 + +object GraphTransformations { + def reverseGraphStartingAt(graph: ModuleGraph, root: ModuleId): ModuleGraph = { + val deps = graph.reverseDependencyMap + + def visit(module: ModuleId, visited: Set[ModuleId]): Seq[(ModuleId, ModuleId)] = + if (visited(module)) + Nil + else + deps.get(module) match { + case Some(deps) => + deps.flatMap { to => + (module, to.id) +: visit(to.id, visited + module) + } + case None => Nil + } + + val edges = visit(root, Set.empty) + val nodes = edges.foldLeft(Set.empty[ModuleId])((set, edge) => set + edge._1 + edge._2).map(graph.module) + ModuleGraph(nodes.toSeq, edges) + } + + def ignoreScalaLibrary(scalaVersion: String, graph: ModuleGraph): ModuleGraph = { + def isScalaLibrary(m: Module) = isScalaLibraryId(m.id) + def isScalaLibraryId(id: ModuleId) = id.organisation == "org.scala-lang" && id.name == "scala-library" + + def dependsOnScalaLibrary(m: Module): Boolean = + graph.dependencyMap(m.id).exists(isScalaLibrary) + + def addScalaLibraryAnnotation(m: Module): Module = { + if (dependsOnScalaLibrary(m)) + m.copy(extraInfo = m.extraInfo + " [S]") + else + m + } + + val newNodes = graph.nodes.map(addScalaLibraryAnnotation).filterNot(isScalaLibrary) + val newEdges = graph.edges.filterNot(e => isScalaLibraryId(e._2)) + ModuleGraph(newNodes, newEdges) + } +} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala b/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala deleted file mode 100644 index fd84b63f9..000000000 --- a/src/main/scala/net/virtualvoid/sbt/graph/IvyGraphMLDependencies.scala +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright 2011, 2012 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 - -import xml.parsing.ConstructingParser -import java.io.File -import collection.mutable.HashMap -import collection.mutable.MultiMap -import collection.mutable.{Set => MSet} -import sbt.ConsoleLogger -import xml.{NodeSeq, Document, XML, Node} -import com.github.mdr.ascii.layout -import layout._ -import sbinary.{Format, DefaultProtocol} - -object IvyGraphMLDependencies extends App { - 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, - error: Option[String] = None) { - def hadError: Boolean = error.isDefined - def isUsed: Boolean = !evictedByVersion.isDefined - } - - type Edge = (ModuleId, ModuleId) - - case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) { - lazy val modules: Map[ModuleId, Module] = - nodes.map(n => (n.id, n)).toMap - - def module(id: ModuleId): Module = modules(id) - - lazy val dependencyMap: Map[ModuleId, Seq[Module]] = - createMap(identity) - - lazy val reverseDependencyMap: Map[ModuleId, Seq[Module]] = - createMap { case (a, b) => (b, a) } - - def createMap(bindingFor: ((ModuleId, ModuleId)) => (ModuleId, ModuleId)): Map[ModuleId, Seq[Module]] = { - val m = new HashMap[ModuleId, MSet[Module]] with MultiMap[ModuleId, Module] - edges.foreach { entry => - val (f, t) = bindingFor(entry) - m.addBinding(f, module(t)) - } - m.toMap.mapValues(_.toSeq.sortBy(_.id.idString)).withDefaultValue(Nil) - } - } - - def graph(ivyReportFile: String): ModuleGraph = - buildGraph(buildDoc(ivyReportFile)) - - def buildGraph(doc: Document): ModuleGraph = { - def edgesForModule(id: ModuleId, revision: NodeSeq): Seq[Edge] = - for { - caller <- revision \ "caller" - callerModule = moduleIdFromElement(caller, caller.attribute("callerrev").get.text) - } yield (moduleIdFromElement(caller, caller.attribute("callerrev").get.text), id) - - val moduleEdges: Seq[(Module, Seq[Edge])] = for { - mod <- doc \ "dependencies" \ "module" - revision <- mod \ "revision" - rev = revision.attribute("name").get.text - moduleId = moduleIdFromElement(mod, rev) - 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)) - } yield (module, edgesForModule(moduleId, revision)) - - val (nodes, edges) = moduleEdges.unzip - - val info = (doc \ "info").head - def infoAttr(name: String): String = - info.attribute(name).getOrElse(throw new IllegalArgumentException("Missing attribute "+name)).text - val rootModule = Module(ModuleId(infoAttr("organisation"), infoAttr("module"), infoAttr("revision"))) - - ModuleGraph(rootModule +: nodes, edges.flatten) - } - - def reverseGraphStartingAt(graph: ModuleGraph, root: ModuleId): ModuleGraph = { - val deps = graph.reverseDependencyMap - - def visit(module: ModuleId, visited: Set[ModuleId]): Seq[(ModuleId, ModuleId)] = - if (visited(module)) - Nil - else - deps.get(module) match { - case Some(deps) => - deps.flatMap { to => - (module, to.id) +: visit(to.id, visited + module) - } - case None => Nil - } - - val edges = visit(root, Set.empty) - val nodes = edges.foldLeft(Set.empty[ModuleId])((set, edge) => set + edge._1 + edge._2).map(graph.module) - ModuleGraph(nodes.toSeq, edges) - } - - def ignoreScalaLibrary(scalaVersion: String, graph: ModuleGraph): ModuleGraph = { - def isScalaLibrary(m: Module) = isScalaLibraryId(m.id) - def isScalaLibraryId(id: ModuleId) = id.organisation == "org.scala-lang" && id.name == "scala-library" - - def dependsOnScalaLibrary(m: Module): Boolean = - graph.dependencyMap(m.id).exists(isScalaLibrary) - - def addScalaLibraryAnnotation(m: Module): Module = { - if (dependsOnScalaLibrary(m)) - m.copy(extraInfo = m.extraInfo + " [S]") - else - m - } - - val newNodes = graph.nodes.map(addScalaLibraryAnnotation).filterNot(isScalaLibrary) - val newEdges = graph.edges.filterNot(e => isScalaLibraryId(e._2)) - ModuleGraph(newNodes, newEdges) - } - - def asciiGraph(graph: ModuleGraph): String = - Layouter.renderGraph(buildAsciiGraph(graph)) - - def asciiTree(graph: ModuleGraph): String = { - val deps = graph.dependencyMap - - // there should only be one root node (the project itself) - val roots = graph.nodes.filter(n => !graph.edges.exists(_._2 == n.id)).sortBy(_.id.idString) - roots.map { root => - util.AsciiTreeLayout.toAscii[Module](root, node => deps.getOrElse(node.id, Seq.empty[Module]), displayModule) - }.mkString("\n") - } - - def displayModule(module: Module): String = - red(module.id.idString + - module.extraInfo + - module.error.map(" (error: "+_+")").getOrElse("") + - module.evictedByVersion.map(_ formatted " (evicted by: %s)").getOrElse(""), module.hadError) - - private def buildAsciiGraph(moduleGraph: ModuleGraph): layout.Graph[String] = { - def renderVertex(module: Module): String = - module.id.name + module.extraInfo + "\n" + - module.id.organisation + "\n" + - module.id.version + - module.error.map("\nerror: "+_).getOrElse("") + - module.evictedByVersion.map(_ formatted "\nevicted by: %s").getOrElse("") - - val vertices = moduleGraph.nodes.map(renderVertex).toList - val edges = moduleGraph.edges.toList.map { case (from, to) ⇒ (renderVertex(moduleGraph.module(from)), renderVertex(moduleGraph.module(to))) } - layout.Graph(vertices, edges) - } - - def saveAsGraphML(graph: ModuleGraph, outputFile: String) { - val nodesXml = - for (n <- graph.nodes) - yield - - - {n.id.idString} - - - - val edgesXml = - for (e <- graph.edges) - yield - - val xml = - - - - {nodesXml} - {edgesXml} - - - - XML.save(outputFile, xml) - } - def saveAsDot(graph: ModuleGraph, - dotHead: String, - nodeFormation: (String, String, String) => String, - outputFile: File): File = { - val nodes = { - for (n <- graph.nodes) - yield - """ "%s"[label=%s]""".format(n.id.idString, - nodeFormation(n.id.organisation, n.id.name, n.id.version)) - }.mkString("\n") - - val edges = { - for ( e <- graph.edges) - yield - """ "%s" -> "%s"""".format(e._1.idString, e._2.idString) - }.mkString("\n") - - val dot = "%s\n%s\n%s\n}".format(dotHead, nodes, edges) - - sbt.IO.write(outputFile, dot) - outputFile - } - - def moduleIdFromElement(element: Node, version: String): ModuleId = - ModuleId(element.attribute("organisation").get.text, element.attribute("name").get.text, version) - - private def buildDoc(ivyReportFile: String) = ConstructingParser.fromSource(io.Source.fromFile(ivyReportFile), false).document - - def red(str: String, doRed: Boolean): String = - if (ConsoleLogger.formatEnabled && doRed) - Console.RED + str + Console.RESET - else - str - - def die(msg: String): Nothing = { - println(msg) - sys.exit(1) - } - def usage: String = - "Usage: " - - val reportFile = args.lift(0).filter(f => new File(f).exists).getOrElse(die(usage)) - val outputFile = args.lift(1).getOrElse(die(usage)) - saveAsGraphML(graph(reportFile), outputFile) -} - -object ModuleGraphProtocol extends DefaultProtocol { - import IvyGraphMLDependencies._ - - 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] = asProduct5(Module)(Module.unapply(_).get) - implicit val ModuleGraphFormat: Format[ModuleGraph] = asProduct2(ModuleGraph)(ModuleGraph.unapply(_).get) -} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Main.scala b/src/main/scala/net/virtualvoid/sbt/graph/Main.scala new file mode 100644 index 000000000..497258260 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/Main.scala @@ -0,0 +1,33 @@ +/* + * Copyright 2015 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 + +import java.io.File + +object Main extends App { + def die(msg: String): Nothing = { + println(msg) + sys.exit(1) + } + def usage: String = + "Usage: " + + val reportFile = args.lift(0).filter(f => new File(f).exists).getOrElse(die(usage)) + val outputFile = args.lift(1).getOrElse(die(usage)) + val graph = frontend.IvyReport.fromReportFile(reportFile) + rendering.GraphML.saveAsGraphML(graph, outputFile) +} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/frontend/IvyReport.scala b/src/main/scala/net/virtualvoid/sbt/graph/frontend/IvyReport.scala new file mode 100644 index 000000000..94c9b61e9 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/frontend/IvyReport.scala @@ -0,0 +1,61 @@ +/* + * Copyright 2015 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.frontend + +import net.virtualvoid.sbt.graph._ + +import scala.xml.{NodeSeq, Document, Node} +import scala.xml.parsing.ConstructingParser + +object IvyReport { + def fromReportFile(ivyReportFile: String): ModuleGraph = + fromReportXML(loadXML(ivyReportFile)) + + def fromReportXML(doc: Document): ModuleGraph = { + def edgesForModule(id: ModuleId, revision: NodeSeq): Seq[Edge] = + for { + caller <- revision \ "caller" + callerModule = moduleIdFromElement(caller, caller.attribute("callerrev").get.text) + } yield (moduleIdFromElement(caller, caller.attribute("callerrev").get.text), id) + + val moduleEdges: Seq[(Module, Seq[Edge])] = for { + mod <- doc \ "dependencies" \ "module" + revision <- mod \ "revision" + rev = revision.attribute("name").get.text + moduleId = moduleIdFromElement(mod, rev) + 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)) + } yield (module, edgesForModule(moduleId, revision)) + + val (nodes, edges) = moduleEdges.unzip + + val info = (doc \ "info").head + def infoAttr(name: String): String = + info.attribute(name).getOrElse(throw new IllegalArgumentException("Missing attribute "+name)).text + val rootModule = Module(ModuleId(infoAttr("organisation"), infoAttr("module"), infoAttr("revision"))) + + ModuleGraph(rootModule +: nodes, edges.flatten) + } + + private def moduleIdFromElement(element: Node, version: String): ModuleId = + ModuleId(element.attribute("organisation").get.text, element.attribute("name").get.text, version) + + private def loadXML(ivyReportFile: String) = + ConstructingParser.fromSource(io.Source.fromFile(ivyReportFile), preserveWS = false).document() +} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/model.scala b/src/main/scala/net/virtualvoid/sbt/graph/model.scala new file mode 100644 index 000000000..9af79d129 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/model.scala @@ -0,0 +1,63 @@ +/* + * Copyright 2015 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 + +import scala.collection.mutable.{MultiMap, HashMap, 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, + error: Option[String] = None) { + def hadError: Boolean = error.isDefined + def isUsed: Boolean = !evictedByVersion.isDefined +} + +case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) { + lazy val modules: Map[ModuleId, Module] = + nodes.map(n => (n.id, n)).toMap + + def module(id: ModuleId): Module = modules(id) + + lazy val dependencyMap: Map[ModuleId, Seq[Module]] = + createMap(identity) + + lazy val reverseDependencyMap: Map[ModuleId, Seq[Module]] = + createMap { case (a, b) => (b, a) } + + def createMap(bindingFor: ((ModuleId, ModuleId)) => (ModuleId, ModuleId)): Map[ModuleId, Seq[Module]] = { + val m = new HashMap[ModuleId, Set[Module]] with MultiMap[ModuleId, Module] + edges.foreach { entry => + val (f, t) = bindingFor(entry) + m.addBinding(f, module(t)) + } + m.toMap.mapValues(_.toSeq.sortBy(_.id.idString)).withDefaultValue(Nil) + } +} + +import sbinary.{Format, DefaultProtocol} +object ModuleGraphProtocol extends 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] = asProduct5(Module)(Module.unapply(_).get) + implicit val ModuleGraphFormat: Format[ModuleGraph] = asProduct2(ModuleGraph.apply _)(ModuleGraph.unapply(_).get) +} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/package.scala b/src/main/scala/net/virtualvoid/sbt/graph/package.scala new file mode 100644 index 000000000..1fe4e5fc1 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/package.scala @@ -0,0 +1,21 @@ +/* + * Copyright 2015 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 + +package object graph { + type Edge = (ModuleId, ModuleId) +} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala new file mode 100644 index 000000000..f4b21ea95 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala @@ -0,0 +1,38 @@ +/* + * Copyright 2015 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 + +import com.github.mdr.ascii.layout._ + +object AsciiGraph { + def asciiGraph(graph: ModuleGraph): String = + Layouter.renderGraph(buildAsciiGraph(graph)) + + private def buildAsciiGraph(moduleGraph: ModuleGraph): Graph[String] = { + def renderVertex(module: Module): String = + module.id.name + module.extraInfo + "\n" + + module.id.organisation + "\n" + + module.id.version + + module.error.map("\nerror: "+_).getOrElse("") + + module.evictedByVersion.map(_ formatted "\nevicted by: %s").getOrElse("") + + val vertices = moduleGraph.nodes.map(renderVertex).toList + val edges = moduleGraph.edges.toList.map { case (from, to) ⇒ (renderVertex(moduleGraph.module(from)), renderVertex(moduleGraph.module(to))) } + Graph(vertices, edges) + } +} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala new file mode 100644 index 000000000..d406a310e --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala @@ -0,0 +1,39 @@ +/* + * Copyright 2015 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 + +import util.AsciiTreeLayout +import util.ConsoleUtils._ + +object AsciiTree { + def asciiTree(graph: ModuleGraph): String = { + val deps = graph.dependencyMap + + // there should only be one root node (the project itself) + val roots = graph.nodes.filter(n => !graph.edges.exists(_._2 == n.id)).sortBy(_.id.idString) + roots.map { root => + AsciiTreeLayout.toAscii[Module](root, node => deps.getOrElse(node.id, Seq.empty[Module]), displayModule) + }.mkString("\n") + } + + def displayModule(module: Module): String = + red(module.id.idString + + module.extraInfo + + module.error.map(" (error: "+_+")").getOrElse("") + + module.evictedByVersion.map(_ formatted " (evicted by: %s)").getOrElse(""), module.hadError) +} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala new file mode 100644 index 000000000..e7cb2c3f5 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala @@ -0,0 +1,46 @@ +/* + * Copyright 2015 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.rendering + +import java.io.File + +import net.virtualvoid.sbt.graph.ModuleGraph + +object DOT { + def saveAsDot(graph: ModuleGraph, + dotHead: String, + nodeFormation: (String, String, String) => String, + outputFile: File): File = { + val nodes = { + for (n <- graph.nodes) + yield + """ "%s"[label=%s]""".format(n.id.idString, + nodeFormation(n.id.organisation, n.id.name, n.id.version)) + }.mkString("\n") + + val edges = { + for ( e <- graph.edges) + yield + """ "%s" -> "%s"""".format(e._1.idString, e._2.idString) + }.mkString("\n") + + val dot = "%s\n%s\n%s\n}".format(dotHead, nodes, edges) + + sbt.IO.write(outputFile, dot) + outputFile + } +} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/GraphML.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/GraphML.scala new file mode 100644 index 000000000..48bf1ce6b --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/GraphML.scala @@ -0,0 +1,52 @@ +/* + * Copyright 2015 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.rendering + +import net.virtualvoid.sbt.graph.ModuleGraph + +import scala.xml.XML + +object GraphML { + def saveAsGraphML(graph: ModuleGraph, outputFile: String) { + val nodesXml = + for (n <- graph.nodes) + yield + + + {n.id.idString} + + + + val edgesXml = + for (e <- graph.edges) + yield + + val xml = + + + + {nodesXml} + {edgesXml} + + + + XML.save(outputFile, xml) + } +} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/util/ConsoleUtils.scala b/src/main/scala/net/virtualvoid/sbt/graph/util/ConsoleUtils.scala new file mode 100644 index 000000000..ceba7da65 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/util/ConsoleUtils.scala @@ -0,0 +1,27 @@ +/* + * Copyright 2015 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.util + +import sbt.ConsoleLogger + +object ConsoleUtils { + def red(str: String, doRed: Boolean): String = + if (ConsoleLogger.formatEnabled && doRed) + Console.RED + str + Console.RESET + else + str +} diff --git a/src/main/scala/sbt/SbtAccess.scala b/src/main/scala/sbt/SbtAccess.scala index eb9113300..a75a57c31 100644 --- a/src/main/scala/sbt/SbtAccess.scala +++ b/src/main/scala/sbt/SbtAccess.scala @@ -16,6 +16,7 @@ package sbt +/** Accessors to private[sbt] symbols. */ object SbtAccess { val unmanagedScalaInstanceOnly = Defaults.unmanagedScalaInstanceOnly From 5f3c2c2659c58bdcb4a5bd70ff8329db1b22a9a6 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 17 Nov 2015 17:27:34 +0100 Subject: [PATCH 150/252] more AsciiTreeLayout tests --- .../sbt/graph/util/AsciiTreeLayoutSpecs.scala | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala b/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala index 4f0d8a836..ba1d7d00b 100644 --- a/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala +++ b/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala @@ -28,6 +28,19 @@ class AsciiTreeLayoutSpecs extends Specification { | +-333 | """.stripMargin } + "add separator lines where applicable" in { + val simple = Branch(Branch(Leaf(1), Branch(Leaf(2), Leaf(3))), Leaf(4)) + AsciiTreeLayout.toAscii(simple, children, display, 20) === + """Branch + | +-Branch + | | +-1 + | | +-Branch + | | +-22 + | | +-333 + | |\u0020\u0020\u0020 + | +-4444 + | """.stripMargin + } "layout deep graphs" in { val simple = Branch(Branch(Branch(Branch(Branch(Branch(Leaf(1), Leaf(1)), Leaf(1)), Leaf(1)), Leaf(2)), Leaf(3)), Leaf(4)) AsciiTreeLayout.toAscii(simple, children, display, 10) === @@ -51,5 +64,28 @@ class AsciiTreeLayoutSpecs extends Specification { | +-4444 | """.stripMargin } + "cut off cycles" in { + AsciiTreeLayout.toAscii[Int](1, Map( + 1 -> Seq(2,3,4), + 2 -> Seq(4,5), + 3 -> Seq(), + 4 -> Seq(3), + 5 -> Seq(1,4,6,7), + 6 -> Seq(), + 7 -> Seq()), _.toString).trim === + """1 + | +-2 + | | +-4 + | | | +-3 + | | | + | | +-5 + | | #-1 + | | #-4 + | | +-6 + | | +-7 + | | + | #-3 + | #-4""".stripMargin.trim + } } } From 0c3cf98a89808ee4d3c7dae93750fab111726cd6 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 17 Nov 2015 17:29:58 +0100 Subject: [PATCH 151/252] allow cycles in graphs even when printing with AsciiTreeLayout, fixes #77 --- .../sbt/graph/util/AsciiTreeLayout.scala | 31 ++++++++++++------- .../sbt/graph/util/AsciiTreeLayoutSpecs.scala | 13 +++++--- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala b/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala index f9f0125f7..c7f8e6395 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala @@ -28,20 +28,27 @@ object AsciiTreeLayout { }) + s.slice(at + 1, s.length) else s - def toAsciiLines(node: A, level: Int): Vector[String] = { - val line = limitLine((twoSpaces * level) + (if (level == 0) "" else "+-") + display(node)) - val cs = Vector(children(node): _*) - val childLines = cs map {toAsciiLines(_, level + 1)} - val withBar = childLines.zipWithIndex flatMap { - case (lines, pos) if pos < (cs.size - 1) => lines map {insertBar(_, 2 * (level + 1))} - case (lines, pos) => - if (lines.last.trim != "") lines ++ Vector(twoSpaces * (level + 1)) - else lines + def toAsciiLines(node: A, level: Int, parents: Set[A]): Vector[String] = + if (parents contains node) // cycle + Vector(limitLine((twoSpaces * level) + "#-" + display(node))) + else { + val line = limitLine((twoSpaces * level) + (if (level == 0) "" else "+-") + display(node)) + val cs = Vector(children(node): _*) + val childLines = cs map { + toAsciiLines(_, level + 1, parents + node) + } + val withBar = childLines.zipWithIndex flatMap { + case (lines, pos) if pos < (cs.size - 1) => lines map { + insertBar(_, 2 * (level + 1)) + } + case (lines, pos) => + if (lines.last.trim != "") lines ++ Vector(twoSpaces * (level + 1)) + else lines + } + line +: withBar } - line +: withBar - } - toAsciiLines(top, 0).mkString("\n") + toAsciiLines(top, 0, Set.empty).mkString("\n") } def defaultColumnSize: Int = { diff --git a/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala b/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala index ba1d7d00b..cd110c7e4 100644 --- a/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala +++ b/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala @@ -77,15 +77,18 @@ class AsciiTreeLayoutSpecs extends Specification { | +-2 | | +-4 | | | +-3 - | | | + | | |\u0020 | | +-5 | | #-1 - | | #-4 + | | +-4 + | | | +-3 + | | |\u0020 | | +-6 | | +-7 - | | - | #-3 - | #-4""".stripMargin.trim + | |\u0020\u0020\u0020 + | +-3 + | +-4 + | +-3""".stripMargin.trim } } } From 0c4bc73a64de7dcb6530bb7f32d94084bc0badc9 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 17 Nov 2015 17:32:02 +0100 Subject: [PATCH 152/252] enable Scalariform auto-formatting --- build.sbt | 2 + .../sbt/graph/DependencyGraphKeys.scala | 7 +- .../sbt/graph/DependencyGraphSettings.scala | 108 +++++++++--------- .../sbt/graph/GraphTransformations.scala | 10 +- .../net/virtualvoid/sbt/graph/Main.scala | 2 +- .../sbt/graph/frontend/IvyReport.scala | 16 +-- .../net/virtualvoid/sbt/graph/model.scala | 14 +-- .../sbt/graph/rendering/AsciiGraph.scala | 2 +- .../sbt/graph/rendering/AsciiTree.scala | 8 +- .../virtualvoid/sbt/graph/rendering/DOT.scala | 14 +-- .../sbt/graph/rendering/GraphML.scala | 26 ++--- .../sbt/graph/util/AsciiTreeLayout.scala | 78 ++++++------- .../sbt/graph/util/AsciiTreeLayoutSpecs.scala | 46 ++++---- 13 files changed, 164 insertions(+), 169 deletions(-) diff --git a/build.sbt b/build.sbt index 201ba01c7..4cec1065f 100644 --- a/build.sbt +++ b/build.sbt @@ -24,3 +24,5 @@ sbt.CrossBuilding.latestCompatibleVersionMapper ~= { case x => original(x) } } + +ScalariformSupport.formatSettings \ No newline at end of file diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index a33f347f2..a5e8cf944 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -25,7 +25,7 @@ trait DependencyGraphKeys { "Creates a graphml file containing the dependency-graph for a project") 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", "The header of the dot file. (e.g. to set your preferred node shapes)") @@ -41,14 +41,13 @@ trait DependencyGraphKeys { "Returns a string containing an ascii tree representation of the dependency graph for a project") val dependencyTree = TaskKey[Unit]("dependency-tree", "Prints the ascii tree 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", "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", - "Specifies if scala dependency should be filtered in dependency-* output" - ) + "Specifies if scala dependency should be filtered in dependency-* output") val licenseInfo = TaskKey[Unit]("dependency-license-info", "Aggregates and shows information about the licenses of dependencies") diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index 9f8bffce5..ea8c9f681 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -31,29 +31,28 @@ object DependencyGraphSettings { import ModuleGraphProtocol._ def graphSettings = Seq( - ivyReportFunction <<= (sbtVersion, target, projectID, ivyModule, appConfiguration, streams) map { (sbtV, target, projectID, ivyModule, config, streams) => + ivyReportFunction <<= (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, _) => + 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)) + (c: String) ⇒ file("%s/resolution-cache/reports/%s/%s-resolved.xml" format (target, id, c)) } - case _ => + case _ ⇒ val home = config.provider.scalaProvider.launcher.ivyHome - (c: String) => file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c)) + (c: String) ⇒ file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c)) } }, - updateConfiguration in ignoreMissingUpdate <<= updateConfiguration(config => new UpdateConfiguration(config.retrieve, true, config.logging)), + updateConfiguration in ignoreMissingUpdate <<= updateConfiguration(config ⇒ new UpdateConfiguration(config.retrieve, true, config.logging)), ignoreMissingUpdateT, - filterScalaLibrary in Global := true - ) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(ivyReportForConfig) + filterScalaLibrary in Global := true) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(ivyReportForConfig) def ivyReportForConfig(config: Configuration) = inConfig(config)(Seq( - ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn(ignoreMissingUpdate), + ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn (ignoreMissingUpdate), moduleGraph <<= ivyReport map (absoluteReportPath.andThen(frontend.IvyReport.fromReportFile)), - moduleGraph <<= (scalaVersion, moduleGraph, filterScalaLibrary) map { (scalaV, graph, filter) => + moduleGraph <<= (scalaVersion, moduleGraph, filterScalaLibrary) map { (scalaV, graph, filter) ⇒ if (filter) GraphTransformations.ignoreScalaLibrary(scalaV, graph) else @@ -61,8 +60,8 @@ object DependencyGraphSettings { }, moduleGraphStore <<= moduleGraph storeAs moduleGraphStore triggeredBy moduleGraph, asciiGraph <<= moduleGraph map rendering.AsciiGraph.asciiGraph, - dependencyGraph <<= InputTask(shouldForceParser) { force => - (force, moduleGraph, streams) map { (force, graph, streams) => + 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") @@ -91,35 +90,34 @@ object DependencyGraphSettings { | edge [ | arrowtail="none" | ]""".stripMargin, - dependencyDotNodeLabel := { (organisation: String, name: String, version: String) => + dependencyDotNodeLabel := { (organisation: String, name: String, version: String) ⇒ """<%s
%s
%s>""".format(organisation, name, version) }, - whatDependsOn <<= InputTask(artifactIdParser) { module => - (module, streams, moduleGraph) map { (module, streams, graph) => + whatDependsOn <<= InputTask(artifactIdParser) { module ⇒ + (module, streams, moduleGraph) map { (module, streams, graph) ⇒ streams.log.info(rendering.AsciiTree.asciiTree(GraphTransformations.reverseGraphStartingAt(graph, module))) } }, - licenseInfo <<= (moduleGraph, streams) map showLicenseInfo - )) + licenseInfo <<= (moduleGraph, streams) map showLicenseInfo)) def printAsciiGraphTask = (streams, asciiGraph) map (_.log.info(_)) def dependencyGraphMLTask = - (moduleGraph, dependencyGraphMLFile, streams) map { (graph, resultFile, streams) => + (moduleGraph, dependencyGraphMLFile, streams) map { (graph, resultFile, streams) ⇒ rendering.GraphML.saveAsGraphML(graph, resultFile.getAbsolutePath) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } def dependencyDotTask = (moduleGraph, dependencyDotHeader, dependencyDotNodeLabel, dependencyDotFile, streams).map { - (graph, dotHead, nodeLabel, outFile, streams) => + (graph, dotHead, nodeLabel, outFile, streams) ⇒ val resultFile = rendering.DOT.saveAsDot(graph, dotHead, nodeLabel, outFile) streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } - def absoluteReportPath = (file: File) => file.getAbsolutePath + def absoluteReportPath = (file: File) ⇒ file.getAbsolutePath def print(key: TaskKey[String]) = (streams, key) map (_.log.info(_)) @@ -127,38 +125,40 @@ object DependencyGraphSettings { def showLicenseInfo(graph: ModuleGraph, streams: TaskStreams) { val output = graph.nodes.filter(_.isUsed).groupBy(_.license).toSeq.sortBy(_._1).map { - case (license, modules) => - license.getOrElse("No license specified")+"\n"+ + case (license, modules) ⇒ + license.getOrElse("No license specified") + "\n" + modules.map(_.id.idString formatted "\t %s").mkString("\n") }.mkString("\n\n") streams.log.info(output) } import Project._ - val shouldForceParser: State => Parser[Boolean] = { (state: State) => + val shouldForceParser: State ⇒ Parser[Boolean] = { (state: State) ⇒ import sbt.complete.DefaultParsers._ (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) + val artifactIdParser: Initialize[State ⇒ Parser[ModuleId]] = + resolvedScoped { ctx ⇒ + (state: State) ⇒ + val graph = loadFromContext(moduleGraphStore, ctx, state) getOrElse ModuleGraph(Nil, Nil) - import sbt.complete.DefaultParsers._ - def moduleFrom(modules: Seq[ModuleId]) = - modules.map { m => - (token(m.name) ~ Space ~ token(m.version)).map(_ => m) - }.reduce(_ | _) + import sbt.complete.DefaultParsers._ + def moduleFrom(modules: Seq[ModuleId]) = + modules.map { m ⇒ + (token(m.name) ~ Space ~ token(m.version)).map(_ ⇒ m) + }.reduce(_ | _) - graph.nodes.map(_.id).groupBy(_.organisation).map { - case (org, modules) => - Space ~ token(org) ~ Space ~> moduleFrom(modules) - }.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(_.organisation).map { + case (org, modules) ⇒ + Space ~ token(org) ~ Space ~> moduleFrom(modules) + }.reduceOption(_ | _).getOrElse { + (Space ~> token(StringBasic, "organization") ~ Space ~ token(StringBasic, "module") ~ Space ~ token(StringBasic, "version")).map { + case ((((org, _), mod), _), version) ⇒ + ModuleId(org, mod, version) + } } - } } // This is to support 0.13.8's InlineConfigurationWithExcludes while not forcing 0.13.8 @@ -167,17 +167,17 @@ object DependencyGraphSettings { } def crossName(ivyModule: IvySbt#Module) = ivyModule.moduleSettings match { - case ic: InlineConfiguration => ic.module.name - case hm: HasModule if hm.getClass.getName == "sbt.InlineConfigurationWithExcludes" => hm.module.name - case _ => + case ic: InlineConfiguration ⇒ ic.module.name + case hm: HasModule if hm.getClass.getName == "sbt.InlineConfigurationWithExcludes" ⇒ hm.module.name + case _ ⇒ throw new IllegalStateException("sbt-dependency-graph plugin currently only supports InlineConfiguration of ivy settings (the default in sbt)") } val VersionPattern = """(\d+)\.(\d+)\.(\d+)(?:-(.*))?""".r object Version { def unapply(str: String): Option[(Int, Int, Int, Option[String])] = str match { - case VersionPattern(major, minor, fix, appendix) => Some((major.toInt, minor.toInt, fix.toInt, Option(appendix))) - case _ => None + case VersionPattern(major, minor, fix, appendix) ⇒ Some((major.toInt, minor.toInt, fix.toInt, Option(appendix))) + case _ ⇒ None } } @@ -195,17 +195,17 @@ object DependencyGraphSettings { // 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) => + 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 + 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 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 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) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/GraphTransformations.scala b/src/main/scala/net/virtualvoid/sbt/graph/GraphTransformations.scala index dc4e976c2..c5c4e8a21 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/GraphTransformations.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/GraphTransformations.scala @@ -25,15 +25,15 @@ object GraphTransformations { Nil else deps.get(module) match { - case Some(deps) => - deps.flatMap { to => + case Some(deps) ⇒ + deps.flatMap { to ⇒ (module, to.id) +: visit(to.id, visited + module) } - case None => Nil + case None ⇒ Nil } val edges = visit(root, Set.empty) - val nodes = edges.foldLeft(Set.empty[ModuleId])((set, edge) => set + edge._1 + edge._2).map(graph.module) + val nodes = edges.foldLeft(Set.empty[ModuleId])((set, edge) ⇒ set + edge._1 + edge._2).map(graph.module) ModuleGraph(nodes.toSeq, edges) } @@ -52,7 +52,7 @@ object GraphTransformations { } val newNodes = graph.nodes.map(addScalaLibraryAnnotation).filterNot(isScalaLibrary) - val newEdges = graph.edges.filterNot(e => isScalaLibraryId(e._2)) + val newEdges = graph.edges.filterNot(e ⇒ isScalaLibraryId(e._2)) ModuleGraph(newNodes, newEdges) } } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Main.scala b/src/main/scala/net/virtualvoid/sbt/graph/Main.scala index 497258260..5d031abc9 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Main.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Main.scala @@ -26,7 +26,7 @@ object Main extends App { def usage: String = "Usage: " - val reportFile = args.lift(0).filter(f => new File(f).exists).getOrElse(die(usage)) + val reportFile = args.lift(0).filter(f ⇒ new File(f).exists).getOrElse(die(usage)) val outputFile = args.lift(1).getOrElse(die(usage)) val graph = frontend.IvyReport.fromReportFile(reportFile) rendering.GraphML.saveAsGraphML(graph, outputFile) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/frontend/IvyReport.scala b/src/main/scala/net/virtualvoid/sbt/graph/frontend/IvyReport.scala index 94c9b61e9..164b154ea 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/frontend/IvyReport.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/frontend/IvyReport.scala @@ -18,7 +18,7 @@ package net.virtualvoid.sbt.graph.frontend import net.virtualvoid.sbt.graph._ -import scala.xml.{NodeSeq, Document, Node} +import scala.xml.{ NodeSeq, Document, Node } import scala.xml.parsing.ConstructingParser object IvyReport { @@ -28,16 +28,16 @@ object IvyReport { def fromReportXML(doc: Document): ModuleGraph = { def edgesForModule(id: ModuleId, revision: NodeSeq): Seq[Edge] = for { - caller <- revision \ "caller" + caller ← revision \ "caller" callerModule = moduleIdFromElement(caller, caller.attribute("callerrev").get.text) } yield (moduleIdFromElement(caller, caller.attribute("callerrev").get.text), id) val moduleEdges: Seq[(Module, Seq[Edge])] = for { - mod <- doc \ "dependencies" \ "module" - revision <- mod \ "revision" - rev = revision.attribute("name").get.text - moduleId = moduleIdFromElement(mod, rev) - module = Module(moduleId, + mod ← doc \ "dependencies" \ "module" + revision ← mod \ "revision" + rev = revision.attribute("name").get.text + moduleId = moduleIdFromElement(mod, rev) + 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)) @@ -47,7 +47,7 @@ object IvyReport { val info = (doc \ "info").head def infoAttr(name: String): String = - info.attribute(name).getOrElse(throw new IllegalArgumentException("Missing attribute "+name)).text + info.attribute(name).getOrElse(throw new IllegalArgumentException("Missing attribute " + name)).text val rootModule = Module(ModuleId(infoAttr("organisation"), infoAttr("module"), infoAttr("revision"))) ModuleGraph(rootModule +: nodes, edges.flatten) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/model.scala b/src/main/scala/net/virtualvoid/sbt/graph/model.scala index 9af79d129..f4b51cfcb 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/model.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/model.scala @@ -16,12 +16,12 @@ package net.virtualvoid.sbt.graph -import scala.collection.mutable.{MultiMap, HashMap, Set} +import scala.collection.mutable.{ MultiMap, HashMap, Set } case class ModuleId(organisation: String, name: String, version: String) { - def idString: String = organisation+":"+name+":"+version + def idString: String = organisation + ":" + name + ":" + version } case class Module(id: ModuleId, license: Option[String] = None, @@ -34,7 +34,7 @@ case class Module(id: ModuleId, case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) { lazy val modules: Map[ModuleId, Module] = - nodes.map(n => (n.id, n)).toMap + nodes.map(n ⇒ (n.id, n)).toMap def module(id: ModuleId): Module = modules(id) @@ -42,11 +42,11 @@ case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) { createMap(identity) lazy val reverseDependencyMap: Map[ModuleId, Seq[Module]] = - createMap { case (a, b) => (b, a) } + createMap { case (a, b) ⇒ (b, a) } - def createMap(bindingFor: ((ModuleId, ModuleId)) => (ModuleId, ModuleId)): Map[ModuleId, Seq[Module]] = { + def createMap(bindingFor: ((ModuleId, ModuleId)) ⇒ (ModuleId, ModuleId)): Map[ModuleId, Seq[Module]] = { val m = new HashMap[ModuleId, Set[Module]] with MultiMap[ModuleId, Module] - edges.foreach { entry => + edges.foreach { entry ⇒ val (f, t) = bindingFor(entry) m.addBinding(f, module(t)) } @@ -54,7 +54,7 @@ case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) { } } -import sbinary.{Format, DefaultProtocol} +import sbinary.{ Format, DefaultProtocol } object ModuleGraphProtocol extends 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) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala index f4b21ea95..8da025149 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala @@ -28,7 +28,7 @@ object AsciiGraph { module.id.name + module.extraInfo + "\n" + module.id.organisation + "\n" + module.id.version + - module.error.map("\nerror: "+_).getOrElse("") + + module.error.map("\nerror: " + _).getOrElse("") + module.evictedByVersion.map(_ formatted "\nevicted by: %s").getOrElse("") val vertices = moduleGraph.nodes.map(renderVertex).toList diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala index d406a310e..0843affbf 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala @@ -25,15 +25,15 @@ object AsciiTree { val deps = graph.dependencyMap // there should only be one root node (the project itself) - val roots = graph.nodes.filter(n => !graph.edges.exists(_._2 == n.id)).sortBy(_.id.idString) - roots.map { root => - AsciiTreeLayout.toAscii[Module](root, node => deps.getOrElse(node.id, Seq.empty[Module]), displayModule) + val roots = graph.nodes.filter(n ⇒ !graph.edges.exists(_._2 == n.id)).sortBy(_.id.idString) + roots.map { root ⇒ + AsciiTreeLayout.toAscii[Module](root, node ⇒ deps.getOrElse(node.id, Seq.empty[Module]), displayModule) }.mkString("\n") } def displayModule(module: Module): String = red(module.id.idString + module.extraInfo + - module.error.map(" (error: "+_+")").getOrElse("") + + module.error.map(" (error: " + _ + ")").getOrElse("") + module.evictedByVersion.map(_ formatted " (evicted by: %s)").getOrElse(""), module.hadError) } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala index e7cb2c3f5..3eb168e5b 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala @@ -23,19 +23,17 @@ import net.virtualvoid.sbt.graph.ModuleGraph object DOT { def saveAsDot(graph: ModuleGraph, dotHead: String, - nodeFormation: (String, String, String) => String, + nodeFormation: (String, String, String) ⇒ String, outputFile: File): File = { val nodes = { - for (n <- graph.nodes) - yield - """ "%s"[label=%s]""".format(n.id.idString, - nodeFormation(n.id.organisation, n.id.name, n.id.version)) + for (n ← graph.nodes) + yield """ "%s"[label=%s]""".format(n.id.idString, + nodeFormation(n.id.organisation, n.id.name, n.id.version)) }.mkString("\n") val edges = { - for ( e <- graph.edges) - yield - """ "%s" -> "%s"""".format(e._1.idString, e._2.idString) + for (e ← graph.edges) + yield """ "%s" -> "%s"""".format(e._1.idString, e._2.idString) }.mkString("\n") val dot = "%s\n%s\n%s\n}".format(dotHead, nodes, edges) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/GraphML.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/GraphML.scala index 48bf1ce6b..436a90c2e 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/rendering/GraphML.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/GraphML.scala @@ -23,27 +23,23 @@ import scala.xml.XML object GraphML { def saveAsGraphML(graph: ModuleGraph, outputFile: String) { val nodesXml = - for (n <- graph.nodes) - yield - - - {n.id.idString} - - + for (n ← graph.nodes) + yield + + { n.id.idString } + + val edgesXml = - for (e <- graph.edges) - yield + for (e ← graph.edges) + yield val xml = - + - {nodesXml} - {edgesXml} + { nodesXml } + { edgesXml } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala b/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala index c7f8e6395..1e6ce563a 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala @@ -6,50 +6,50 @@ package net.virtualvoid.sbt.graph.util object AsciiTreeLayout { - // [info] foo - // [info] +-bar - // [info] | +-baz - // [info] | - // [info] +-quux - def toAscii[A](top: A, - children: A => Seq[A], - display: A => String, + // [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 = { - val twoSpaces = " " + " " // prevent accidentally being converted into a tab - def limitLine(s: String): String = - if (s.length > maxColumn) s.slice(0, maxColumn - 2) + ".." - else s - def insertBar(s: String, at: Int): String = + val twoSpaces = " " + " " // prevent accidentally being converted into a tab + def limitLine(s: String): String = + if (s.length > maxColumn) s.slice(0, maxColumn - 2) + ".." + else s + def insertBar(s: String, at: Int): String = if (at < s.length) s.slice(0, at) + - (s(at).toString match { - case " " => "|" - case x => x - }) + - s.slice(at + 1, s.length) + (s(at).toString match { + case " " ⇒ "|" + case x ⇒ x + }) + + s.slice(at + 1, s.length) else s - def toAsciiLines(node: A, level: Int, parents: Set[A]): Vector[String] = - if (parents contains node) // cycle - Vector(limitLine((twoSpaces * level) + "#-" + display(node))) - else { - val line = limitLine((twoSpaces * level) + (if (level == 0) "" else "+-") + display(node)) - val cs = Vector(children(node): _*) - val childLines = cs map { - toAsciiLines(_, level + 1, parents + node) - } - val withBar = childLines.zipWithIndex flatMap { - case (lines, pos) if pos < (cs.size - 1) => lines map { - insertBar(_, 2 * (level + 1)) - } - case (lines, pos) => - if (lines.last.trim != "") lines ++ Vector(twoSpaces * (level + 1)) - else lines - } - line +: withBar - } + def toAsciiLines(node: A, level: Int, parents: Set[A]): Vector[String] = + if (parents contains node) // cycle + Vector(limitLine((twoSpaces * level) + "#-" + display(node))) + else { + val line = limitLine((twoSpaces * level) + (if (level == 0) "" else "+-") + display(node)) + val cs = Vector(children(node): _*) + val childLines = cs map { + toAsciiLines(_, level + 1, parents + node) + } + val withBar = childLines.zipWithIndex flatMap { + case (lines, pos) if pos < (cs.size - 1) ⇒ lines map { + insertBar(_, 2 * (level + 1)) + } + case (lines, pos) ⇒ + if (lines.last.trim != "") lines ++ Vector(twoSpaces * (level + 1)) + else lines + } + line +: withBar + } - toAsciiLines(top, 0, Set.empty).mkString("\n") - } + toAsciiLines(top, 0, Set.empty).mkString("\n") + } def defaultColumnSize: Int = { val termWidth = sbt.SbtAccess.getTerminalWidth diff --git a/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala b/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala index cd110c7e4..94fd5c825 100644 --- a/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala +++ b/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala @@ -8,12 +8,12 @@ class AsciiTreeLayoutSpecs extends Specification { case class Leaf(i: Int) extends Tree def children(t: Tree): Seq[Tree] = t match { - case Branch(left, right) => Seq(left, right) - case _: Leaf => Nil + case Branch(left, right) ⇒ Seq(left, right) + case _: Leaf ⇒ Nil } def display(t: Tree): String = t match { - case Branch(left, right) => "Branch" - case Leaf(value) => value.toString * value + case Branch(left, right) ⇒ "Branch" + case Leaf(value) ⇒ value.toString * value } "Graph" should { @@ -66,29 +66,29 @@ class AsciiTreeLayoutSpecs extends Specification { } "cut off cycles" in { AsciiTreeLayout.toAscii[Int](1, Map( - 1 -> Seq(2,3,4), - 2 -> Seq(4,5), + 1 -> Seq(2, 3, 4), + 2 -> Seq(4, 5), 3 -> Seq(), 4 -> Seq(3), - 5 -> Seq(1,4,6,7), + 5 -> Seq(1, 4, 6, 7), 6 -> Seq(), 7 -> Seq()), _.toString).trim === - """1 - | +-2 - | | +-4 - | | | +-3 - | | |\u0020 - | | +-5 - | | #-1 - | | +-4 - | | | +-3 - | | |\u0020 - | | +-6 - | | +-7 - | |\u0020\u0020\u0020 - | +-3 - | +-4 - | +-3""".stripMargin.trim + """1 + | +-2 + | | +-4 + | | | +-3 + | | |\u0020 + | | +-5 + | | #-1 + | | +-4 + | | | +-3 + | | |\u0020 + | | +-6 + | | +-7 + | |\u0020\u0020\u0020 + | +-3 + | +-4 + | +-3""".stripMargin.trim } } } From a82235e8135cc6650e9e82b082620698386999e3 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 17 Nov 2015 17:34:51 +0100 Subject: [PATCH 153/252] make cycles in the graph more visible --- .../scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala | 2 +- .../net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala b/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala index 1e6ce563a..24b8d6063 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala @@ -30,7 +30,7 @@ object AsciiTreeLayout { else s def toAsciiLines(node: A, level: Int, parents: Set[A]): Vector[String] = if (parents contains node) // cycle - Vector(limitLine((twoSpaces * level) + "#-" + display(node))) + Vector(limitLine((twoSpaces * level) + "#-" + display(node) + " (cycle)")) else { val line = limitLine((twoSpaces * level) + (if (level == 0) "" else "+-") + display(node)) val cs = Vector(children(node): _*) diff --git a/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala b/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala index 94fd5c825..097b7adf6 100644 --- a/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala +++ b/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala @@ -79,7 +79,7 @@ class AsciiTreeLayoutSpecs extends Specification { | | | +-3 | | |\u0020 | | +-5 - | | #-1 + | | #-1 (cycle) | | +-4 | | | +-3 | | |\u0020 From 8f107639ae2781276536876884b567eac35a8e06 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 17 Nov 2015 18:02:01 +0100 Subject: [PATCH 154/252] fix typo --- .../scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index a5e8cf944..06b77eca5 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -30,7 +30,7 @@ trait DependencyGraphKeys { 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", - "Creates a dot file containing the dpendency-graph for a project") + "Creates a dot file containing the dependency-graph for a project") val moduleGraph = TaskKey[ModuleGraph]("module-graph", "The dependency graph for a project") val asciiGraph = TaskKey[String]("dependency-graph-string", From 191d12aa7a02086abcb89ba50ddcfd655ce765d0 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 17 Nov 2015 19:14:36 +0100 Subject: [PATCH 155/252] enable plugin automatically --- .../scala/net/virtualvoid/sbt/graph/DependencyGraphPlugin.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphPlugin.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphPlugin.scala index 9389fe8f9..31f36d729 100755 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphPlugin.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphPlugin.scala @@ -23,4 +23,6 @@ object DependencyGraphPlugin extends AutoPlugin { object autoImport extends DependencyGraphKeys override def projectSettings: Seq[Def.Setting[_]] = DependencyGraphSettings.graphSettings + + override def trigger: PluginTrigger = AllRequirements } From a89e63f95618b29adf28c7196867118640ad8bca Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 17 Nov 2015 19:16:02 +0100 Subject: [PATCH 156/252] new backend to generate graph directly from sbt data structures, fixes #39 --- .../sbt/graph/DependencyGraphKeys.scala | 1 + .../sbt/graph/DependencyGraphSettings.scala | 16 ++++--- .../sbt/graph/frontend/SbtUpdateReport.scala | 42 +++++++++++++++++++ .../net/virtualvoid/sbt/graph/package.scala | 1 + 4 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/frontend/SbtUpdateReport.scala diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index 06b77eca5..d8ccdf62b 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -55,6 +55,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") + private[graph] val crossProjectId = SettingKey[ModuleID]("dependency-graph-cross-project-id") } object DependencyGraphKeys extends DependencyGraphKeys \ No newline at end of file diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index ea8c9f681..3c5be5790 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -16,6 +16,7 @@ package net.virtualvoid.sbt.graph +import net.virtualvoid.sbt.graph.frontend.SbtUpdateReport import sbt._ import Keys._ @@ -51,12 +52,11 @@ object DependencyGraphSettings { def ivyReportForConfig(config: Configuration) = inConfig(config)(Seq( ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn (ignoreMissingUpdate), - moduleGraph <<= ivyReport map (absoluteReportPath.andThen(frontend.IvyReport.fromReportFile)), + crossProjectId <<= (scalaVersion, scalaBinaryVersion, projectID)((sV, sBV, id) ⇒ CrossVersion(sV, sBV)(id)), + moduleGraph <<= sbtUpdateReportGraph, moduleGraph <<= (scalaVersion, moduleGraph, filterScalaLibrary) map { (scalaV, graph, filter) ⇒ - if (filter) - GraphTransformations.ignoreScalaLibrary(scalaV, graph) - else - graph + if (filter) GraphTransformations.ignoreScalaLibrary(scalaV, graph) + else graph }, moduleGraphStore <<= moduleGraph storeAs moduleGraphStore triggeredBy moduleGraph, asciiGraph <<= moduleGraph map rendering.AsciiGraph.asciiGraph, @@ -100,6 +100,12 @@ object DependencyGraphSettings { }, licenseInfo <<= (moduleGraph, streams) map showLicenseInfo)) + def ivyReportGraph = ivyReport map (absoluteReportPath.andThen(frontend.IvyReport.fromReportFile)) + def sbtUpdateReportGraph = + (ignoreMissingUpdate, crossProjectId, configuration) map { (update, root, config) ⇒ + SbtUpdateReport.fromConfigurationReport(update.configuration(config.name).get, root) + } + def printAsciiGraphTask = (streams, asciiGraph) map (_.log.info(_)) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/frontend/SbtUpdateReport.scala b/src/main/scala/net/virtualvoid/sbt/graph/frontend/SbtUpdateReport.scala new file mode 100644 index 000000000..fe802ef2c --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/frontend/SbtUpdateReport.scala @@ -0,0 +1,42 @@ +/* + * Copyright 2015 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 frontend + +import sbt._ + +object SbtUpdateReport { + def fromConfigurationReport(report: ConfigurationReport, rootInfo: sbt.ModuleID): ModuleGraph = { + implicit def id(sbtId: sbt.ModuleID): ModuleId = ModuleId(sbtId.organization, sbtId.name, sbtId.revision) + + def moduleEdges(orgArt: OrganizationArtifactReport): Seq[(Module, Seq[Edge])] = { + val chosenVersion = orgArt.modules.find(!_.evicted).map(_.module.revision) + orgArt.modules.map(moduleEdge(chosenVersion)) + } + + def moduleEdge(chosenVersion: Option[String])(report: ModuleReport): (Module, Seq[Edge]) = { + val evictedByVersion = if (report.evicted) chosenVersion else None + (Module(report.module, license = report.licenses.headOption.map(_._1), evictedByVersion = evictedByVersion, error = report.problem), + report.callers.map(caller ⇒ Edge(caller.caller, report.module))) + } + + val (nodes, edges) = report.details.flatMap(moduleEdges).unzip + val root = Module(rootInfo) + + ModuleGraph(root +: nodes, edges.flatten) + } +} diff --git a/src/main/scala/net/virtualvoid/sbt/graph/package.scala b/src/main/scala/net/virtualvoid/sbt/graph/package.scala index 1fe4e5fc1..41921bcfa 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/package.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/package.scala @@ -18,4 +18,5 @@ package net.virtualvoid.sbt package object graph { type Edge = (ModuleId, ModuleId) + def Edge(from: ModuleId, to: ModuleId): Edge = from -> to } From 932085bdf6e7429b490e42334f9e546fec373880 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Tue, 17 Nov 2015 20:39:18 +0100 Subject: [PATCH 157/252] rename frontend -> backend --- .../net/virtualvoid/sbt/graph/DependencyGraphSettings.scala | 4 ++-- src/main/scala/net/virtualvoid/sbt/graph/Main.scala | 4 +++- .../sbt/graph/{frontend => backend}/IvyReport.scala | 5 ++--- .../sbt/graph/{frontend => backend}/SbtUpdateReport.scala | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) rename src/main/scala/net/virtualvoid/sbt/graph/{frontend => backend}/IvyReport.scala (96%) rename src/main/scala/net/virtualvoid/sbt/graph/{frontend => backend}/SbtUpdateReport.scala (98%) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index 3c5be5790..f1ff27d6c 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -16,7 +16,7 @@ package net.virtualvoid.sbt.graph -import net.virtualvoid.sbt.graph.frontend.SbtUpdateReport +import net.virtualvoid.sbt.graph.backend.{ IvyReport, SbtUpdateReport } import sbt._ import Keys._ @@ -100,7 +100,7 @@ object DependencyGraphSettings { }, licenseInfo <<= (moduleGraph, streams) map showLicenseInfo)) - def ivyReportGraph = ivyReport map (absoluteReportPath.andThen(frontend.IvyReport.fromReportFile)) + def ivyReportGraph = ivyReport map (absoluteReportPath.andThen(IvyReport.fromReportFile)) def sbtUpdateReportGraph = (ignoreMissingUpdate, crossProjectId, configuration) map { (update, root, config) ⇒ SbtUpdateReport.fromConfigurationReport(update.configuration(config.name).get, root) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/Main.scala b/src/main/scala/net/virtualvoid/sbt/graph/Main.scala index 5d031abc9..fb51d60b7 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/Main.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/Main.scala @@ -18,6 +18,8 @@ package net.virtualvoid.sbt.graph import java.io.File +import net.virtualvoid.sbt.graph.backend.IvyReport + object Main extends App { def die(msg: String): Nothing = { println(msg) @@ -28,6 +30,6 @@ object Main extends App { val reportFile = args.lift(0).filter(f ⇒ new File(f).exists).getOrElse(die(usage)) val outputFile = args.lift(1).getOrElse(die(usage)) - val graph = frontend.IvyReport.fromReportFile(reportFile) + val graph = IvyReport.fromReportFile(reportFile) rendering.GraphML.saveAsGraphML(graph, outputFile) } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/frontend/IvyReport.scala b/src/main/scala/net/virtualvoid/sbt/graph/backend/IvyReport.scala similarity index 96% rename from src/main/scala/net/virtualvoid/sbt/graph/frontend/IvyReport.scala rename to src/main/scala/net/virtualvoid/sbt/graph/backend/IvyReport.scala index 164b154ea..129dde6d9 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/frontend/IvyReport.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/backend/IvyReport.scala @@ -14,9 +14,8 @@ * limitations under the License. */ -package net.virtualvoid.sbt.graph.frontend - -import net.virtualvoid.sbt.graph._ +package net.virtualvoid.sbt.graph +package backend import scala.xml.{ NodeSeq, Document, Node } import scala.xml.parsing.ConstructingParser diff --git a/src/main/scala/net/virtualvoid/sbt/graph/frontend/SbtUpdateReport.scala b/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala similarity index 98% rename from src/main/scala/net/virtualvoid/sbt/graph/frontend/SbtUpdateReport.scala rename to src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala index fe802ef2c..e7f8fbfd5 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/frontend/SbtUpdateReport.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala @@ -15,7 +15,7 @@ */ package net.virtualvoid.sbt.graph -package frontend +package backend import sbt._ From ac0ab5189a3ca9d9e7b893bad275dd394df89b53 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 18 Nov 2015 17:35:29 +0100 Subject: [PATCH 158/252] in DOT graph render special evicted by edges and access new elements through evicted ones --- .../sbt/graph/DependencyGraphKeys.scala | 2 + .../sbt/graph/DependencyGraphSettings.scala | 29 +++++----- .../virtualvoid/sbt/graph/rendering/DOT.scala | 55 +++++++++++++------ .../virtualvoid/sbt/graph/util/IOUtil.scala | 55 +++++++++++++++++++ 4 files changed, 110 insertions(+), 31 deletions(-) create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/util/IOUtil.scala diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index d8ccdf62b..0dcbb0d15 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -31,6 +31,8 @@ trait DependencyGraphKeys { "The header of the dot file. (e.g. to set your preferred node shapes)") val dependencyDot = TaskKey[File]("dependency-dot", "Creates a dot file containing the dependency-graph for a project") + val dependencyDotString = TaskKey[String]("dependency-dot-string", + "Creates a String containing the dependency-graph for a project in dot format") val moduleGraph = TaskKey[ModuleGraph]("module-graph", "The dependency graph for a project") val asciiGraph = TaskKey[String]("dependency-graph-string", diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index f1ff27d6c..29c8fc306 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -17,12 +17,12 @@ package net.virtualvoid.sbt.graph import net.virtualvoid.sbt.graph.backend.{ IvyReport, SbtUpdateReport } +import net.virtualvoid.sbt.graph.util.IOUtil import sbt._ import Keys._ import CrossVersion._ -import sbt.complete.DefaultParsers._ import sbt.complete.Parser import org.apache.ivy.core.resolve.ResolveOptions @@ -81,17 +81,15 @@ object DependencyGraphSettings { dependencyGraphMLFile <<= target / "dependencies-%s.graphml".format(config.toString), dependencyGraphML <<= dependencyGraphMLTask, dependencyDotFile <<= target / "dependencies-%s.dot".format(config.toString), - dependencyDot <<= dependencyDotTask, + dependencyDotString <<= dependencyDotStringTask, + dependencyDot <<= writeToFile(dependencyDotString, dependencyDotFile), dependencyDotHeader := """digraph "dependency-graph" { | graph[rankdir="LR"] - | node [ - | shape="record" - | ] | edge [ | arrowtail="none" | ]""".stripMargin, dependencyDotNodeLabel := { (organisation: String, name: String, version: String) ⇒ - """<%s
%s
%s>""".format(organisation, name, version) + """%s
%s
%s""".format(organisation, name, version) }, whatDependsOn <<= InputTask(artifactIdParser) { module ⇒ (module, streams, moduleGraph) map { (module, streams, graph) ⇒ @@ -115,14 +113,19 @@ object DependencyGraphSettings { streams.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } - def dependencyDotTask = - (moduleGraph, dependencyDotHeader, dependencyDotNodeLabel, dependencyDotFile, streams).map { - (graph, dotHead, nodeLabel, outFile, streams) ⇒ - - val resultFile = rendering.DOT.saveAsDot(graph, dotHead, nodeLabel, outFile) - streams.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) } + + def writeToFile(dataTask: TaskKey[String], fileTask: SettingKey[File]) = + (dataTask, fileTask, streams).map { (data, outFile, streams) ⇒ + IOUtil.writeToFile(data, outFile) + + streams.log.info("Wrote dependency graph to '%s'" format outFile) + outFile + } + def absoluteReportPath = (file: File) ⇒ file.getAbsolutePath def print(key: TaskKey[String]) = diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala index 3eb168e5b..181e8b7eb 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala @@ -14,31 +14,50 @@ * limitations under the License. */ -package net.virtualvoid.sbt.graph.rendering - -import java.io.File - -import net.virtualvoid.sbt.graph.ModuleGraph +package net.virtualvoid.sbt.graph +package rendering object DOT { - def saveAsDot(graph: ModuleGraph, - dotHead: String, - nodeFormation: (String, String, String) ⇒ String, - outputFile: File): File = { + val EvictedStyle = "stroke-dasharray: 5,5" + + def dotGraph(graph: ModuleGraph, + dotHead: String, + nodeFormation: (String, String, String) ⇒ String): String = { val nodes = { - for (n ← graph.nodes) - yield """ "%s"[label=%s]""".format(n.id.idString, - nodeFormation(n.id.organisation, n.id.name, n.id.version)) + for (n ← graph.nodes) yield { + val style = if (n.isEvicted) EvictedStyle else "" + """ "%s"[labelType="html" label="%s" style="%s"]""".format(n.id.idString, + nodeFormation(n.id.organisation, n.id.name, n.id.version), + style) + } }.mkString("\n") + def originWasEvicted(edge: Edge): Boolean = graph.module(edge._1).isEvicted + def targetWasEvicted(edge: Edge): Boolean = graph.module(edge._2).isEvicted + + // add extra edges from evicted to evicted-by module + val evictedByEdges: Seq[Edge] = + graph.nodes.filter(_.isEvicted).map(m ⇒ Edge(m.id, m.id.copy(version = m.evictedByVersion.get))) + + // remove edges to new evicted-by module which is now replaced by a chain + // dependend -> [evicted] -> dependee + val evictionTargetEdges = + graph.edges.filter(targetWasEvicted).map { + case (from, evicted) ⇒ (from, evicted.copy(version = graph.module(evicted).evictedByVersion.get)) + }.toSet + + val filteredEdges = + graph.edges + .filterNot(e ⇒ originWasEvicted(e) || evictionTargetEdges(e)) ++ evictedByEdges + val edges = { - for (e ← graph.edges) - yield """ "%s" -> "%s"""".format(e._1.idString, e._2.idString) + for (e ← filteredEdges) yield { + val extra = if (graph.module(e._1).isEvicted) + s""" [label="Evicted By" style="$EvictedStyle"]""" else "" + """ "%s" -> "%s"%s""".format(e._1.idString, e._2.idString, extra) + } }.mkString("\n") - val dot = "%s\n%s\n%s\n}".format(dotHead, nodes, edges) - - sbt.IO.write(outputFile, dot) - outputFile + "%s\n%s\n%s\n}".format(dotHead, nodes, edges) } } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/util/IOUtil.scala b/src/main/scala/net/virtualvoid/sbt/graph/util/IOUtil.scala new file mode 100644 index 000000000..c9b8ebbf5 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/util/IOUtil.scala @@ -0,0 +1,55 @@ +/* + * Copyright 2015 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.util + +import java.io.{ OutputStream, InputStream, FileOutputStream, File } +import java.nio.charset.Charset + +import scala.annotation.tailrec + +object IOUtil { + val utf8 = Charset.forName("utf8") + + def writeToFile(string: String, file: File): Unit = + sbt.IO.write(file, string, utf8) + + def saveResource(resourcePath: String, to: File): Unit = { + val is = getClass.getClassLoader.getResourceAsStream(resourcePath) + require(is ne null, s"Couldn't load '$resourcePath' from classpath.") + + val fos = new FileOutputStream(to) + try copy(is, fos) + finally { + is.close() + fos.close() + } + } + + def copy(from: InputStream, to: OutputStream): Unit = { + val buffer = new Array[Byte](65536) + + @tailrec def rec(): Unit = { + val read = from.read(buffer) + if (read > 0) { + to.write(buffer, 0, read) + rec() + } else if (read == 0) + throw new IllegalStateException("InputStream.read returned 0") + } + rec() + } +} From 000b0ed253f6233e5ce67a6ae55a4e549f84ae87 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 18 Nov 2015 17:38:20 +0100 Subject: [PATCH 159/252] render a graph in the browser using dagre-d3 and graphlib-dot, fixes #29 --- src/main/resources/graph.html | 126 ++++++++++++++++++ .../sbt/graph/DependencyGraphKeys.scala | 6 + .../sbt/graph/DependencyGraphSettings.scala | 20 ++- .../net/virtualvoid/sbt/graph/model.scala | 3 +- .../sbt/graph/rendering/DagreHTML.scala | 40 ++++++ 5 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 src/main/resources/graph.html create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/rendering/DagreHTML.scala diff --git a/src/main/resources/graph.html b/src/main/resources/graph.html new file mode 100644 index 000000000..eae90cff0 --- /dev/null +++ b/src/main/resources/graph.html @@ -0,0 +1,126 @@ + + + + + +Dependency Graph + + + + + + + + + + + + + +

Dependencies

+ + + + + + + diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index 0dcbb0d15..7356e97a9 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -33,6 +33,12 @@ trait DependencyGraphKeys { "Creates a dot file containing the dependency-graph for a project") 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", + "The location dependency browse graph files should be put.") + 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", + "Opens an HTML page that can be used to view the graph.") val moduleGraph = TaskKey[ModuleGraph]("module-graph", "The dependency graph for a project") val asciiGraph = TaskKey[String]("dependency-graph-string", diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index 29c8fc306..038c3282a 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -16,8 +16,6 @@ package net.virtualvoid.sbt.graph -import net.virtualvoid.sbt.graph.backend.{ IvyReport, SbtUpdateReport } -import net.virtualvoid.sbt.graph.util.IOUtil import sbt._ import Keys._ @@ -27,6 +25,10 @@ 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.util.IOUtil + object DependencyGraphSettings { import DependencyGraphKeys._ import ModuleGraphProtocol._ @@ -83,6 +85,13 @@ object DependencyGraphSettings { 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...") + java.awt.Desktop.getDesktop.browse(uri) + uri + }, dependencyDotHeader := """digraph "dependency-graph" { | graph[rankdir="LR"] | edge [ @@ -118,6 +127,13 @@ object DependencyGraphSettings { (graph, dotHead, nodeLabel) ⇒ rendering.DOT.dotGraph(graph, dotHead, nodeLabel) } + def browseGraphHTMLTask = + (dependencyDotString, dependencyBrowseGraphTarget, streams).map { (graph, target, streams) ⇒ + val link = DagreHTML.createLink(graph, target) + streams.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) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/model.scala b/src/main/scala/net/virtualvoid/sbt/graph/model.scala index f4b51cfcb..e833d34ab 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/model.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/model.scala @@ -29,7 +29,8 @@ case class Module(id: ModuleId, evictedByVersion: Option[String] = None, error: Option[String] = None) { def hadError: Boolean = error.isDefined - def isUsed: Boolean = !evictedByVersion.isDefined + def isUsed: Boolean = !isEvicted + def isEvicted: Boolean = evictedByVersion.isDefined } case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) { diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/DagreHTML.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/DagreHTML.scala new file mode 100644 index 000000000..3064ef502 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/DagreHTML.scala @@ -0,0 +1,40 @@ +/* + * Copyright 2015 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 + +import java.io.File +import java.net.{ URLEncoder, URI } + +import net.virtualvoid.sbt.graph.util.IOUtil + +object DagreHTML { + def createLink(dotGraph: String, targetDirectory: File): URI = { + targetDirectory.mkdirs() + val graphHTML = new File(targetDirectory, "graph.html") + IOUtil.saveResource("graph.html", graphHTML) + IOUtil.writeToFile(dotGraph, new File(targetDirectory, "dependencies.dot")) + + val graphString = + URLEncoder.encode(dotGraph, "utf8") + .replaceAllLiterally("+", "%20") + + IOUtil.writeToFile(s"""data = "$graphString";""", new File(targetDirectory, "dependencies.dot.js")) + + new URI(graphHTML.toURI.toString) + } +} From eac58262d45f28029129ebaf9d2f28d78cf022f9 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 18 Nov 2015 17:58:23 +0100 Subject: [PATCH 160/252] preliminary overhaul of the README --- README.md | 41 +++++++++++++++++++++++++---------------- project.sbt | 2 +- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index bb0b41e1f..1d029e04f 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,22 @@ sbt-dependency-graph Visualize your project's dependencies. +New in 0.8.x +------------ + + * sbt >= 0.13.8 is now required (for older sbt versions see [0.7.5](https://github.com/jrudolph/sbt-dependency-graph/tree/0.7)) + * This plugin is now an auto-plugin and it is automatically enabled. + * Code was restructured which touched a lot of the classes but didn't change the function or syntax of settings and tasks. + * 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. + * (experimental) the DOT graph can now be shown in the browser. Try the new `dependencyBrowseGraph` task. + * A few smaller bug fixes. + +The README has not yet been completely overhauled so please send a PR against the 0.8 branch if you find something missing +or inaccurate. + How To Use ---------- @@ -11,29 +27,22 @@ install it as a [global plugin] so that you can use it in any SBT project withou this, add the plugin dependency to `~/.sbt/0.13/plugins/plugins.sbt`: ```scala -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.7.5") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.0-beta1") ``` -Then, apply the plugin's settings in `~/.sbt/0.13/global.sbt`, the [global build configuration], by adding the following line: - -```scala -net.virtualvoid.sbt.graph.Plugin.graphSettings -``` - -Note, that sbt-dependency-graph is not an [AutoPlugin](http://www.scala-sbt.org/0.13/docs/Plugins.html#Creating+an+auto+plugin) yet (until [#51](https://github.com/jrudolph/sbt-dependency-graph/issues/51) is fixed), so adding the above line to your global or project configuration is mandatory. - -Tasks ------ +Main Tasks +---------- + * `dependency-tree`: Shows an ASCII tree representation of the project's dependencies * `dependency-graph`: Shows an ASCII graph of the project's dependencies on the sbt console + * `dependency-browse-graph`: Opens a browser window with a visualization of the dependency graph (courtesy of graphlib-dot + dagre-d3). + * `what-depends-on `: Find out what depends on an artifact. Shows a reverse dependency + tree for the selected module. + * `dependency-license-info`: show dependencies grouped by declared license * `dependency-graph-ml`: Generates a .graphml file with the project's dependencies to `target/dependencies-.graphml`. Use e.g. [yEd](http://www.yworks.com/en/products_yed_about.html) to format the graph to your needs. * `dependency-dot`: Generates a .dot file with the project's dependencies to `target/dependencies-.dot`. Use [graphviz](http://www.graphviz.org/) to render it to your preferred graphic format. - * `dependency-tree`: Shows an ASCII tree representation of the project's dependencies - * `what-depends-on `: Find out what depends on an artifact. Shows a reverse dependency - tree for the selected module. - * `dependency-license-info`: show dependencies grouped by declared license * `ivy-report`: let's ivy generate the resolution report for you project. Use `show ivy-report` for the filename of the generated report @@ -95,7 +104,7 @@ Credits License ------- -Copyright (c) 2011, 2012 Johannes Rudolph +Copyright (c) 2011, 2012, 2013, 2014, 2015 Johannes Rudolph Published under the [Apache License 2.0](http://en.wikipedia.org/wiki/Apache_license). diff --git a/project.sbt b/project.sbt index c61f29c46..9026b5536 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.8.0-SNAPSHOT" +version := "0.8.0-beta1" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From 167a8a3f507059fac6571c334aca7c312b13e195 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 18 Nov 2015 18:22:51 +0100 Subject: [PATCH 161/252] Link to 0.8 branch in README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index bb0b41e1f..08d11cc30 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ sbt-dependency-graph Visualize your project's dependencies. +**Note: A more recent (currently experimental) version lives in the [0.8 branch](https://github.com/jrudolph/sbt-dependency-graph/tree/0.8).** + How To Use ---------- From a821b278093e25fdaba8bf511c6e93865a2cfad2 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 25 Nov 2015 16:50:30 +0100 Subject: [PATCH 162/252] bump version to 0.8.0 and update README to reflect changes --- NOTICE | 2 +- README.md | 53 ++++++++++++++++---------------------------- notes/0.8.0.markdown | 14 ++++++++++++ project.sbt | 2 +- 4 files changed, 35 insertions(+), 36 deletions(-) create mode 100644 notes/0.8.0.markdown diff --git a/NOTICE b/NOTICE index 59536b942..282e7e8e5 100644 --- a/NOTICE +++ b/NOTICE @@ -1,4 +1,4 @@ -Graph.scala is copied from sbt and is distributed under the following license: +AsciiTreeLayout.scala is copied from sbt and is distributed under the following license: Copyright (c) 2008, 2009, 2010 Steven Blundy, Josh Cough, Mark Harrah, Stuart Roebuck, Tony Sloane, Vesa Vilhonen, Jason Zaugg All rights reserved. diff --git a/README.md b/README.md index 1d029e04f..10b0146ce 100644 --- a/README.md +++ b/README.md @@ -3,21 +3,11 @@ sbt-dependency-graph Visualize your project's dependencies. -New in 0.8.x ------------- +Preliminaries +------------- - * sbt >= 0.13.8 is now required (for older sbt versions see [0.7.5](https://github.com/jrudolph/sbt-dependency-graph/tree/0.7)) - * This plugin is now an auto-plugin and it is automatically enabled. - * Code was restructured which touched a lot of the classes but didn't change the function or syntax of settings and tasks. - * 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. - * (experimental) the DOT graph can now be shown in the browser. Try the new `dependencyBrowseGraph` task. - * A few smaller bug fixes. - -The README has not yet been completely overhauled so please send a PR against the 0.8 branch if you find something missing -or inaccurate. +Starting with version 0.8.0, the plugin will only work for sbt-projects that use sbt >= 0.13.8. See +the [0.7 branch](https://github.com/jrudolph/sbt-dependency-graph/tree/0.7) for older versions that still work with sbt < 0.13.8. How To Use ---------- @@ -27,26 +17,30 @@ install it as a [global plugin] so that you can use it in any SBT project withou this, add the plugin dependency to `~/.sbt/0.13/plugins/plugins.sbt`: ```scala -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.0-beta1") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.0") ``` +This plugin is an auto-plugin which will be automatically enabled. + +To add the plugin only to a single project, put this line into `project/plugins.sbt` of your project, instead. + Main Tasks ---------- - * `dependency-tree`: Shows an ASCII tree representation of the project's dependencies - * `dependency-graph`: Shows an ASCII graph of the project's dependencies on the sbt console - * `dependency-browse-graph`: Opens a browser window with a visualization of the dependency graph (courtesy of graphlib-dot + dagre-d3). - * `what-depends-on `: Find out what depends on an artifact. Shows a reverse dependency + * `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 + * `whatDependsOn `: Find out what depends on an artifact. Shows a reverse dependency tree for the selected module. - * `dependency-license-info`: show dependencies grouped by declared license - * `dependency-graph-ml`: Generates a .graphml file with the project's dependencies to `target/dependencies-.graphml`. + * `dependencyLicenseInfo`: show dependencies grouped by declared license + * `dependencyGraphMl`: Generates a `.graphml` file with the project's dependencies to `target/dependencies-.graphml`. Use e.g. [yEd](http://www.yworks.com/en/products_yed_about.html) to format the graph to your needs. - * `dependency-dot`: Generates a .dot file with the project's dependencies to `target/dependencies-.dot`. + * `dependencyDot`: Generates a .dot file with the project's dependencies to `target/dependencies-.dot`. Use [graphviz](http://www.graphviz.org/) to render it to your preferred graphic format. - * `ivy-report`: let's ivy generate the resolution report for you project. Use - `show ivy-report` for the filename of the generated report + * `ivyReport`: let's 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:dependency-graph`, +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. @@ -93,19 +87,10 @@ Known issues * #19: There's an unfixed bug with graph generation for particular layouts. Workaround: Use `dependency-tree` instead of `dependency-graph`. - * #12: Excluded dependencies will be shown in the graph in sbt < 0.12, works with later versions - -Credits -------- - - * Matt Russell (@mdr) for contributing the ASCII graph layout. - * berleon (@berleon) for contributing rendering to dot. License ------- -Copyright (c) 2011, 2012, 2013, 2014, 2015 Johannes Rudolph - Published under the [Apache License 2.0](http://en.wikipedia.org/wiki/Apache_license). [global plugin]: http://www.scala-sbt.org/0.13/tutorial/Using-Plugins.html#Global+plugins diff --git a/notes/0.8.0.markdown b/notes/0.8.0.markdown new file mode 100644 index 000000000..5008fe3b7 --- /dev/null +++ b/notes/0.8.0.markdown @@ -0,0 +1,14 @@ +This is a major release which brings a few breaking changes. + +New features: + - (experimental) open dependency graph directly in the browser with `dependencyBrowseGraph` ([#24](https://github.com/jrudolph/sbt-dependency-graph/issues/24)) + +Other changes: + - sbt >= 0.13.8 is now required + - this plugin is now an auto-plugin and it is automatically enabled ([#51](https://github.com/jrudolph/sbt-dependency-graph/issues/51)) + - 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. + - 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) \ No newline at end of file diff --git a/project.sbt b/project.sbt index 9026b5536..e45164a0f 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.8.0-beta1" +version := "0.8.0" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From 83a311b4af5584080c913798dbfb76d690137445 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Thu, 26 Nov 2015 11:53:47 +0100 Subject: [PATCH 163/252] make it compile again with sbt 0.13.6 --- build.sbt | 2 +- .../net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 4cec1065f..59deabbe9 100644 --- a/build.sbt +++ b/build.sbt @@ -20,7 +20,7 @@ scalacOptions ++= Seq("-deprecation", "-unchecked") sbt.CrossBuilding.latestCompatibleVersionMapper ~= { original => { - case "0.13" => "0.13.8" + case "0.13" => "0.13.6" case x => original(x) } } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala b/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala index e7f8fbfd5..432fb80e0 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala @@ -20,6 +20,10 @@ package backend import sbt._ object SbtUpdateReport { + type OrganizationArtifactReport = { + def modules: Seq[ModuleReport] + } + def fromConfigurationReport(report: ConfigurationReport, rootInfo: sbt.ModuleID): ModuleGraph = { implicit def id(sbtId: sbt.ModuleID): ModuleId = ModuleId(sbtId.organization, sbtId.name, sbtId.revision) From 21e5b7ce5be308bd6c1de8cf3b7872f43ffcfb11 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Thu, 26 Nov 2015 11:56:00 +0100 Subject: [PATCH 164/252] refactoring --- .../sbt/graph/DependencyGraphSettings.scala | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index 038c3282a..a8bc387ad 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -34,20 +34,7 @@ object DependencyGraphSettings { import ModuleGraphProtocol._ def graphSettings = Seq( - ivyReportFunction <<= (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)) - } - }, + ivyReportFunction <<= ivyReportFunctionTask, updateConfiguration in ignoreMissingUpdate <<= updateConfiguration(config ⇒ new UpdateConfiguration(config.retrieve, true, config.logging)), ignoreMissingUpdateT, filterScalaLibrary in Global := true) ++ Seq(Compile, Test, Runtime, Provided, Optional).flatMap(ivyReportForConfig) @@ -107,6 +94,22 @@ object DependencyGraphSettings { }, licenseInfo <<= (moduleGraph, streams) map showLicenseInfo)) + 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 ivyReportGraph = ivyReport map (absoluteReportPath.andThen(IvyReport.fromReportFile)) def sbtUpdateReportGraph = (ignoreMissingUpdate, crossProjectId, configuration) map { (update, root, config) ⇒ From 2a54348003ed998ab7a48a2f0482f9c631265892 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Thu, 26 Nov 2015 13:18:08 +0100 Subject: [PATCH 165/252] fall back on ivy report XML for sbt < 0.13.6 --- .../virtualvoid/sbt/graph/DependencyGraphKeys.scala | 4 ++++ .../sbt/graph/DependencyGraphSettings.scala | 13 ++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index 7356e97a9..e0159a4f0 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -41,6 +41,10 @@ trait DependencyGraphKeys { "Opens an HTML page that can be used to view the graph.") val moduleGraph = TaskKey[ModuleGraph]("module-graph", "The dependency graph for a project") + 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", + "The dependency graph for a project as generated from SBT data structures.") 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", diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index a8bc387ad..55234b2da 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -42,7 +42,14 @@ object DependencyGraphSettings { 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)), - moduleGraph <<= sbtUpdateReportGraph, + moduleGraphSbt <<= moduleGraphSbtTask, + moduleGraphIvyReport <<= moduleGraphIvyReportTask, + moduleGraph <<= (sbtVersion, moduleGraphSbt, moduleGraphIvyReport) { (version, graphSbt, graphIvy) ⇒ + version match { + case Version(0, 13, x, _) if x >= 6 ⇒ graphSbt + case _ ⇒ graphIvy + } + }, moduleGraph <<= (scalaVersion, moduleGraph, filterScalaLibrary) map { (scalaV, graph, filter) ⇒ if (filter) GraphTransformations.ignoreScalaLibrary(scalaV, graph) else graph @@ -110,8 +117,8 @@ object DependencyGraphSettings { } } - def ivyReportGraph = ivyReport map (absoluteReportPath.andThen(IvyReport.fromReportFile)) - def sbtUpdateReportGraph = + def moduleGraphIvyReportTask = ivyReport map (absoluteReportPath.andThen(IvyReport.fromReportFile)) + def moduleGraphSbtTask = (ignoreMissingUpdate, crossProjectId, configuration) map { (update, root, config) ⇒ SbtUpdateReport.fromConfigurationReport(update.configuration(config.name).get, root) } From 7b7f4d983fff61906d8f714c330fc737a99040a7 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Thu, 26 Nov 2015 13:18:18 +0100 Subject: [PATCH 166/252] update README / notes --- README.md | 62 +++++++++++++++++++------------------------- notes/0.8.0.markdown | 5 ++-- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 10b0146ce..ebaff4cbd 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,14 @@ -sbt-dependency-graph -==================== +# sbt-dependency-graph Visualize your project's dependencies. -Preliminaries -------------- +## Preliminaries -Starting with version 0.8.0, the plugin will only work for sbt-projects that use sbt >= 0.13.8. See -the [0.7 branch](https://github.com/jrudolph/sbt-dependency-graph/tree/0.7) for older versions that still work with sbt < 0.13.8. +Starting with version 0.8.0, the plugin will only work for projects that use sbt 0.13.x. See +the [0.7 branch](https://github.com/jrudolph/sbt-dependency-graph/tree/0.7) for older versions that still work with +sbt < 0.13. -How To Use ----------- +## How To Use Since sbt-dependency-graph is an informational tool rather than one that changes your build, 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 @@ -20,12 +18,12 @@ this, add the plugin dependency to `~/.sbt/0.13/plugins/plugins.sbt`: addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.0") ``` -This plugin is an auto-plugin which will be automatically enabled. - To add the plugin only to a single project, put this line into `project/plugins.sbt` of your project, instead. -Main Tasks ----------- +This plugin is an auto-plugin which will be automatically enabled starting from sbt 0.13.5. See the +[compatibility notes](#Compatibility notes) when using this plugin with sbt < 0.13.6. + +## 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). @@ -44,10 +42,8 @@ All tasks can be scoped to a configuration to get the report for a specific conf for example, prints the dependencies in the `test` configuration. If you don't specify any configuration, `compile` is assumed as usual. +## Configuration settings -Configuration settings ----------------------- - * `filterScalaLibrary`: Defines if the scala library should be excluded from the output of the dependency-* functions. If `true`, instead of showing the dependency `"[S]"` is appended to the artifact name. Set to `false` if you want the scala-library dependency to appear in the output. (default: true) @@ -65,33 +61,27 @@ filterScalaLibrary := false // include scala library in output dependencyDotFile := file("dependencies.dot") //render dot file to `./dependencies.dot` ``` -Standalone usage ----------------- - -You can use the project without sbt as well by either depending on the library and calling -`IvyGraphMLDependencies.saveAsGraphML(IvyGraphMLDependencies.graph(reportFile), outputFile)` or by just getting the binary -and calling it like `scala sbt-dependency-graph-0.7.5.jar `. - -Inner Workings --------------- - -sbt/Ivy's `update` task create ivy-report xml-files inside `.ivy2/cache` (in sbt 0.12.1: -`/target/resolution-cache/reports/`). You can -just open them with your browser to look at the dependency report for your project. -This project takes the report xml of your project and creates a graphml file out of it. (BTW, -ivy can create graphml files itself, but since I didn't want to spend to much time getting -sbt to call into Ivy to create graphs, I went with the easy way here) - -Known issues ------------- +## Known issues * #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. -License -------- +## Compatibility notes + + * sbt < 0.13.6: fallback on the old ivy report XML backend which suffers from [#39] + * sbt < 0.13.5: 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. + +## License Published under the [Apache License 2.0](http://en.wikipedia.org/wiki/Apache_license). [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 +[#39]: https://github.com/jrudolph/sbt-dependency-graph/issues/39 \ No newline at end of file diff --git a/notes/0.8.0.markdown b/notes/0.8.0.markdown index 5008fe3b7..7251f0e2c 100644 --- a/notes/0.8.0.markdown +++ b/notes/0.8.0.markdown @@ -1,14 +1,15 @@ This is a major release which brings a few breaking changes. New features: + - (experimental) open dependency graph directly in the browser with `dependencyBrowseGraph` ([#24](https://github.com/jrudolph/sbt-dependency-graph/issues/24)) Other changes: - - sbt >= 0.13.8 is now required + - this plugin is now an auto-plugin and it is automatically enabled ([#51](https://github.com/jrudolph/sbt-dependency-graph/issues/51)) - 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. + 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) \ No newline at end of file From 90923e9be55323b89486506b3ff26b5d119cb771 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Thu, 26 Nov 2015 13:26:21 +0100 Subject: [PATCH 167/252] fix scripted tests --- .../sbt-dependency-graph/build.properties | 1 + .../ignoreScalaLibrary/build.sbt | 4 ---- .../ignoreScalaLibrary/project/build.properties | 1 + .../intervalRangedVersions/build.sbt | 4 ---- .../project/build.properties | 1 + .../showMissingUpdates/build.sbt | 4 ---- .../showMissingUpdates/project/build.properties | 1 + .../testDotFileGeneration/project/Build.scala | 17 +++++++---------- .../project/build.properties | 1 + 9 files changed, 12 insertions(+), 22 deletions(-) create mode 100644 src/sbt-test/sbt-dependency-graph/build.properties create mode 120000 src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/build.properties create mode 120000 src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/build.properties create mode 120000 src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/build.properties create mode 120000 src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.properties diff --git a/src/sbt-test/sbt-dependency-graph/build.properties b/src/sbt-test/sbt-dependency-graph/build.properties new file mode 100644 index 000000000..df58110af --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/build.properties @@ -0,0 +1 @@ +sbt.version=0.13.6 \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt index 025703043..8c47bfc25 100644 --- a/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt +++ b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt @@ -1,7 +1,3 @@ -import net.virtualvoid.sbt.graph.Plugin._ - -graphSettings - scalaVersion := "2.9.2" libraryDependencies ++= Seq( diff --git a/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/build.properties b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/build.properties new file mode 120000 index 000000000..fe5407f08 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/build.properties @@ -0,0 +1 @@ +../../build.properties \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt index 0ef12f58a..b73285b94 100644 --- a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt +++ b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt @@ -1,7 +1,3 @@ -import net.virtualvoid.sbt.graph.Plugin._ - -graphSettings - scalaVersion := "2.9.1" libraryDependencies ++= Seq( diff --git a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/build.properties b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/build.properties new file mode 120000 index 000000000..fe5407f08 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/build.properties @@ -0,0 +1 @@ +../../build.properties \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt index 232b18d22..6ca4b0313 100644 --- a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt +++ b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt @@ -1,7 +1,3 @@ -import net.virtualvoid.sbt.graph.Plugin._ - -graphSettings - scalaVersion := "2.9.2" libraryDependencies += diff --git a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/build.properties b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/build.properties new file mode 120000 index 000000000..fe5407f08 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/build.properties @@ -0,0 +1 @@ +../../build.properties \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala index a4a1622ba..720d27ddf 100644 --- a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala +++ b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala @@ -1,13 +1,14 @@ import collection.mutable.ListBuffer -import net.virtualvoid.sbt.graph.Plugin._ import sbt._ import sbt.Keys._ +import net.virtualvoid.sbt.graph.DependencyGraphKeys._ + object Build extends sbt.Build { def defaultSettings = - seq(scalaVersion := "2.9.2") + Seq(scalaVersion := "2.9.2") lazy val justATransiviteDependencyEndpointProject = Project("just-a-transitive-dependency-endpoint", file("a")) @@ -24,23 +25,19 @@ object Build extends sbt.Build { lazy val test_project = Project("test-dot-file-generation", file("d")) - .settings(graphSettings: _*) .settings(defaultSettings: _*) .settings( TaskKey[Unit]("check") <<= (dependencyDot in Compile) map { (dotFile) => val expectedGraph = """digraph "dependency-graph" { | graph[rankdir="LR"] - | node [ - | shape="record" - | ] | edge [ | arrowtail="none" | ] - | "test-dot-file-generation:test-dot-file-generation_2.9.2:0.1-SNAPSHOT"[label=test-dot-file-generation_2.9.2
0.1-SNAPSHOT>] - | "just-a-transitive-dependency:just-a-transitive-dependency_2.9.2:0.1-SNAPSHOT"[label=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"[label=just-a-transitive-dependency-endpoint_2.9.2
0.1-SNAPSHOT>] - | "just-a-dependency:just-a-dependency_2.9.2:0.1-SNAPSHOT"[label=just-a-dependency_2.9.2
0.1-SNAPSHOT>] + | "test-dot-file-generation:test-dot-file-generation_2.9.2:0.1-SNAPSHOT"[labelType="html" label="test-dot-file-generation
test-dot-file-generation_2.9.2
0.1-SNAPSHOT" style=""] + | "just-a-transitive-dependency:just-a-transitive-dependency_2.9.2:0.1-SNAPSHOT"[labelType="html" label="just-a-transitive-dependency
just-a-transitive-dependency_2.9.2
0.1-SNAPSHOT" style=""] + | "just-a-transitive-dependency-endpoint:just-a-transitive-dependency-endpoint_2.9.2:0.1-SNAPSHOT"[labelType="html" label="just-a-transitive-dependency-endpoint
just-a-transitive-dependency-endpoint_2.9.2
0.1-SNAPSHOT" style=""] + | "just-a-dependency:just-a-dependency_2.9.2:0.1-SNAPSHOT"[labelType="html" label="just-a-dependency
just-a-dependency_2.9.2
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" diff --git a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.properties b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.properties new file mode 120000 index 000000000..fe5407f08 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.properties @@ -0,0 +1 @@ +../../build.properties \ No newline at end of file From 5655b98c1e46610a849b9e8dae6e95f741cdbbb0 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Thu, 26 Nov 2015 13:35:01 +0100 Subject: [PATCH 168/252] Fix links in README --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ebaff4cbd..9818a596f 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.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. See the -[compatibility notes](#Compatibility notes) when using this plugin with sbt < 0.13.6. +[compatibility notes](#Compatibility-notes) when using this plugin with sbt < 0.13.6. ## Main Tasks @@ -63,7 +63,7 @@ dependencyDotFile := file("dependencies.dot") //render dot file to `./dependenci ## Known issues - * #19: There's an unfixed bug with graph generation for particular layouts. Workaround: + * [#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. @@ -84,4 +84,5 @@ 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 -[#39]: https://github.com/jrudolph/sbt-dependency-graph/issues/39 \ No newline at end of file +[#19]: https://github.com/jrudolph/sbt-dependency-graph/issues/19 +[#39]: https://github.com/jrudolph/sbt-dependency-graph/issues/39 From 21ccad21096d66100017aa552ab704c007200822 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Thu, 26 Nov 2015 14:32:22 +0100 Subject: [PATCH 169/252] fix notes --- notes/0.8.0.markdown | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/notes/0.8.0.markdown b/notes/0.8.0.markdown index 7251f0e2c..c8b76a665 100644 --- a/notes/0.8.0.markdown +++ b/notes/0.8.0.markdown @@ -1,15 +1,20 @@ -This is a major release which brings a few breaking changes. +sbt-dependency-graph is finally an AutoPlugin and learned to render graph in the browser. -New features: +## New features - - (experimental) open dependency graph directly in the browser with `dependencyBrowseGraph` ([#24](https://github.com/jrudolph/sbt-dependency-graph/issues/24)) + - (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) -Other changes: + - 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 remove the `net.virtualvoid.sbt.graph.Plugin.graphSettings` line from your configurations.** + +## Other changes - - this plugin is now an auto-plugin and it is automatically enabled ([#51](https://github.com/jrudolph/sbt-dependency-graph/issues/51)) - 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) \ No newline at end of file + - fixed [#77](https://github.com/jrudolph/sbt-dependency-graph/issues/77) From ce4c20dc60fa0f961e3a946d1b16737e98edc753 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Thu, 26 Nov 2015 14:36:04 +0100 Subject: [PATCH 170/252] Better README wording --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index e5185d5aa..1867f73cc 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@ Visualize your project's dependencies. ## Preliminaries -Starting with version 0.8.0, the plugin will work best with sbt >= 0.13.6. See the -[compatibility notes](#Compatibility-notes) when using this plugin with sbt < 0.13.6. +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 From 8e43a2fd027b635bf7096a87184b424a7975713e Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Thu, 26 Nov 2015 14:43:22 +0100 Subject: [PATCH 171/252] Better wording --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1867f73cc..5f1bb48e3 100644 --- a/README.md +++ b/README.md @@ -66,15 +66,15 @@ dependencyDotFile := file("dependencies.dot") //render dot file to `./dependenci ## Compatibility notes - * sbt < 0.13.6: fallback on the old ivy report XML backend which suffers from [#39] - * sbt < 0.13.5: no autoplugin support, you need to add + * 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 - ``` + ```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). - to your `build.sbt` or (`~/.sbt/0.13/user.sbt` for global configuration) to enable the plugin. - * sbt <= 0.12.x: please use the old version from the [0.7 branch](https://github.com/jrudolph/sbt-dependency-graph/tree/0.7) ## License From 0e0a30fd6fba8344e02d0f74b5ad985b1665f572 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Thu, 26 Nov 2015 14:43:31 +0100 Subject: [PATCH 172/252] update notes --- notes/0.8.0.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notes/0.8.0.markdown b/notes/0.8.0.markdown index c8b76a665..9670242c8 100644 --- a/notes/0.8.0.markdown +++ b/notes/0.8.0.markdown @@ -1,4 +1,4 @@ -sbt-dependency-graph is finally an AutoPlugin and learned to render graph in the browser. +sbt-dependency-graph is finally an AutoPlugin and can now show the dependency graph in the browser directly. ## New features @@ -8,7 +8,7 @@ sbt-dependency-graph is finally an AutoPlugin and learned to render graph in the - 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 remove the `net.virtualvoid.sbt.graph.Plugin.graphSettings` line from your configurations.** +**Note: To update from 0.7.x remove the `net.virtualvoid.sbt.graph.Plugin.graphSettings` line from your configurations.** ## Other changes From cc2c3d1d9ec8727eaec0c0a6b39c34dca29686b5 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 8 Jan 2016 17:14:51 +0100 Subject: [PATCH 173/252] bump version --- project.sbt | 2 +- src/sbt-test/sbt-dependency-graph/plugins.sbt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/project.sbt b/project.sbt index e45164a0f..05275e95f 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.8.0" +version := "0.8.1-SNAPSHOT" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) diff --git a/src/sbt-test/sbt-dependency-graph/plugins.sbt b/src/sbt-test/sbt-dependency-graph/plugins.sbt index fe656e183..0fc2a349c 100644 --- a/src/sbt-test/sbt-dependency-graph/plugins.sbt +++ b/src/sbt-test/sbt-dependency-graph/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.0-SNAPSHOT") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.1-SNAPSHOT") From 00d64878aa94aec27061f59c153e19a1c13d86d5 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 8 Jan 2016 17:14:00 +0100 Subject: [PATCH 174/252] dependencyDot: fix rendering of HTML labels, fixes #84 --- .../sbt/graph/DependencyGraphSettings.scala | 7 ++--- .../virtualvoid/sbt/graph/rendering/DOT.scala | 26 ++++++++++++++++--- .../testDotFileGeneration/project/Build.scala | 8 +++--- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index 55234b2da..98ca55d39 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -134,12 +134,13 @@ object DependencyGraphSettings { } def dependencyDotStringTask = (moduleGraph, dependencyDotHeader, dependencyDotNodeLabel).map { - (graph, dotHead, nodeLabel) ⇒ rendering.DOT.dotGraph(graph, dotHead, nodeLabel) + (graph, dotHead, nodeLabel) ⇒ rendering.DOT.dotGraph(graph, dotHead, nodeLabel, rendering.DOT.AngleBrackets) } def browseGraphHTMLTask = - (dependencyDotString, dependencyBrowseGraphTarget, streams).map { (graph, target, streams) ⇒ - val link = DagreHTML.createLink(graph, target) + (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") link } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala index 181e8b7eb..368cf9e2d 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/DOT.scala @@ -22,12 +22,14 @@ object DOT { def dotGraph(graph: ModuleGraph, dotHead: String, - nodeFormation: (String, String, String) ⇒ String): String = { + nodeFormation: (String, String, String) ⇒ String, + labelRendering: HTMLLabelRendering): String = { val nodes = { for (n ← graph.nodes) yield { val style = if (n.isEvicted) EvictedStyle else "" - """ "%s"[labelType="html" label="%s" style="%s"]""".format(n.id.idString, - nodeFormation(n.id.organisation, n.id.name, n.id.version), + val label = nodeFormation(n.id.organisation, n.id.name, n.id.version) + """ "%s"[%s style="%s"]""".format(n.id.idString, + labelRendering.renderLabel(label), style) } }.mkString("\n") @@ -60,4 +62,22 @@ object DOT { "%s\n%s\n%s\n}".format(dotHead, nodes, edges) } + + sealed trait HTMLLabelRendering { + def renderLabel(labelText: String): String + } + /** + * Render HTML labels in Angle brackets as defined at http://graphviz.org/content/node-shapes#html + */ + case object AngleBrackets extends HTMLLabelRendering { + def renderLabel(labelText: String): String = s"label=<$labelText>" + } + + /** + * Render HTML labels with `labelType="html"` and label content in double quotes as supported by + * dagre-d3 + */ + case object LabelTypeHtml extends HTMLLabelRendering { + def renderLabel(labelText: String): String = s"""labelType="html" label="$labelText"""" + } } diff --git a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala index 720d27ddf..d5081feb1 100644 --- a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala +++ b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala @@ -34,10 +34,10 @@ object Build extends sbt.Build { | edge [ | arrowtail="none" | ] - | "test-dot-file-generation:test-dot-file-generation_2.9.2:0.1-SNAPSHOT"[labelType="html" label="test-dot-file-generation
test-dot-file-generation_2.9.2
0.1-SNAPSHOT" style=""] - | "just-a-transitive-dependency:just-a-transitive-dependency_2.9.2:0.1-SNAPSHOT"[labelType="html" label="just-a-transitive-dependency
just-a-transitive-dependency_2.9.2
0.1-SNAPSHOT" style=""] - | "just-a-transitive-dependency-endpoint:just-a-transitive-dependency-endpoint_2.9.2:0.1-SNAPSHOT"[labelType="html" label="just-a-transitive-dependency-endpoint
just-a-transitive-dependency-endpoint_2.9.2
0.1-SNAPSHOT" style=""] - | "just-a-dependency:just-a-dependency_2.9.2:0.1-SNAPSHOT"[labelType="html" label="just-a-dependency
just-a-dependency_2.9.2
0.1-SNAPSHOT" style=""] + | "test-dot-file-generation:test-dot-file-generation_2.9.2:0.1-SNAPSHOT"[label=test-dot-file-generation_2.9.2
0.1-SNAPSHOT> style=""] + | "just-a-transitive-dependency:just-a-transitive-dependency_2.9.2:0.1-SNAPSHOT"[label=just-a-transitive-dependency_2.9.2
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_2.9.2
0.1-SNAPSHOT> style=""] + | "just-a-dependency:just-a-dependency_2.9.2:0.1-SNAPSHOT"[label=just-a-dependency_2.9.2
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" From f7e3a49e932c47085a75e6d2baf4df600cfdd590 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 8 Jan 2016 17:29:29 +0100 Subject: [PATCH 175/252] add `dependency-list`, fixes #85 --- README.md | 1 + .../sbt/graph/DependencyGraphKeys.scala | 4 ++- .../sbt/graph/DependencyGraphSettings.scala | 1 + .../sbt/graph/rendering/FlatList.scala | 28 +++++++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/rendering/FlatList.scala diff --git a/README.md b/README.md index 5f1bb48e3..ab20fbaa2 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ This plugin is an auto-plugin which will be automatically enabled starting from * `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 `: Find out what depends on an artifact. Shows a reverse dependency tree for the selected module. * `dependencyLicenseInfo`: show dependencies grouped by declared license diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index e0159a4f0..a5b33d26e 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -52,7 +52,9 @@ trait DependencyGraphKeys { 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", - "Prints the ascii tree to the console") + "Prints an ascii tree of all the dependencies to the console") + val dependencyList = TaskKey[Unit]("dependency-list", + "Prints a list of all dependencies to the console") 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", diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index 98ca55d39..776eef144 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -86,6 +86,7 @@ object DependencyGraphSettings { java.awt.Desktop.getDesktop.browse(uri) uri }, + dependencyList <<= (moduleGraph, streams).map((graph, streams) ⇒ streams.log.info(rendering.FlatList.render(graph, _.id.idString))), dependencyDotHeader := """digraph "dependency-graph" { | graph[rankdir="LR"] | edge [ diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/FlatList.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/FlatList.scala new file mode 100644 index 000000000..eb26cff87 --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/FlatList.scala @@ -0,0 +1,28 @@ +/* + * Copyright 2016 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 FlatList { + def render(graph: ModuleGraph, display: Module ⇒ String): String = + graph.modules.values.toSeq + .distinct + .filterNot(_.isEvicted) + .sortBy(m ⇒ (m.id.organisation, m.id.name)) + .map(display) + .mkString("\n") +} From c9d1f81149ba6d096438df931e4e0c5a36d0cd7d Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 8 Jan 2016 18:30:01 +0100 Subject: [PATCH 176/252] added `dependencyStats`: a tabular console output showing an overview of jar-sizes, fixes #83 --- README.md | 1 + .../sbt/graph/DependencyGraphKeys.scala | 2 + .../sbt/graph/DependencyGraphSettings.scala | 6 +- .../sbt/graph/backend/SbtUpdateReport.scala | 8 ++- .../net/virtualvoid/sbt/graph/model.scala | 8 ++- .../sbt/graph/rendering/AsciiTree.scala | 2 +- .../sbt/graph/rendering/Statistics.scala | 71 +++++++++++++++++++ 7 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/rendering/Statistics.scala diff --git a/README.md b/README.md index ab20fbaa2..af98ed9ff 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ This plugin is an auto-plugin which will be automatically enabled starting from * `whatDependsOn `: Find out what depends on an artifact. Shows a reverse dependency tree for the selected module. * `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`. 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-.dot`. diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index a5b33d26e..ace01d160 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -55,6 +55,8 @@ trait DependencyGraphKeys { "Prints an ascii tree of all the dependencies to the console") val dependencyList = TaskKey[Unit]("dependency-list", "Prints a list of all dependencies to the console") + val dependencyStats = TaskKey[Unit]("dependency-stats", + "Prints statistics for all dependencies to the console") 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", diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index 776eef144..e954de208 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -86,7 +86,8 @@ object DependencyGraphSettings { java.awt.Desktop.getDesktop.browse(uri) uri }, - dependencyList <<= (moduleGraph, streams).map((graph, streams) ⇒ streams.log.info(rendering.FlatList.render(graph, _.id.idString))), + dependencyList <<= printFromGraph(rendering.FlatList.render(_, _.id.idString)), + dependencyStats <<= printFromGraph(rendering.Statistics.renderModuleStatsList), dependencyDotHeader := """digraph "dependency-graph" { | graph[rankdir="LR"] | edge [ @@ -159,6 +160,9 @@ object DependencyGraphSettings { def print(key: TaskKey[String]) = (streams, key) map (_.log.info(_)) + def printFromGraph(f: ModuleGraph ⇒ String) = + (streams, moduleGraph) map ((streams, graph) ⇒ streams.log.info(f(graph))) + def showLicenseInfo(graph: ModuleGraph, streams: TaskStreams) { val output = graph.nodes.filter(_.isUsed).groupBy(_.license).toSeq.sortBy(_._1).map { diff --git a/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala b/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala index 432fb80e0..f5596269a 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala @@ -34,7 +34,13 @@ object SbtUpdateReport { def moduleEdge(chosenVersion: Option[String])(report: ModuleReport): (Module, Seq[Edge]) = { val evictedByVersion = if (report.evicted) chosenVersion else None - (Module(report.module, license = report.licenses.headOption.map(_._1), evictedByVersion = evictedByVersion, error = report.problem), + val jarFile = report.artifacts.find(_._1.`type` == "jar").orElse(report.artifacts.find(_._1.extension == "jar")).map(_._2) + (Module( + id = report.module, + license = report.licenses.headOption.map(_._1), + evictedByVersion = evictedByVersion, + jarFile = jarFile, + error = report.problem), report.callers.map(caller ⇒ Edge(caller.caller, report.module))) } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/model.scala b/src/main/scala/net/virtualvoid/sbt/graph/model.scala index e833d34ab..06c2b5bac 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/model.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/model.scala @@ -16,6 +16,8 @@ package net.virtualvoid.sbt.graph +import java.io.File + import scala.collection.mutable.{ MultiMap, HashMap, Set } case class ModuleId(organisation: String, @@ -27,6 +29,7 @@ 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 @@ -53,12 +56,15 @@ case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) { } m.toMap.mapValues(_.toSeq.sortBy(_.id.idString)).withDefaultValue(Nil) } + + def roots: Seq[Module] = + nodes.filter(n ⇒ !edges.exists(_._2 == n.id)).sortBy(_.id.idString) } import sbinary.{ Format, DefaultProtocol } object ModuleGraphProtocol extends 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] = asProduct5(Module)(Module.unapply(_).get) + implicit val ModuleFormat: Format[Module] = asProduct6(Module)(Module.unapply(_).get) implicit val ModuleGraphFormat: Format[ModuleGraph] = asProduct2(ModuleGraph.apply _)(ModuleGraph.unapply(_).get) } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala index 0843affbf..c2670e6a2 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala @@ -25,7 +25,7 @@ object AsciiTree { val deps = graph.dependencyMap // there should only be one root node (the project itself) - val roots = graph.nodes.filter(n ⇒ !graph.edges.exists(_._2 == n.id)).sortBy(_.id.idString) + val roots = graph.roots roots.map { root ⇒ AsciiTreeLayout.toAscii[Module](root, node ⇒ deps.getOrElse(node.id, Seq.empty[Module]), displayModule) }.mkString("\n") diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/Statistics.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/Statistics.scala new file mode 100644 index 000000000..5a82e922b --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/Statistics.scala @@ -0,0 +1,71 @@ +/* + * Copyright 2016 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 Statistics { + def renderModuleStatsList(graph: ModuleGraph): String = { + case class ModuleStats( + id: ModuleId, + numDirectDependencies: Int, + numTransitiveDependencies: Int, + selfSize: Option[Long], + transitiveSize: Long, + transitiveDependencyStats: Map[ModuleId, ModuleStats]) { + def transitiveStatsWithSelf: Map[ModuleId, ModuleStats] = transitiveDependencyStats + (id -> this) + } + + def statsFor(moduleId: ModuleId): ModuleStats = { + val directDependencies = graph.dependencyMap(moduleId).filterNot(_.isEvicted).map(_.id) + val dependencyStats = directDependencies.map(statsFor).flatMap(_.transitiveStatsWithSelf).toMap + val selfSize = graph.module(moduleId).jarFile.filter(_.exists).map(_.length) + val numDirectDependencies = directDependencies.size + val numTransitiveDependencies = dependencyStats.size + val transitiveSize = selfSize.getOrElse(0L) + dependencyStats.map(_._2.selfSize.getOrElse(0L)).sum + + ModuleStats(moduleId, numDirectDependencies, numTransitiveDependencies, selfSize, transitiveSize, dependencyStats) + } + + def format(stats: ModuleStats): String = { + import stats._ + def mb(bytes: Long): Double = bytes.toDouble / 1000000 + val selfSize = + stats.selfSize match { + case Some(size) ⇒ f"${mb(size)}%7.3f" + case None ⇒ "-------" + } + f"${mb(transitiveSize)}%7.3f MB $selfSize MB $numTransitiveDependencies%4d $numDirectDependencies%4d ${id.idString}%s" + } + + val allStats = + graph.roots.flatMap(r ⇒ statsFor(r.id).transitiveStatsWithSelf).toMap.values.toSeq + .sortBy(s ⇒ (-s.transitiveSize, -s.numTransitiveDependencies)) + + val header = " TotSize JarSize #TDe #Dep Module\n" + + header + + allStats.map(format).mkString("\n") + + """ + | + |Columns are + | - Jar-Size including dependencies + | - Jar-Size + | - Number of transitive dependencies + | - Number of direct dependencies + | - ModuleID""".stripMargin + } +} From 88f0699398f51e44149c7416cefc2ac301feeec3 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 8 Jan 2016 18:38:20 +0100 Subject: [PATCH 177/252] bump version to 0.8.1 --- README.md | 2 +- notes/0.8.1.markdown | 9 +++++++++ project.sbt | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 notes/0.8.1.markdown diff --git a/README.md b/README.md index af98ed9ff..1002b3e4d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ install it as a [global plugin] so that you can use it in any SBT project withou this, add the plugin dependency to `~/.sbt/0.13/plugins/plugins.sbt`: ```scala -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.0") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.1") ``` To add the plugin only to a single project, put this line into `project/plugins.sbt` of your project, instead. diff --git a/notes/0.8.1.markdown b/notes/0.8.1.markdown new file mode 100644 index 000000000..83dc422bc --- /dev/null +++ b/notes/0.8.1.markdown @@ -0,0 +1,9 @@ +This is a maintenance 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. \ No newline at end of file diff --git a/project.sbt b/project.sbt index 05275e95f..ce661fcca 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.8.1-SNAPSHOT" +version := "0.8.1" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From 9fe12b83809cb68bf958ac770db9463877d1e7de Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 8 Jan 2016 18:41:36 +0100 Subject: [PATCH 178/252] next version --- project.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.sbt b/project.sbt index ce661fcca..52a678259 100644 --- a/project.sbt +++ b/project.sbt @@ -4,7 +4,7 @@ name := "sbt-dependency-graph" organization := "net.virtual-void" -version := "0.8.1" +version := "0.8.2-SNAPSHOT" homepage := Some(url("http://github.com/jrudolph/sbt-dependency-graph")) From d6d53ff0e97fd7d3e81f011701848c1ccd8bd6ca Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sun, 10 Jan 2016 11:25:05 +0100 Subject: [PATCH 179/252] 0.8.1 notes fixes --- notes/0.8.1.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notes/0.8.1.markdown b/notes/0.8.1.markdown index 83dc422bc..21f9aaabe 100644 --- a/notes/0.8.1.markdown +++ b/notes/0.8.1.markdown @@ -1,4 +1,4 @@ -This is a maintenance fixing a regression in 0.8.0 and adding two small features. +This is a maintenance release fixing a regression in 0.8.0 and adding two small features. All changes: From b62fcec67667867856ebe92122c7e38be2023933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Derosiaux?= Date: Sun, 31 Jan 2016 18:11:32 +0100 Subject: [PATCH 180/252] Use v0.4.16 of dagre-d3 to avoid javascript error When using `dagre-d3` v0.4.10, my browser (Chrome 49) crashes an javascript error and the arrows are not displayed : ``` Uncaught TypeError: t.getTransformToElement is not a function ``` This happens in the function `getCoords` of the library. Using the latest version v0.4.16 of dagre-d3 fixes the issue. --- src/main/resources/graph.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/graph.html b/src/main/resources/graph.html index eae90cff0..67dcd6203 100644 --- a/src/main/resources/graph.html +++ b/src/main/resources/graph.html @@ -33,7 +33,7 @@ THE SOFTWARE. - + + + +

Dependencies

+Search: +
+ + + + \ No newline at end of file diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index fbc6ae440..0ca497312 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -49,6 +49,15 @@ trait DependencyGraphKeys { val dependencyBrowseGraph = TaskKey[URI]( "dependency-browse-graph", "Opens an HTML page that can be used to view the graph.") + val dependencyBrowseTreeTarget = SettingKey[File]( + "dependency-browse-tree-target", + "The location dependency browse tree files should be put.") + val dependencyBrowseTreeHTML = TaskKey[URI]( + "dependency-browse-tree-html", + "Creates an HTML page that can be used to view the dependency tree") + val dependencyBrowseTree = TaskKey[URI]( + "dependency-browse-tree", + "Opens an HTML page that can be used to view the dependency tree") val moduleGraph = TaskKey[ModuleGraph]( "module-graph", "The dependency graph for a project") @@ -97,4 +106,4 @@ trait DependencyGraphKeys { private[graph] val crossProjectId = SettingKey[ModuleID]("dependency-graph-cross-project-id") } -object DependencyGraphKeys extends DependencyGraphKeys \ No newline at end of file +object DependencyGraphKeys extends DependencyGraphKeys diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index 2924fa368..d4b6907e6 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -22,7 +22,7 @@ import sbt._ import Keys._ import sbt.complete.Parser import net.virtualvoid.sbt.graph.backend.{ IvyReport, SbtUpdateReport } -import net.virtualvoid.sbt.graph.rendering.{ AsciiGraph, DagreHTML } +import net.virtualvoid.sbt.graph.rendering.{ AsciiGraph, DagreHTML, TreeView } import net.virtualvoid.sbt.graph.util.IOUtil import internal.librarymanagement._ import librarymanagement._ @@ -74,12 +74,10 @@ object DependencyGraphSettings { 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 - }, + dependencyBrowseGraph := openBrowser(dependencyBrowseGraphHTML).value, + dependencyBrowseTreeTarget := { target.value / "browse-dependency-tree" }, + dependencyBrowseTreeHTML := browseTreeHTMLTask.value, + dependencyBrowseTree := openBrowser(dependencyBrowseTreeHTML).value, dependencyList := printFromGraph(rendering.FlatList.render(_, _.id.idString)).value, dependencyStats := printFromGraph(rendering.Statistics.renderModuleStatsList).value, dependencyDotHeader := @@ -139,6 +137,14 @@ object DependencyGraphSettings { link } + def browseTreeHTMLTask = + Def.task { + val renderedTree = TreeView.createJson(moduleGraph.value) + val link = TreeView.createLink(renderedTree, target.value) + streams.value.log.info(s"HTML tree written to $link") + link + } + def writeToFile(dataTask: TaskKey[String], fileTask: SettingKey[File]) = Def.task { val outFile = fileTask.value @@ -156,6 +162,14 @@ object DependencyGraphSettings { def printFromGraph(f: ModuleGraph ⇒ String) = Def.task { streams.value.log.info(f(moduleGraph.value)) } + def openBrowser(uriKey: TaskKey[URI]) = + Def.task { + val uri = uriKey.value + streams.value.log.info("Opening in browser...") + java.awt.Desktop.getDesktop.browse(uri) + uri + } + def showLicenseInfo(graph: ModuleGraph, streams: TaskStreams): Unit = { val output = graph.nodes.filter(_.isUsed).groupBy(_.license).toSeq.sortBy(_._1).map { diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/TreeView.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/TreeView.scala new file mode 100644 index 000000000..582202def --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/TreeView.scala @@ -0,0 +1,42 @@ +package net.virtualvoid.sbt.graph.rendering + +import java.io.File +import java.net.URI + +import net.virtualvoid.sbt.graph.util.IOUtil +import net.virtualvoid.sbt.graph.{ Module, ModuleGraph } + +import scala.util.parsing.json.{ JSONArray, JSONObject } + +object TreeView { + def createJson(graph: ModuleGraph): String = { + val trees = graph.roots + .map(module ⇒ processSubtree(graph, module)) + .toList + JSONArray(trees).toString + } + + def createLink(graphJson: String, targetDirectory: File): URI = { + targetDirectory.mkdirs() + val graphHTML = new File(targetDirectory, "tree.html") + IOUtil.saveResource("tree.html", graphHTML) + IOUtil.writeToFile(graphJson, new File(targetDirectory, "tree.json")) + IOUtil.writeToFile(s"tree_data = $graphJson;", new File(targetDirectory, "tree.data.js")) + new URI(graphHTML.toURI.toString) + } + + private def processSubtree(graph: ModuleGraph, module: Module): JSONObject = { + val children = graph.dependencyMap + .getOrElse(module.id, List()) + .map(module ⇒ processSubtree(graph, module)) + .toList + moduleAsJson(module, children) + } + + private def moduleAsJson(module: Module, children: List[JSONObject]): JSONObject = { + val eviction = module.evictedByVersion.map(version ⇒ s" (evicted by $version)").getOrElse("") + val error = module.error.map(err ⇒ s" (errors: $err)").getOrElse("") + val text = module.id.idString + eviction + error + JSONObject(Map("text" -> text, "children" -> JSONArray(children))) + } +} From 2836f83286190f8cd492b959df2a45b49ef0bb8a Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 14 Sep 2018 14:33:04 +0200 Subject: [PATCH 237/252] Add changelog entry for dependencyBrowseTree and move it a bit down in documentation --- CHANGELOG.md | 4 ++++ README.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8c81ffda..9ca4bf054 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Version 0.10.0 (unreleased) + * [#136](https://github.com/jrudolph/sbt-dependency-graph/pull/136): Added `dependencyBrowseTree` to open a searchable dependency tree in the browser. + Thanks, [@pcejrowski](https://github.com/pcejrowski) for contributing this feature. + ## Version 0.9.2 (2018-08-26) * [#159](https://github.com/jrudolph/sbt-dependency-graph/pull/159): Fixed regression in `whatDependsOn` where task parser failed when no other sbt-dependency-graph task was called before diff --git a/README.md b/README.md index 3a97598aa..b22edb2b3 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,9 @@ the notes of version [0.8.2](https://github.com/jrudolph/sbt-dependency-graph/tr ## Main Tasks - * `dependencyBrowseTree`: Opens a browser window with a visualization of the dependency tree (courtesy of jstree). * `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). + * `dependencyBrowseTree`: Opens a browser window with a visualization of the dependency tree (courtesy of jstree). * `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. The `` argument is optional. From 7992dc91f8ba5358cd87d4812f747b12ff5e7573 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 14 Sep 2018 15:00:47 +0200 Subject: [PATCH 238/252] Get rid of local updateTask copy by using `inTask` instead, fixes #148 --- .../DependencyGraphSbtCompat.scala | 66 ------------------- .../DependencyGraphSbtCompat.scala | 57 ---------------- .../sbt/graph/DependencyGraphSettings.scala | 9 ++- .../scala/sbt/dependencygraph/SbtAccess.scala | 7 +- 4 files changed, 11 insertions(+), 128 deletions(-) diff --git a/src/main/scala-sbt-0.13/sbt/dependencygraph/DependencyGraphSbtCompat.scala b/src/main/scala-sbt-0.13/sbt/dependencygraph/DependencyGraphSbtCompat.scala index 9408ed050..5aa6bacc6 100644 --- a/src/main/scala-sbt-0.13/sbt/dependencygraph/DependencyGraphSbtCompat.scala +++ b/src/main/scala-sbt-0.13/sbt/dependencygraph/DependencyGraphSbtCompat.scala @@ -3,14 +3,6 @@ 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 @@ -20,62 +12,4 @@ object DependencyGraphSbtCompat { 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) - } } diff --git a/src/main/scala-sbt-1.0/sbt/dependencygraph/DependencyGraphSbtCompat.scala b/src/main/scala-sbt-1.0/sbt/dependencygraph/DependencyGraphSbtCompat.scala index 06a466a31..ea196cb8f 100644 --- a/src/main/scala-sbt-1.0/sbt/dependencygraph/DependencyGraphSbtCompat.scala +++ b/src/main/scala-sbt-1.0/sbt/dependencygraph/DependencyGraphSbtCompat.scala @@ -1,63 +1,6 @@ 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) - } } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index d4b6907e6..0ec5cab81 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -17,7 +17,6 @@ package net.virtualvoid.sbt.graph import scala.language.reflectiveCalls - import sbt._ import Keys._ import sbt.complete.Parser @@ -26,7 +25,7 @@ import net.virtualvoid.sbt.graph.rendering.{ AsciiGraph, DagreHTML, TreeView } import net.virtualvoid.sbt.graph.util.IOUtil import internal.librarymanagement._ import librarymanagement._ -import sbt.dependencygraph.DependencyGraphSbtCompat +import sbt.dependencygraph.SbtAccess import sbt.dependencygraph.DependencyGraphSbtCompat.Implicits._ object DependencyGraphSettings { @@ -38,7 +37,11 @@ object DependencyGraphSettings { def baseSettings = Seq( ivyReportFunction := ivyReportFunctionTask.value, updateConfiguration in ignoreMissingUpdate := updateConfiguration.value.withMissingOk(true), - ignoreMissingUpdate := DependencyGraphSbtCompat.updateTask(ignoreMissingUpdate).value, + + ignoreMissingUpdate := + // inTask will make sure the new definition will pick up `updateConfiguration in ignoreMissingUpdate` + SbtAccess.inTask(ignoreMissingUpdate, Classpaths.updateTask).value, + filterScalaLibrary in Global := true) def reportSettings = diff --git a/src/main/scala/sbt/dependencygraph/SbtAccess.scala b/src/main/scala/sbt/dependencygraph/SbtAccess.scala index 558aeb1b6..d1f4e596e 100644 --- a/src/main/scala/sbt/dependencygraph/SbtAccess.scala +++ b/src/main/scala/sbt/dependencygraph/SbtAccess.scala @@ -14,13 +14,16 @@ * limitations under the License. */ -package sbt.dependencygraph +package sbt +package dependencygraph -import sbt.Defaults +import Def._ /** Accessors to private[sbt] symbols. */ object SbtAccess { val unmanagedScalaInstanceOnly = Defaults.unmanagedScalaInstanceOnly def getTerminalWidth: Int = sbt.internal.util.JLine.usingTerminal(_.getWidth) + + def inTask[T](t: Scoped, i: Initialize[T]): Initialize[T] = _root_.sbt.inTask(t, i) } From 8aa58cd8ff429096e7583b510a907b6fd76a8350 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 14 Sep 2018 16:50:23 +0200 Subject: [PATCH 239/252] For common operations introduce `asString`, `printToConsole`, and `toFile` subtasks, fixes #164 --- README.md | 21 +- .../sbt/graph/DependencyGraphKeys.scala | 4 + .../sbt/graph/DependencyGraphSettings.scala | 183 ++++++++++-------- .../sbt/graph/rendering/FlatList.scala | 2 +- .../sbt/graph/rendering/LicenseInfo.scala | 12 ++ .../toFileSubTask/build.sbt | 26 +++ .../toFileSubTask/expected/licenses.txt | 9 + .../toFileSubTask/expected/list.txt | 4 + .../toFileSubTask/expected/stats.txt | 12 ++ .../toFileSubTask/expected/tree.txt | 6 + .../toFileSubTask/project/plugins.sbt | 1 + .../sbt-dependency-graph/toFileSubTask/test | 5 + 12 files changed, 200 insertions(+), 85 deletions(-) create mode 100644 src/main/scala/net/virtualvoid/sbt/graph/rendering/LicenseInfo.scala create mode 100644 src/sbt-test/sbt-dependency-graph/toFileSubTask/build.sbt create mode 100644 src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/licenses.txt create mode 100644 src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/list.txt create mode 100644 src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/stats.txt create mode 100644 src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/tree.txt create mode 100644 src/sbt-test/sbt-dependency-graph/toFileSubTask/project/plugins.sbt create mode 100644 src/sbt-test/sbt-dependency-graph/toFileSubTask/test diff --git a/README.md b/README.md index b22edb2b3..e0e6e1cbf 100644 --- a/README.md +++ b/README.md @@ -37,11 +37,30 @@ the notes of version [0.8.2](https://github.com/jrudolph/sbt-dependency-graph/tr * `ivyReport`: Lets ivy generate the resolution report for you project. Use `show ivyReport` for the filename of the generated report +The following tasks also support the `toFile` subtask to save the contents to a file: + + * `dependencyTree` + * `dependencyList` + * `dependencyStats` + * `dependencyLicenseInfo` + +The `toFile` subtask has the following syntax: + +``` +:::toFile [-f|--force] +``` + +Use `-f` to force overwriting an existing file. + +E.g. `test:dependencyStats::toFile target/depstats.txt` will write the output of the `dependencyStats` in the `test` +configuration to the file `target/depstats.txt` but would not overwrite an existing file. + 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 "`. +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 "`. ## Configuration settings diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index 0ca497312..3bb4eab43 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -19,6 +19,10 @@ package net.virtualvoid.sbt.graph import sbt._ trait DependencyGraphKeys { + val asString = TaskKey[String]("asString", "Provides the string value for the task it is scoped for") + val printToConsole = TaskKey[Unit]("printToConsole", "Prints the tasks value to the console") + val toFile = InputKey[File]("toFile", "Writes the task value to the given file") + val dependencyGraphMLFile = SettingKey[File]( "dependency-graph-ml-file", "The location the graphml file should be generated at") diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index 0ec5cab81..2ea3b3cce 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -27,6 +27,7 @@ import internal.librarymanagement._ import librarymanagement._ import sbt.dependencygraph.SbtAccess import sbt.dependencygraph.DependencyGraphSbtCompat.Implicits._ +import sbt.complete.Parsers object DependencyGraphSettings { import DependencyGraphKeys._ @@ -47,70 +48,95 @@ object DependencyGraphSettings { def reportSettings = Seq(Compile, Test, IntegrationTest, Runtime, Provided, Optional).flatMap(ivyReportForConfig) - def ivyReportForConfig(config: Configuration) = inConfig(config)(Seq( - 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 := { - // FIXME: remove busywork - val scalaVersion = Keys.scalaVersion.value - val moduleGraph = DependencyGraphKeys.moduleGraph.value + val renderingAlternatives: Seq[(TaskKey[Unit], ModuleGraph ⇒ String)] = + Seq( + dependencyTree -> rendering.AsciiTree.asciiTree _, + dependencyList -> rendering.FlatList.render(_.id.idString), + dependencyStats -> rendering.Statistics.renderModuleStatsList _, + licenseInfo -> rendering.LicenseInfo.render _) - if (filterScalaLibrary.value) GraphTransformations.ignoreScalaLibrary(scalaVersion, moduleGraph) - else moduleGraph - }, - 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 := openBrowser(dependencyBrowseGraphHTML).value, - dependencyBrowseTreeTarget := { target.value / "browse-dependency-tree" }, - dependencyBrowseTreeHTML := browseTreeHTMLTask.value, - dependencyBrowseTree := openBrowser(dependencyBrowseTreeHTML).value, - dependencyList := printFromGraph(rendering.FlatList.render(_, _.id.idString)).value, - dependencyStats := printFromGraph(rendering.Statistics.renderModuleStatsList).value, - dependencyDotHeader := - """|digraph "dependency-graph" { + def ivyReportForConfig(config: Configuration) = inConfig(config)( + Seq( + 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 := { + // FIXME: remove busywork + val scalaVersion = Keys.scalaVersion.value + val moduleGraph = DependencyGraphKeys.moduleGraph.value + + if (filterScalaLibrary.value) GraphTransformations.ignoreScalaLibrary(scalaVersion, moduleGraph) + else moduleGraph + }, + moduleGraphStore := (moduleGraph storeAs moduleGraphStore triggeredBy moduleGraph).value, + + // browse + dependencyBrowseGraphTarget := { target.value / "browse-dependency-graph" }, + dependencyBrowseGraphHTML := browseGraphHTMLTask.value, + dependencyBrowseGraph := openBrowser(dependencyBrowseGraphHTML).value, + + dependencyBrowseTreeTarget := { target.value / "browse-dependency-tree" }, + dependencyBrowseTreeHTML := browseTreeHTMLTask.value, + dependencyBrowseTree := openBrowser(dependencyBrowseTreeHTML).value, + + // dot support + 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, + dependencyDotHeader := + """|digraph "dependency-graph" { | graph[rankdir="LR"] | edge [ | arrowtail="none" | ]""".stripMargin, - dependencyDotNodeLabel := { (organisation: String, name: String, version: String) ⇒ - """%s
%s
%s""".format(organisation, name, version) - }, - 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) - } - val output = - modules - .map { module ⇒ - rendering.AsciiTree.asciiTree(GraphTransformations.reverseGraphStartingAt(graph, module)) - } - .mkString("\n") + dependencyDotNodeLabel := { (organisation: String, name: String, version: String) ⇒ + """%s
%s
%s""".format(organisation, name, version) + }, - streams.value.log.info(output) - output - }, - licenseInfo := showLicenseInfo(moduleGraph.value, streams.value)) ++ AsciiGraph.asciiGraphSetttings) + // GraphML support + dependencyGraphMLFile := { target.value / "dependencies-%s.graphml".format(config.toString) }, + dependencyGraphML := dependencyGraphMLTask.value, + + 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) + } + val output = + modules + .map { module ⇒ + rendering.AsciiTree.asciiTree(GraphTransformations.reverseGraphStartingAt(graph, module)) + } + .mkString("\n") + + streams.value.log.info(output) + output + }, + // deprecated settings + asciiTree := (asString in dependencyTree).value) ++ + renderingAlternatives.flatMap((renderingTaskSettings _).tupled) ++ + AsciiGraph.asciiGraphSetttings) + + def renderingTaskSettings(key: TaskKey[Unit], renderer: ModuleGraph ⇒ String): Seq[Setting[_]] = + Seq( + asString in key := renderer(moduleGraph.value), + printToConsole in key := streams.value.log.info((asString in key).value), + toFile in key := { + val (targetFile, force) = targetFileAndForceParser.parsed + writeToFile(key.key.label, (asString in key).value, targetFile, force, streams.value) + }, + key := (printToConsole in key).value) def ivyReportFunctionTask = Def.task { val ivyConfig = Keys.ivyConfiguration.value.asInstanceOf[InlineIvyConfiguration] @@ -157,14 +183,18 @@ object DependencyGraphSettings { outFile } + def writeToFile(what: String, data: String, targetFile: File, force: Boolean, streams: TaskStreams): File = + if (targetFile.exists && !force) + throw new RuntimeException(s"Target file for $what already exists at ${targetFile.getAbsolutePath}. Use '-f' to override") + else { + IOUtil.writeToFile(data, targetFile) + + streams.log.info(s"Wrote $what to '$targetFile'") + targetFile + } + def absoluteReportPath = (file: File) ⇒ file.getAbsolutePath - def print(key: TaskKey[String]) = - Def.task { streams.value.log.info(key.value) } - - def printFromGraph(f: ModuleGraph ⇒ String) = - Def.task { streams.value.log.info(f(moduleGraph.value)) } - def openBrowser(uriKey: TaskKey[URI]) = Def.task { val uri = uriKey.value @@ -173,33 +203,16 @@ object DependencyGraphSettings { uri } - def showLicenseInfo(graph: ModuleGraph, streams: TaskStreams): Unit = { - val output = - graph.nodes.filter(_.isUsed).groupBy(_.license).toSeq.sortBy(_._1).map { - case (license, modules) ⇒ - license.getOrElse("No license specified") + "\n" + - modules.map(_.id.idString formatted "\t %s").mkString("\n") - }.mkString("\n\n") - streams.log.info(output) - } - - import Project._ - val shouldForceParser: State ⇒ Parser[Boolean] = { (state: State) ⇒ - import sbt.complete.DefaultParsers._ - - (Space ~> token("--force")).?.map(_.isDefined) - } - case class ArtifactPattern( organisation: String, name: String, version: Option[String]) + import sbt.complete.DefaultParsers._ 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)) @@ -222,6 +235,10 @@ object DependencyGraphSettings { } } } + val shouldForceParser: Parser[Boolean] = (Space ~> (Parser.literal("-f") | "--force")).?.map(_.isDefined) + + val targetFileAndForceParser: Parser[(File, Boolean)] = + Parsers.fileParser(new File(".")) ~ shouldForceParser // This is to support 0.13.8's InlineConfigurationWithExcludes while not forcing 0.13.8 type HasModule = { @@ -230,7 +247,7 @@ object DependencyGraphSettings { def crossName(ivyModule: IvySbt#Module) = ivyModule.moduleSettings match { case ic: InlineConfiguration ⇒ ic.module.name - case hm: HasModule if hm.getClass.getName == "sbt.InlineConfigurationWithExcludes" ⇒ hm.module.name + case hm: HasModule @unchecked if hm.getClass.getName == "sbt.InlineConfigurationWithExcludes" ⇒ hm.module.name case _ ⇒ throw new IllegalStateException("sbt-dependency-graph plugin currently only supports InlineConfiguration of ivy settings (the default in sbt)") } diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/FlatList.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/FlatList.scala index eb26cff87..95f0676d6 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/rendering/FlatList.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/FlatList.scala @@ -18,7 +18,7 @@ package net.virtualvoid.sbt.graph package rendering object FlatList { - def render(graph: ModuleGraph, display: Module ⇒ String): String = + def render(display: Module ⇒ String)(graph: ModuleGraph): String = graph.modules.values.toSeq .distinct .filterNot(_.isEvicted) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/rendering/LicenseInfo.scala b/src/main/scala/net/virtualvoid/sbt/graph/rendering/LicenseInfo.scala new file mode 100644 index 000000000..cb97d3f0e --- /dev/null +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/LicenseInfo.scala @@ -0,0 +1,12 @@ +package net.virtualvoid.sbt.graph.rendering + +import net.virtualvoid.sbt.graph.ModuleGraph + +object LicenseInfo { + def render(graph: ModuleGraph): String = + graph.nodes.filter(_.isUsed).groupBy(_.license).toSeq.sortBy(_._1).map { + case (license, modules) ⇒ + license.getOrElse("No license specified") + "\n" + + modules.map(_.id.idString formatted "\t %s").mkString("\n") + }.mkString("\n\n") +} diff --git a/src/sbt-test/sbt-dependency-graph/toFileSubTask/build.sbt b/src/sbt-test/sbt-dependency-graph/toFileSubTask/build.sbt new file mode 100644 index 000000000..d34ee89e9 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/toFileSubTask/build.sbt @@ -0,0 +1,26 @@ +scalaVersion := "2.12.6" + +organization := "org.example" + +name := "blubber" + +version := "0.1" + +libraryDependencies ++= Seq( + "com.codahale" % "jerkson_2.9.1" % "0.5.0" +) + +TaskKey[Unit]("check") := { + val candidates = "tree list stats licenses".split(' ').map(_.trim) + candidates.foreach { c => + val expected = new File(s"expected/$c.txt") + val actual = new File(s"target/$c.txt") + + import sys.process._ + val exit = s"diff -U3 ${expected.getPath} ${actual.getPath}".! + require(exit == 0, s"Diff was non-zero for ${actual.getName}") + } + + //require(sanitize(graph) == sanitize(expectedGraph), "Graph for report %s was '\n%s' but should have been '\n%s'" format (report, sanitize(graph), sanitize(expectedGraph))) + () +} diff --git a/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/licenses.txt b/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/licenses.txt new file mode 100644 index 000000000..826ed0153 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/licenses.txt @@ -0,0 +1,9 @@ +No license specified + org.example:blubber_2.12:0.1 + +The Apache Software License, Version 2.0 + org.codehaus.jackson:jackson-mapper-asl:1.9.11 + org.codehaus.jackson:jackson-core-asl:1.9.11 + +The MIT License + com.codahale:jerkson_2.9.1:0.5.0 \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/list.txt b/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/list.txt new file mode 100644 index 000000000..4bf401868 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/list.txt @@ -0,0 +1,4 @@ +com.codahale:jerkson_2.9.1:0.5.0 +org.codehaus.jackson:jackson-core-asl:1.9.11 +org.codehaus.jackson:jackson-mapper-asl:1.9.11 +org.example:blubber_2.12:0.1 \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/stats.txt b/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/stats.txt new file mode 100644 index 000000000..6a76e3522 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/stats.txt @@ -0,0 +1,12 @@ + TotSize JarSize #TDe #Dep Module + 1.754 MB ------- MB 3 1 org.example:blubber_2.12:0.1 + 1.754 MB 0.741 MB 2 2 com.codahale:jerkson_2.9.1:0.5.0 + 1.013 MB 0.780 MB 1 1 org.codehaus.jackson:jackson-mapper-asl:1.9.11 + 0.232 MB 0.232 MB 0 0 org.codehaus.jackson:jackson-core-asl:1.9.11 + +Columns are + - Jar-Size including dependencies + - Jar-Size + - Number of transitive dependencies + - Number of direct dependencies + - ModuleID \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/tree.txt b/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/tree.txt new file mode 100644 index 000000000..5b1f1aa5e --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/tree.txt @@ -0,0 +1,6 @@ +org.example:blubber_2.12:0.1 [S] + +-com.codahale:jerkson_2.9.1:0.5.0 [S] + +-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 + \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/toFileSubTask/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/toFileSubTask/project/plugins.sbt new file mode 100644 index 000000000..6fdebb6d6 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/toFileSubTask/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/toFileSubTask/test b/src/sbt-test/sbt-dependency-graph/toFileSubTask/test new file mode 100644 index 000000000..83d872e3e --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/toFileSubTask/test @@ -0,0 +1,5 @@ +> dependencyTree::toFile target/tree.txt +> dependencyList::toFile target/list.txt +> dependencyStats::toFile target/stats.txt +> dependencyLicenseInfo::toFile target/licenses.txt +> check From c117be2091e7f9f98112b5486e77ad15ae61c6dd Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Sat, 15 Sep 2018 15:04:12 +0200 Subject: [PATCH 240/252] Rename our own update task to something else so we don't conflict with other task scopes --- .../scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala index 3bb4eab43..2abdd156d 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala @@ -95,7 +95,6 @@ trait DependencyGraphKeys { 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", "Specifies if scala dependency should be filtered in dependency-* output") @@ -105,6 +104,7 @@ trait DependencyGraphKeys { "Aggregates and shows information about the licenses of dependencies") // internal + private[graph] val ignoreMissingUpdate = TaskKey[UpdateReport]("dependencyUpdate", "sbt-dependency-graph version of update") private[graph] val moduleGraphStore = TaskKey[ModuleGraph]("module-graph-store", "The stored module-graph from the last run") 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") From f9aeec3a5e53b6f4540539479a7d90f51b99494c Mon Sep 17 00:00:00 2001 From: Sean Sullivan Date: Mon, 17 Dec 2018 17:03:17 -0800 Subject: [PATCH 241/252] sbt 1.2.7 --- build.sbt | 4 ++-- project/build.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.sbt b/build.sbt index c3224dbb3..27799adea 100644 --- a/build.sbt +++ b/build.sbt @@ -18,7 +18,7 @@ libraryDependencies += Defaults.sbtPluginExtra( (scalaBinaryVersion in update).value ) -crossSbtVersions := Seq("1.2.1", "0.13.16") +crossSbtVersions := Seq("1.2.7", "0.13.18") scalacOptions ++= Seq( "-deprecation", @@ -27,4 +27,4 @@ scalacOptions ++= Seq( "-unchecked" ) -ScalariformSupport.formatSettings \ No newline at end of file +ScalariformSupport.formatSettings diff --git a/project/build.properties b/project/build.properties index 5620cc502..72f902892 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.2.1 +sbt.version=1.2.7 From a093b91433dbdedfd02827e897cf1f856d16b948 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 17 May 2019 21:51:09 +0200 Subject: [PATCH 242/252] Revert to old README until new version has been released --- README.md | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/README.md b/README.md index e0e6e1cbf..255a12b38 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,6 @@ 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). - * `dependencyBrowseTree`: Opens a browser window with a visualization of the dependency tree (courtesy of jstree). * `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. The `` argument is optional. @@ -37,30 +36,11 @@ the notes of version [0.8.2](https://github.com/jrudolph/sbt-dependency-graph/tr * `ivyReport`: Lets ivy generate the resolution report for you project. Use `show ivyReport` for the filename of the generated report -The following tasks also support the `toFile` subtask to save the contents to a file: - - * `dependencyTree` - * `dependencyList` - * `dependencyStats` - * `dependencyLicenseInfo` - -The `toFile` subtask has the following syntax: - -``` -:::toFile [-f|--force] -``` - -Use `-f` to force overwriting an existing file. - -E.g. `test:dependencyStats::toFile target/depstats.txt` will write the output of the `dependencyStats` in the `test` -configuration to the file `target/depstats.txt` but would not overwrite an existing file. - 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 "`. +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 "`. ## Configuration settings From 39609b0d3ec57ac2689832616378e0f27c35eb40 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 17 May 2019 22:04:03 +0200 Subject: [PATCH 243/252] Add note that sbt 1.3.x is currently unsupported --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 255a12b38..ffa546cfb 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ Visualize your project's dependencies. +**Note: sbt 1.3.x is currently not supported because by default sbt 1.3.x. [replaced Ivy with coursier](https://www.lightbend.com/blog/sbt-1.3.0-release). For the time being, if you want to use sbt-dependency-graph, either stay on sbt 1.2.x, or disable coursier (`ThisBuild / useCoursier := false`). Please also consider helping out implementing support for coursier in this plugin (see [#178](https://github.com/jrudolph/sbt-dependency-graph/issues/178)).** + ## Usage Instructions sbt-dependency-graph is an informational tool rather than one that changes your build, so you will more than likely wish to From 6e8ab672196695eb3be0ae47353ddfe2009bc228 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Fri, 17 May 2019 22:10:37 +0200 Subject: [PATCH 244/252] Adapt README again because reason given was probably wrong It seems the problem might already be fixed in master. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ffa546cfb..62f5c06c7 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Visualize your project's dependencies. -**Note: sbt 1.3.x is currently not supported because by default sbt 1.3.x. [replaced Ivy with coursier](https://www.lightbend.com/blog/sbt-1.3.0-release). For the time being, if you want to use sbt-dependency-graph, either stay on sbt 1.2.x, or disable coursier (`ThisBuild / useCoursier := false`). Please also consider helping out implementing support for coursier in this plugin (see [#178](https://github.com/jrudolph/sbt-dependency-graph/issues/178)).** +**Note: sbt 1.3.x is currently not supported (but hopefully fixed soon), see [#178](https://github.com/jrudolph/sbt-dependency-graph/issues/178)).** ## Usage Instructions From b4eae629a67addede3c3bdfd33a0c4fe95a3247f Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Jul 2019 08:18:01 +0200 Subject: [PATCH 245/252] Releasing 0.10.0-RC1 --- CHANGELOG.md | 5 ++++- README.md | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ca4bf054..bcd87ebbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ # Changelog -## Version 0.10.0 (unreleased) +## Version 0.10.0-RC1 (2019-07-24) * [#136](https://github.com/jrudolph/sbt-dependency-graph/pull/136): Added `dependencyBrowseTree` to open a searchable dependency tree in the browser. Thanks, [@pcejrowski](https://github.com/pcejrowski) for contributing this feature. + * [#163](https://github.com/jrudolph/sbt-dependency-graph/pull/163): Remove some usage of internal sbt APIs, this allows to run sbt-dependency-graph with sbt 1.3.0 + but results are not entirely correct. + * [#165](https://github.com/jrudolph/sbt-dependency-graph/pull/165): For common operations introduce `asString`, `printToConsole`, and `toFile` subtasks ## Version 0.9.2 (2018-08-26) * [#159](https://github.com/jrudolph/sbt-dependency-graph/pull/159): Fixed regression in `whatDependsOn` where task parser failed when no other sbt-dependency-graph task was called before diff --git a/README.md b/README.md index 62f5c06c7..e9a0b1cc4 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ install it as a [global plugin] so that you can use it in any SBT project withou 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.9.2") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.10.0-RC1") ``` To add the plugin only to a single project, put this line into `project/plugins.sbt` of your project, instead. From d2dd796fd70ef3fa2f15d4f18ad89f31fcfa7d88 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Wed, 24 Jul 2019 08:21:05 +0200 Subject: [PATCH 246/252] Reinstate documentation for new features This reverts commit a093b91433dbdedfd02827e897cf1f856d16b948. --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e9a0b1cc4..f16d2c211 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ 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). + * `dependencyBrowseTree`: Opens a browser window with a visualization of the dependency tree (courtesy of jstree). * `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. The `` argument is optional. @@ -38,11 +39,30 @@ the notes of version [0.8.2](https://github.com/jrudolph/sbt-dependency-graph/tr * `ivyReport`: Lets ivy generate the resolution report for you project. Use `show ivyReport` for the filename of the generated report +The following tasks also support the `toFile` subtask to save the contents to a file: + + * `dependencyTree` + * `dependencyList` + * `dependencyStats` + * `dependencyLicenseInfo` + +The `toFile` subtask has the following syntax: + +``` +:::toFile [-f|--force] +``` + +Use `-f` to force overwriting an existing file. + +E.g. `test:dependencyStats::toFile target/depstats.txt` will write the output of the `dependencyStats` in the `test` +configuration to the file `target/depstats.txt` but would not overwrite an existing file. + 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 "`. +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 "`. ## Configuration settings From 17d25ccc44547c1466b98a73a169ee9bf597b370 Mon Sep 17 00:00:00 2001 From: Brice Jaglin Date: Sat, 7 Sep 2019 14:03:56 +0200 Subject: [PATCH 247/252] Disable cached resolution for ignoreMissingUpdate (#184) Before 7992dc9, a custom, non-cached-resolution-aware update task was used to generate the report that the tree is based on, effectively ignoring the cached resolution flag at the project level. Starting 7992dc9, this plugin, when run with sbt 0.13.8 or sbt 1.2.5+, relies on cached-resolution-backed reports for projects that have the engine enabled via `updateOptions`. Other 1.x releases are not directly impacted as sbt had a buggy implementation of the feature anyway, see https://github.com/sbt/sbt/issues/3761. Cached resolution has the side effect of generating an ivy report with artificial module descriptors which makes it hard to reconstruct the tree without inlining sbt internals (see below), so this effectively ignores it *for the purpose of the tree generation*, even if the project enabled it for the regular report. ModuleId( org.scala-sbt.temp, temp-resolve-e2a956132f02c038285b41b374c02f5838076f37, 1.0 ) https://github.com/sbt/librarymanagement/blob/984de6f/ivy/src/main/scala/sbt/internal/librarymanagement/ivyint/CachedResolutionResolveEngine.scala#L137 --- .travis.yml | 3 ++- CHANGELOG.md | 4 ++++ .../sbt/graph/DependencyGraphSettings.scala | 19 ++++++++++++++++++- .../cachedResolution/build.sbt | 17 +++++++++++++++++ .../cachedResolution/project/plugins.sbt | 1 + .../cachedResolution/test | 1 + 6 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 src/sbt-test/sbt-dependency-graph/cachedResolution/build.sbt create mode 100644 src/sbt-test/sbt-dependency-graph/cachedResolution/project/plugins.sbt create mode 100644 src/sbt-test/sbt-dependency-graph/cachedResolution/test diff --git a/.travis.yml b/.travis.yml index 6190c81fb..5a335d2aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ sudo: false language: scala jdk: oraclejdk8 +dist: trusty script: - sbt ";^test ;^scripted" @@ -12,4 +13,4 @@ before_cache: cache: directories: - $HOME/.ivy2/cache - - $HOME/.sbt \ No newline at end of file + - $HOME/.sbt diff --git a/CHANGELOG.md b/CHANGELOG.md index bcd87ebbd..02eb5e41b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased + * [#184](https://github.com/jrudolph/sbt-dependency-graph/pull/184): Fix regression in 0.10.0-RC1 for recent sbt versions when + `cachedResolution` (with coursier turned off). Thanks [@bjaglin](https://github.com/bjaglin) for the report and the fix. + ## Version 0.10.0-RC1 (2019-07-24) * [#136](https://github.com/jrudolph/sbt-dependency-graph/pull/136): Added `dependencyBrowseTree` to open a searchable dependency tree in the browser. Thanks, [@pcejrowski](https://github.com/pcejrowski) for contributing this feature. diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index 2ea3b3cce..bec65daf6 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -37,10 +37,27 @@ object DependencyGraphSettings { def baseSettings = Seq( ivyReportFunction := ivyReportFunctionTask.value, + + // disable the cached resolution engine (exposing a scoped `ivyModule` used directly by `updateTask`), as it + // generates artificial module descriptors which are internal to sbt, making it hard to reconstruct the + // dependency tree + updateOptions in ignoreMissingUpdate := updateOptions.value.withCachedResolution(false), + ivyConfiguration in ignoreMissingUpdate := + // inTask will make sure the new definition will pick up `updateOptions in ignoreMissingUpdate` + SbtAccess.inTask(ignoreMissingUpdate, Classpaths.mkIvyConfiguration).value, + ivyModule in ignoreMissingUpdate := { + // concatenating & inlining ivySbt & ivyModule default task implementations, as `SbtAccess.inTask` does + // NOT correctly force the scope when applied to `TaskKey.toTask` instances (as opposed to raw + // implementations like `Classpaths.mkIvyConfiguration` or `Classpaths.updateTask`) + val is = new IvySbt((ivyConfiguration in ignoreMissingUpdate).value) + new is.Module(moduleSettings.value) + }, + + // don't fail on missing dependencies updateConfiguration in ignoreMissingUpdate := updateConfiguration.value.withMissingOk(true), ignoreMissingUpdate := - // inTask will make sure the new definition will pick up `updateConfiguration in ignoreMissingUpdate` + // inTask will make sure the new definition will pick up `ivyModule/updateConfiguration in ignoreMissingUpdate` SbtAccess.inTask(ignoreMissingUpdate, Classpaths.updateTask).value, filterScalaLibrary in Global := true) diff --git a/src/sbt-test/sbt-dependency-graph/cachedResolution/build.sbt b/src/sbt-test/sbt-dependency-graph/cachedResolution/build.sbt new file mode 100644 index 000000000..e9aef9b55 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/cachedResolution/build.sbt @@ -0,0 +1,17 @@ +scalaVersion := "2.12.9" + +libraryDependencies += "org.slf4j" % "slf4j-api" % "1.7.28" +updateOptions := updateOptions.value.withCachedResolution(true) + +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:cachedresolution_2.12:0.1.0-SNAPSHOT + | +-org.slf4j:slf4j-api:1.7.28 + | """.stripMargin + require(sanitize(graph) == sanitize(expectedGraph), "Graph for report %s was '\n%s' but should have been '\n%s'" format (report, sanitize(graph), sanitize(expectedGraph))) + () +} diff --git a/src/sbt-test/sbt-dependency-graph/cachedResolution/project/plugins.sbt b/src/sbt-test/sbt-dependency-graph/cachedResolution/project/plugins.sbt new file mode 100644 index 000000000..6fdebb6d6 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/cachedResolution/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/cachedResolution/test b/src/sbt-test/sbt-dependency-graph/cachedResolution/test new file mode 100644 index 000000000..a5912a391 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/cachedResolution/test @@ -0,0 +1 @@ +> check \ No newline at end of file From 221e5fb7a1cf07ec4d457318da10c566f24ef235 Mon Sep 17 00:00:00 2001 From: Johannes Rudolph Date: Mon, 21 Oct 2019 11:07:04 +0200 Subject: [PATCH 248/252] Expand note and ask for help from users --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f16d2c211..b92e8eb76 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Visualize your project's dependencies. -**Note: sbt 1.3.x is currently not supported (but hopefully fixed soon), see [#178](https://github.com/jrudolph/sbt-dependency-graph/issues/178)).** +**Note: sbt >= 1.3.x is currently not supported (but hopefully fixed soon), see [#178](https://github.com/jrudolph/sbt-dependency-graph/issues/178)). Unfortunately, this problem cannot be fixed in sbt-dependency-graph itself but is a regression in sbt. If you'd like to continue using sbt-dependency-graph, please add your support to [sbt/sbt#4706](https://github.com/sbt/sbt/issues/4706) and [sbt/sbt#4707](https://github.com/sbt/sbt/issues/4707).** ## Usage Instructions From ad3acd86f49e059e99a08c4b4ce5d5fe25744c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20Mass=C3=A9?= Date: Mon, 13 Jul 2020 15:27:05 -0400 Subject: [PATCH 249/252] Optimize the screen space for dependencyBrowseGraph --- src/main/resources/graph.html | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/main/resources/graph.html b/src/main/resources/graph.html index 44b37eb8c..4ea8baba6 100644 --- a/src/main/resources/graph.html +++ b/src/main/resources/graph.html @@ -37,11 +37,10 @@ THE SOFTWARE. - - - - - - - - - - - diff --git a/sbt-dependency-graph/src/main/resources/tree.html b/sbt-dependency-graph/src/main/resources/tree.html deleted file mode 100644 index 909a9b82e..000000000 --- a/sbt-dependency-graph/src/main/resources/tree.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - dependencyBrowseTree - - - - - - - - - - - -

Dependencies

-Search: -
- - - - \ No newline at end of file diff --git a/sbt-dependency-graph/src/main/scala-sbt-0.13/net/virtualvoid/sbt/graph/ModuleGraphProtocolCompat.scala b/sbt-dependency-graph/src/main/scala-sbt-0.13/net/virtualvoid/sbt/graph/ModuleGraphProtocolCompat.scala deleted file mode 100644 index d28f20d8b..000000000 --- a/sbt-dependency-graph/src/main/scala-sbt-0.13/net/virtualvoid/sbt/graph/ModuleGraphProtocolCompat.scala +++ /dev/null @@ -1,3 +0,0 @@ -package net.virtualvoid.sbt.graph - -trait ModuleGraphProtocolCompat diff --git a/sbt-dependency-graph/src/main/scala-sbt-0.13/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala b/sbt-dependency-graph/src/main/scala-sbt-0.13/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala deleted file mode 100644 index f1c83ec18..000000000 --- a/sbt-dependency-graph/src/main/scala-sbt-0.13/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2015 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 - -import com.github.mdr.ascii.layout._ -import net.virtualvoid.sbt.graph.DependencyGraphKeys._ -import sbt.Keys._ - -object AsciiGraph { - def asciiGraph(graph: ModuleGraph): String = - Layouter.renderGraph(buildAsciiGraph(graph)) - - private def buildAsciiGraph(moduleGraph: ModuleGraph): Graph[String] = { - def renderVertex(module: Module): String = - module.id.name + module.extraInfo + "\n" + - module.id.organisation + "\n" + - module.id.version + - module.error.map("\nerror: " + _).getOrElse("") + - module.evictedByVersion.map(_ formatted "\nevicted by: %s").getOrElse("") - - val vertices = moduleGraph.nodes.map(renderVertex).toList - 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.") - } - }) -} diff --git a/sbt-dependency-graph/src/main/scala-sbt-0.13/sbt/dependencygraph/DependencyGraphSbtCompat.scala b/sbt-dependency-graph/src/main/scala-sbt-0.13/sbt/dependencygraph/DependencyGraphSbtCompat.scala deleted file mode 100644 index 5aa6bacc6..000000000 --- a/sbt-dependency-graph/src/main/scala-sbt-0.13/sbt/dependencygraph/DependencyGraphSbtCompat.scala +++ /dev/null @@ -1,15 +0,0 @@ -package sbt -package dependencygraph - -import scala.language.implicitConversions - -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) - } - } -} diff --git a/sbt-dependency-graph/src/main/scala-sbt-1.0/net/virtualvoid/sbt/graph/ModuleGraphProtocolCompat.scala b/sbt-dependency-graph/src/main/scala-sbt-1.0/net/virtualvoid/sbt/graph/ModuleGraphProtocolCompat.scala deleted file mode 100644 index 1fb08ccc7..000000000 --- a/sbt-dependency-graph/src/main/scala-sbt-1.0/net/virtualvoid/sbt/graph/ModuleGraphProtocolCompat.scala +++ /dev/null @@ -1,25 +0,0 @@ -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)) - } - } -} diff --git a/sbt-dependency-graph/src/main/scala-sbt-1.0/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala b/sbt-dependency-graph/src/main/scala-sbt-1.0/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala deleted file mode 100644 index b9e187a3b..000000000 --- a/sbt-dependency-graph/src/main/scala-sbt-1.0/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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[_]] -} \ No newline at end of file diff --git a/sbt-dependency-graph/src/main/scala-sbt-1.0/sbt/dependencygraph/DependencyGraphSbtCompat.scala b/sbt-dependency-graph/src/main/scala-sbt-1.0/sbt/dependencygraph/DependencyGraphSbtCompat.scala deleted file mode 100644 index ea196cb8f..000000000 --- a/sbt-dependency-graph/src/main/scala-sbt-1.0/sbt/dependencygraph/DependencyGraphSbtCompat.scala +++ /dev/null @@ -1,6 +0,0 @@ -package sbt -package dependencygraph - -object DependencyGraphSbtCompat { - object Implicits -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala deleted file mode 100644 index 2abdd156d..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphKeys.scala +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2014 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 - -import sbt._ - -trait DependencyGraphKeys { - val asString = TaskKey[String]("asString", "Provides the string value for the task it is scoped for") - val printToConsole = TaskKey[Unit]("printToConsole", "Prints the tasks value to the console") - val toFile = InputKey[File]("toFile", "Writes the task value to the given 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", - "Creates a graphml file containing the dependency-graph for a project") - 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", - "Returns a formated string of a dependency. Takes organisation, name and version as parameters") - 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", - "Creates a dot file containing the dependency-graph for a project") - 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", - "The location dependency browse graph files should be put.") - 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", - "Opens an HTML page that can be used to view the graph.") - val dependencyBrowseTreeTarget = SettingKey[File]( - "dependency-browse-tree-target", - "The location dependency browse tree files should be put.") - val dependencyBrowseTreeHTML = TaskKey[URI]( - "dependency-browse-tree-html", - "Creates an HTML page that can be used to view the dependency tree") - val dependencyBrowseTree = TaskKey[URI]( - "dependency-browse-tree", - "Opens an HTML page that can be used to view the dependency tree") - val moduleGraph = TaskKey[ModuleGraph]( - "module-graph", - "The dependency graph for a project") - 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", - "The dependency graph for a project as generated from SBT data structures.") - 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", - "Prints the ascii graph to the console") - 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", - "Prints an ascii tree of all the dependencies to the console") - val dependencyList = TaskKey[Unit]( - "dependency-list", - "Prints a list of all dependencies to the console") - val dependencyStats = TaskKey[Unit]( - "dependency-stats", - "Prints statistics for all dependencies to the console") - 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", - "A task which returns the location of the ivy report file for a given configuration (default `compile`).") - val filterScalaLibrary = SettingKey[Boolean]( - "filter-scala-library", - "Specifies if scala dependency should be filtered in dependency-* output") - - val licenseInfo = TaskKey[Unit]( - "dependency-license-info", - "Aggregates and shows information about the licenses of dependencies") - - // internal - private[graph] val ignoreMissingUpdate = TaskKey[UpdateReport]("dependencyUpdate", "sbt-dependency-graph version of update") - private[graph] val moduleGraphStore = TaskKey[ModuleGraph]("module-graph-store", "The stored module-graph from the last run") - 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") -} - -object DependencyGraphKeys extends DependencyGraphKeys diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphPlugin.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphPlugin.scala deleted file mode 100755 index 31f36d729..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphPlugin.scala +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2011, 2012 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 - -import sbt._ -import Keys._ - -object DependencyGraphPlugin extends AutoPlugin { - object autoImport extends DependencyGraphKeys - - override def projectSettings: Seq[Def.Setting[_]] = DependencyGraphSettings.graphSettings - - override def trigger: PluginTrigger = AllRequirements -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala deleted file mode 100644 index bec65daf6..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright 2015 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 - -import scala.language.reflectiveCalls -import sbt._ -import Keys._ -import sbt.complete.Parser -import net.virtualvoid.sbt.graph.backend.{ IvyReport, SbtUpdateReport } -import net.virtualvoid.sbt.graph.rendering.{ AsciiGraph, DagreHTML, TreeView } -import net.virtualvoid.sbt.graph.util.IOUtil -import internal.librarymanagement._ -import librarymanagement._ -import sbt.dependencygraph.SbtAccess -import sbt.dependencygraph.DependencyGraphSbtCompat.Implicits._ -import sbt.complete.Parsers - -object DependencyGraphSettings { - import DependencyGraphKeys._ - import ModuleGraphProtocol._ - - def graphSettings = baseSettings ++ reportSettings - - def baseSettings = Seq( - ivyReportFunction := ivyReportFunctionTask.value, - - // disable the cached resolution engine (exposing a scoped `ivyModule` used directly by `updateTask`), as it - // generates artificial module descriptors which are internal to sbt, making it hard to reconstruct the - // dependency tree - updateOptions in ignoreMissingUpdate := updateOptions.value.withCachedResolution(false), - ivyConfiguration in ignoreMissingUpdate := - // inTask will make sure the new definition will pick up `updateOptions in ignoreMissingUpdate` - SbtAccess.inTask(ignoreMissingUpdate, Classpaths.mkIvyConfiguration).value, - ivyModule in ignoreMissingUpdate := { - // concatenating & inlining ivySbt & ivyModule default task implementations, as `SbtAccess.inTask` does - // NOT correctly force the scope when applied to `TaskKey.toTask` instances (as opposed to raw - // implementations like `Classpaths.mkIvyConfiguration` or `Classpaths.updateTask`) - val is = new IvySbt((ivyConfiguration in ignoreMissingUpdate).value) - new is.Module(moduleSettings.value) - }, - - // don't fail on missing dependencies - updateConfiguration in ignoreMissingUpdate := updateConfiguration.value.withMissingOk(true), - - ignoreMissingUpdate := - // inTask will make sure the new definition will pick up `ivyModule/updateConfiguration in ignoreMissingUpdate` - SbtAccess.inTask(ignoreMissingUpdate, Classpaths.updateTask).value, - - filterScalaLibrary in Global := true) - - def reportSettings = - Seq(Compile, Test, IntegrationTest, Runtime, Provided, Optional).flatMap(ivyReportForConfig) - - val renderingAlternatives: Seq[(TaskKey[Unit], ModuleGraph ⇒ String)] = - Seq( - dependencyTree -> rendering.AsciiTree.asciiTree _, - dependencyList -> rendering.FlatList.render(_.id.idString), - dependencyStats -> rendering.Statistics.renderModuleStatsList _, - licenseInfo -> rendering.LicenseInfo.render _) - - def ivyReportForConfig(config: Configuration) = inConfig(config)( - Seq( - 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 := { - // FIXME: remove busywork - val scalaVersion = Keys.scalaVersion.value - val moduleGraph = DependencyGraphKeys.moduleGraph.value - - if (filterScalaLibrary.value) GraphTransformations.ignoreScalaLibrary(scalaVersion, moduleGraph) - else moduleGraph - }, - moduleGraphStore := (moduleGraph storeAs moduleGraphStore triggeredBy moduleGraph).value, - - // browse - dependencyBrowseGraphTarget := { target.value / "browse-dependency-graph" }, - dependencyBrowseGraphHTML := browseGraphHTMLTask.value, - dependencyBrowseGraph := openBrowser(dependencyBrowseGraphHTML).value, - - dependencyBrowseTreeTarget := { target.value / "browse-dependency-tree" }, - dependencyBrowseTreeHTML := browseTreeHTMLTask.value, - dependencyBrowseTree := openBrowser(dependencyBrowseTreeHTML).value, - - // dot support - 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, - dependencyDotHeader := - """|digraph "dependency-graph" { - | graph[rankdir="LR"] - | edge [ - | arrowtail="none" - | ]""".stripMargin, - dependencyDotNodeLabel := { (organisation: String, name: String, version: String) ⇒ - """%s
%s
%s""".format(organisation, name, version) - }, - - // GraphML support - dependencyGraphMLFile := { target.value / "dependencies-%s.graphml".format(config.toString) }, - dependencyGraphML := dependencyGraphMLTask.value, - - 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) - } - val output = - modules - .map { module ⇒ - rendering.AsciiTree.asciiTree(GraphTransformations.reverseGraphStartingAt(graph, module)) - } - .mkString("\n") - - streams.value.log.info(output) - output - }, - // deprecated settings - asciiTree := (asString in dependencyTree).value) ++ - renderingAlternatives.flatMap((renderingTaskSettings _).tupled) ++ - AsciiGraph.asciiGraphSetttings) - - def renderingTaskSettings(key: TaskKey[Unit], renderer: ModuleGraph ⇒ String): Seq[Setting[_]] = - Seq( - asString in key := renderer(moduleGraph.value), - printToConsole in key := streams.value.log.info((asString in key).value), - toFile in key := { - val (targetFile, force) = targetFileAndForceParser.parsed - writeToFile(key.key.label, (asString in key).value, targetFile, force, streams.value) - }, - key := (printToConsole in key).value) - - def ivyReportFunctionTask = Def.task { - val ivyConfig = Keys.ivyConfiguration.value.asInstanceOf[InlineIvyConfiguration] - val projectID = Keys.projectID.value - val ivyModule = Keys.ivyModule.value - - (config: String) ⇒ { - val org = projectID.organization - val name = crossName(ivyModule) - new File(ivyConfig.resolutionCacheDir.get, s"reports/$org-$name-$config.xml") - } - } - - def dependencyGraphMLTask = - 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 browseGraphHTMLTask = - 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 browseTreeHTMLTask = - Def.task { - val renderedTree = TreeView.createJson(moduleGraph.value) - val link = TreeView.createLink(renderedTree, target.value) - streams.value.log.info(s"HTML tree written to $link") - link - } - - def writeToFile(dataTask: TaskKey[String], fileTask: SettingKey[File]) = - Def.task { - val outFile = fileTask.value - IOUtil.writeToFile(dataTask.value, outFile) - - streams.value.log.info("Wrote dependency graph to '%s'" format outFile) - outFile - } - - def writeToFile(what: String, data: String, targetFile: File, force: Boolean, streams: TaskStreams): File = - if (targetFile.exists && !force) - throw new RuntimeException(s"Target file for $what already exists at ${targetFile.getAbsolutePath}. Use '-f' to override") - else { - IOUtil.writeToFile(data, targetFile) - - streams.log.info(s"Wrote $what to '$targetFile'") - targetFile - } - - def absoluteReportPath = (file: File) ⇒ file.getAbsolutePath - - def openBrowser(uriKey: TaskKey[URI]) = - Def.task { - val uri = uriKey.value - streams.value.log.info("Opening in browser...") - java.awt.Desktop.getDesktop.browse(uri) - uri - } - - case class ArtifactPattern( - organisation: String, - name: String, - version: Option[String]) - - import sbt.complete.DefaultParsers._ - val artifactPatternParser: Def.Initialize[State ⇒ Parser[ArtifactPattern]] = - resolvedScoped { ctx ⇒ (state: State) ⇒ - val graph = loadFromContext(moduleGraphStore, ctx, state) getOrElse ModuleGraph(Nil, Nil) - - 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 { - // If the moduleGraphStore couldn't be loaded because no dependency tree command was run before, we should still provide a parser for the command. - ((Space ~> token(StringBasic, "")) ~ (Space ~> token(StringBasic, "")) ~ (Space ~> token(StringBasic, "")).?).map { - case ((org, mod), version) ⇒ - ArtifactPattern(org, mod, version) - } - } - } - val shouldForceParser: Parser[Boolean] = (Space ~> (Parser.literal("-f") | "--force")).?.map(_.isDefined) - - val targetFileAndForceParser: Parser[(File, Boolean)] = - Parsers.fileParser(new File(".")) ~ shouldForceParser - - // This is to support 0.13.8's InlineConfigurationWithExcludes while not forcing 0.13.8 - type HasModule = { - val module: ModuleID - } - def crossName(ivyModule: IvySbt#Module) = - ivyModule.moduleSettings match { - case ic: InlineConfiguration ⇒ ic.module.name - case hm: HasModule @unchecked if hm.getClass.getName == "sbt.InlineConfigurationWithExcludes" ⇒ hm.module.name - case _ ⇒ - throw new IllegalStateException("sbt-dependency-graph plugin currently only supports InlineConfiguration of ivy settings (the default in sbt)") - } - - val VersionPattern = """(\d+)\.(\d+)\.(\d+)(?:-(.*))?""".r - object Version { - def unapply(str: String): Option[(Int, Int, Int, Option[String])] = str match { - case VersionPattern(major, minor, fix, appendix) ⇒ Some((major.toInt, minor.toInt, fix.toInt, Option(appendix))) - case _ ⇒ None - } - } -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/GraphTransformations.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/GraphTransformations.scala deleted file mode 100644 index c5c4e8a21..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/GraphTransformations.scala +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2011, 2012 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 - -object GraphTransformations { - def reverseGraphStartingAt(graph: ModuleGraph, root: ModuleId): ModuleGraph = { - val deps = graph.reverseDependencyMap - - def visit(module: ModuleId, visited: Set[ModuleId]): Seq[(ModuleId, ModuleId)] = - if (visited(module)) - Nil - else - deps.get(module) match { - case Some(deps) ⇒ - deps.flatMap { to ⇒ - (module, to.id) +: visit(to.id, visited + module) - } - case None ⇒ Nil - } - - val edges = visit(root, Set.empty) - val nodes = edges.foldLeft(Set.empty[ModuleId])((set, edge) ⇒ set + edge._1 + edge._2).map(graph.module) - ModuleGraph(nodes.toSeq, edges) - } - - def ignoreScalaLibrary(scalaVersion: String, graph: ModuleGraph): ModuleGraph = { - def isScalaLibrary(m: Module) = isScalaLibraryId(m.id) - def isScalaLibraryId(id: ModuleId) = id.organisation == "org.scala-lang" && id.name == "scala-library" - - def dependsOnScalaLibrary(m: Module): Boolean = - graph.dependencyMap(m.id).exists(isScalaLibrary) - - def addScalaLibraryAnnotation(m: Module): Module = { - if (dependsOnScalaLibrary(m)) - m.copy(extraInfo = m.extraInfo + " [S]") - else - m - } - - val newNodes = graph.nodes.map(addScalaLibraryAnnotation).filterNot(isScalaLibrary) - val newEdges = graph.edges.filterNot(e ⇒ isScalaLibraryId(e._2)) - ModuleGraph(newNodes, newEdges) - } -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/Main.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/Main.scala deleted file mode 100644 index fb51d60b7..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/Main.scala +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2015 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 - -import java.io.File - -import net.virtualvoid.sbt.graph.backend.IvyReport - -object Main extends App { - def die(msg: String): Nothing = { - println(msg) - sys.exit(1) - } - def usage: String = - "Usage: " - - val reportFile = args.lift(0).filter(f ⇒ new File(f).exists).getOrElse(die(usage)) - val outputFile = args.lift(1).getOrElse(die(usage)) - val graph = IvyReport.fromReportFile(reportFile) - rendering.GraphML.saveAsGraphML(graph, outputFile) -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/backend/IvyReport.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/backend/IvyReport.scala deleted file mode 100644 index 426a68a3e..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/backend/IvyReport.scala +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 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 backend - -import scala.xml.{ NodeSeq, Document, Node } -import scala.xml.parsing.ConstructingParser - -object IvyReport { - def fromReportFile(ivyReportFile: String): ModuleGraph = - fromReportXML(loadXML(ivyReportFile)) - - def fromReportXML(doc: Document): ModuleGraph = { - def edgesForModule(id: ModuleId, revision: NodeSeq): Seq[Edge] = - for { - caller ← revision \ "caller" - callerModule = moduleIdFromElement(caller, caller.attribute("callerrev").get.text) - } yield (moduleIdFromElement(caller, caller.attribute("callerrev").get.text), id) - - val moduleEdges: Seq[(Module, Seq[Edge])] = for { - mod ← doc \ "dependencies" \ "module" - revision ← mod \ "revision" - rev = revision.attribute("name").get.text - moduleId = moduleIdFromElement(mod, rev) - 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)) - } yield (module, edgesForModule(moduleId, revision)) - - val (nodes, edges) = moduleEdges.unzip - - val info = (doc \ "info").head - def infoAttr(name: String): String = - info.attribute(name).getOrElse(throw new IllegalArgumentException("Missing attribute " + name)).text - val rootModule = Module(ModuleId(infoAttr("organisation"), infoAttr("module"), infoAttr("revision"))) - - ModuleGraph(rootModule +: nodes, edges.flatten) - } - - private def moduleIdFromElement(element: Node, version: String): ModuleId = - ModuleId(element.attribute("organisation").get.text, element.attribute("name").get.text, version) - - private def loadXML(ivyReportFile: String) = - ConstructingParser.fromSource(io.Source.fromFile(ivyReportFile), preserveWS = false).document() -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala deleted file mode 100644 index 44a4c6cec..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2015 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 backend - -import scala.language.implicitConversions -import scala.language.reflectiveCalls - -import sbt._ - -object SbtUpdateReport { - type OrganizationArtifactReport = { - def modules: Seq[ModuleReport] - } - - def fromConfigurationReport(report: ConfigurationReport, rootInfo: sbt.ModuleID): ModuleGraph = { - implicit def id(sbtId: sbt.ModuleID): ModuleId = ModuleId(sbtId.organization, sbtId.name, sbtId.revision) - - def moduleEdges(orgArt: OrganizationArtifactReport): Seq[(Module, Seq[Edge])] = { - val chosenVersion = orgArt.modules.find(!_.evicted).map(_.module.revision) - orgArt.modules.map(moduleEdge(chosenVersion)) - } - - 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( - id = report.module, - license = report.licenses.headOption.map(_._1), - evictedByVersion = evictedByVersion, - jarFile = jarFile, - error = report.problem), - report.callers.map(caller ⇒ Edge(caller.caller, report.module))) - } - - val (nodes, edges) = report.details.flatMap(moduleEdges).unzip - val root = Module(rootInfo) - - ModuleGraph(root +: nodes, edges.flatten) - } -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/model.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/model.scala deleted file mode 100644 index cbfc43294..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/model.scala +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2015 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 - -import java.io.File - -import sbinary.Format - -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) { - def hadError: Boolean = error.isDefined - def isUsed: Boolean = !isEvicted - def isEvicted: Boolean = evictedByVersion.isDefined -} - -object ModuleGraph { - val empty = ModuleGraph(Seq.empty, Seq.empty) -} - -case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) { - lazy val modules: Map[ModuleId, Module] = - nodes.map(n ⇒ (n.id, n)).toMap - - def module(id: ModuleId): Module = modules(id) - - lazy val dependencyMap: Map[ModuleId, Seq[Module]] = - createMap(identity) - - lazy val reverseDependencyMap: Map[ModuleId, Seq[Module]] = - createMap { case (a, b) ⇒ (b, a) } - - def createMap(bindingFor: ((ModuleId, ModuleId)) ⇒ (ModuleId, ModuleId)): Map[ModuleId, Seq[Module]] = { - val m = new HashMap[ModuleId, Set[Module]] with MultiMap[ModuleId, Module] - edges.foreach { entry ⇒ - val (f, t) = bindingFor(entry) - m.addBinding(f, module(t)) - } - m.toMap.mapValues(_.toSeq.sortBy(_.id.idString)).withDefaultValue(Nil) - } - - def roots: Seq[Module] = - nodes.filter(n ⇒ !edges.exists(_._2 == n.id)).sortBy(_.id.idString) -} - -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) - implicit val ModuleGraphFormat: Format[ModuleGraph] = asProduct2(ModuleGraph.apply _)(ModuleGraph.unapply(_).get) -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/package.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/package.scala deleted file mode 100644 index 41921bcfa..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/package.scala +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2015 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 - -package object graph { - type Edge = (ModuleId, ModuleId) - def Edge(from: ModuleId, to: ModuleId): Edge = from -> to -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala deleted file mode 100644 index c2670e6a2..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiTree.scala +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 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 - -import util.AsciiTreeLayout -import util.ConsoleUtils._ - -object AsciiTree { - def asciiTree(graph: ModuleGraph): String = { - val deps = graph.dependencyMap - - // there should only be one root node (the project itself) - val roots = graph.roots - roots.map { root ⇒ - AsciiTreeLayout.toAscii[Module](root, node ⇒ deps.getOrElse(node.id, Seq.empty[Module]), displayModule) - }.mkString("\n") - } - - def displayModule(module: Module): String = - red(module.id.idString + - module.extraInfo + - module.error.map(" (error: " + _ + ")").getOrElse("") + - module.evictedByVersion.map(_ formatted " (evicted by: %s)").getOrElse(""), module.hadError) -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/DagreHTML.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/DagreHTML.scala deleted file mode 100644 index 3064ef502..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/DagreHTML.scala +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 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 - -import java.io.File -import java.net.{ URLEncoder, URI } - -import net.virtualvoid.sbt.graph.util.IOUtil - -object DagreHTML { - def createLink(dotGraph: String, targetDirectory: File): URI = { - targetDirectory.mkdirs() - val graphHTML = new File(targetDirectory, "graph.html") - IOUtil.saveResource("graph.html", graphHTML) - IOUtil.writeToFile(dotGraph, new File(targetDirectory, "dependencies.dot")) - - val graphString = - URLEncoder.encode(dotGraph, "utf8") - .replaceAllLiterally("+", "%20") - - IOUtil.writeToFile(s"""data = "$graphString";""", new File(targetDirectory, "dependencies.dot.js")) - - new URI(graphHTML.toURI.toString) - } -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/FlatList.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/FlatList.scala deleted file mode 100644 index 95f0676d6..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/FlatList.scala +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2016 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 FlatList { - def render(display: Module ⇒ String)(graph: ModuleGraph): String = - graph.modules.values.toSeq - .distinct - .filterNot(_.isEvicted) - .sortBy(m ⇒ (m.id.organisation, m.id.name)) - .map(display) - .mkString("\n") -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/GraphML.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/GraphML.scala deleted file mode 100644 index e1681fdad..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/GraphML.scala +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2015 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.rendering - -import net.virtualvoid.sbt.graph.ModuleGraph - -import scala.xml.XML - -object GraphML { - def saveAsGraphML(graph: ModuleGraph, outputFile: String): Unit = { - val nodesXml = - for (n ← graph.nodes) - yield - - { n.id.idString } - - - - val edgesXml = - for (e ← graph.edges) - yield - - val xml = - - - - { nodesXml } - { edgesXml } - - - - XML.save(outputFile, xml) - } -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/LicenseInfo.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/LicenseInfo.scala deleted file mode 100644 index cb97d3f0e..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/LicenseInfo.scala +++ /dev/null @@ -1,12 +0,0 @@ -package net.virtualvoid.sbt.graph.rendering - -import net.virtualvoid.sbt.graph.ModuleGraph - -object LicenseInfo { - def render(graph: ModuleGraph): String = - graph.nodes.filter(_.isUsed).groupBy(_.license).toSeq.sortBy(_._1).map { - case (license, modules) ⇒ - license.getOrElse("No license specified") + "\n" + - modules.map(_.id.idString formatted "\t %s").mkString("\n") - }.mkString("\n\n") -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/Statistics.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/Statistics.scala deleted file mode 100644 index a9d10fdba..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/Statistics.scala +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2016 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 Statistics { - def renderModuleStatsList(graph: ModuleGraph): String = { - case class ModuleStats( - id: ModuleId, - numDirectDependencies: Int, - numTransitiveDependencies: Int, - selfSize: Option[Long], - transitiveSize: Long, - transitiveDependencyStats: Map[ModuleId, ModuleStats]) { - def transitiveStatsWithSelf: Map[ModuleId, ModuleStats] = transitiveDependencyStats + (id -> this) - } - - def statsFor(moduleId: ModuleId): ModuleStats = { - val directDependencies = graph.dependencyMap(moduleId).filterNot(_.isEvicted).map(_.id) - val dependencyStats = directDependencies.map(statsFor).flatMap(_.transitiveStatsWithSelf).toMap - val selfSize = graph.module(moduleId).jarFile.filter(_.exists).map(_.length) - val numDirectDependencies = directDependencies.size - val numTransitiveDependencies = dependencyStats.size - val transitiveSize = selfSize.getOrElse(0L) + dependencyStats.map(_._2.selfSize.getOrElse(0L)).sum - - ModuleStats(moduleId, numDirectDependencies, numTransitiveDependencies, selfSize, transitiveSize, dependencyStats) - } - - def format(stats: ModuleStats): String = { - import stats._ - def mb(bytes: Long): Double = bytes.toDouble / 1000000 - val selfSize = - stats.selfSize match { - case Some(size) ⇒ f"${mb(size)}%7.3f" - case None ⇒ "-------" - } - f"${mb(transitiveSize)}%7.3f MB $selfSize MB $numTransitiveDependencies%4d $numDirectDependencies%4d ${id.idString}%s" - } - - val allStats = - graph.roots.flatMap(r ⇒ statsFor(r.id).transitiveStatsWithSelf).toMap.values.toSeq - .sortBy(s ⇒ (-s.transitiveSize, -s.numTransitiveDependencies)) - - val header = " TotSize JarSize #TDe #Dep Module\n" - - header + - allStats.map(format).mkString("\n") + - """ - | - |Columns are - | - Jar-Size including dependencies - | - Jar-Size - | - Number of transitive dependencies - | - Number of direct dependencies - | - ModuleID""".stripMargin - } -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/TreeView.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/TreeView.scala deleted file mode 100644 index 582202def..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/rendering/TreeView.scala +++ /dev/null @@ -1,42 +0,0 @@ -package net.virtualvoid.sbt.graph.rendering - -import java.io.File -import java.net.URI - -import net.virtualvoid.sbt.graph.util.IOUtil -import net.virtualvoid.sbt.graph.{ Module, ModuleGraph } - -import scala.util.parsing.json.{ JSONArray, JSONObject } - -object TreeView { - def createJson(graph: ModuleGraph): String = { - val trees = graph.roots - .map(module ⇒ processSubtree(graph, module)) - .toList - JSONArray(trees).toString - } - - def createLink(graphJson: String, targetDirectory: File): URI = { - targetDirectory.mkdirs() - val graphHTML = new File(targetDirectory, "tree.html") - IOUtil.saveResource("tree.html", graphHTML) - IOUtil.writeToFile(graphJson, new File(targetDirectory, "tree.json")) - IOUtil.writeToFile(s"tree_data = $graphJson;", new File(targetDirectory, "tree.data.js")) - new URI(graphHTML.toURI.toString) - } - - private def processSubtree(graph: ModuleGraph, module: Module): JSONObject = { - val children = graph.dependencyMap - .getOrElse(module.id, List()) - .map(module ⇒ processSubtree(graph, module)) - .toList - moduleAsJson(module, children) - } - - private def moduleAsJson(module: Module, children: List[JSONObject]): JSONObject = { - val eviction = module.evictedByVersion.map(version ⇒ s" (evicted by $version)").getOrElse("") - val error = module.error.map(err ⇒ s" (errors: $err)").getOrElse("") - val text = module.id.idString + eviction + error - JSONObject(Map("text" -> text, "children" -> JSONArray(children))) - } -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala deleted file mode 100644 index 746dab6df..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayout.scala +++ /dev/null @@ -1,62 +0,0 @@ -/* sbt -- Simple Build Tool - * Copyright 2011 Mark Harrah, Eugene Yokota - * - * Copied from sbt 0.12 source code - */ -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 = { - val twoSpaces = " " + " " // prevent accidentally being converted into a tab - def limitLine(s: String): String = - if (s.length > maxColumn) s.slice(0, maxColumn - 2) + ".." - else s - def insertBar(s: String, at: Int): String = - if (at < s.length) - s.slice(0, at) + - (s(at).toString match { - case " " ⇒ "|" - case x ⇒ x - }) + - s.slice(at + 1, s.length) - else s - def toAsciiLines(node: A, level: Int, parents: Set[A]): Vector[String] = - if (parents contains node) // cycle - Vector(limitLine((twoSpaces * level) + "#-" + display(node) + " (cycle)")) - else { - val line = limitLine((twoSpaces * level) + (if (level == 0) "" else "+-") + display(node)) - val cs = Vector(children(node): _*) - val childLines = cs map { - toAsciiLines(_, level + 1, parents + node) - } - val withBar = childLines.zipWithIndex flatMap { - case (lines, pos) if pos < (cs.size - 1) ⇒ lines map { - insertBar(_, 2 * (level + 1)) - } - case (lines, pos) ⇒ - if (lines.last.trim != "") lines ++ Vector(twoSpaces * (level + 1)) - else lines - } - line +: withBar - } - - toAsciiLines(top, 0, Set.empty).mkString("\n") - } - - def defaultColumnSize: Int = { - val termWidth = SbtAccess.getTerminalWidth - if (termWidth > 20) termWidth - 8 - else 80 // ignore termWidth - } -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/util/ConsoleUtils.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/util/ConsoleUtils.scala deleted file mode 100644 index ceba7da65..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/util/ConsoleUtils.scala +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2015 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.util - -import sbt.ConsoleLogger - -object ConsoleUtils { - def red(str: String, doRed: Boolean): String = - if (ConsoleLogger.formatEnabled && doRed) - Console.RED + str + Console.RESET - else - str -} diff --git a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/util/IOUtil.scala b/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/util/IOUtil.scala deleted file mode 100644 index c9b8ebbf5..000000000 --- a/sbt-dependency-graph/src/main/scala/net/virtualvoid/sbt/graph/util/IOUtil.scala +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 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.util - -import java.io.{ OutputStream, InputStream, FileOutputStream, File } -import java.nio.charset.Charset - -import scala.annotation.tailrec - -object IOUtil { - val utf8 = Charset.forName("utf8") - - def writeToFile(string: String, file: File): Unit = - sbt.IO.write(file, string, utf8) - - def saveResource(resourcePath: String, to: File): Unit = { - val is = getClass.getClassLoader.getResourceAsStream(resourcePath) - require(is ne null, s"Couldn't load '$resourcePath' from classpath.") - - val fos = new FileOutputStream(to) - try copy(is, fos) - finally { - is.close() - fos.close() - } - } - - def copy(from: InputStream, to: OutputStream): Unit = { - val buffer = new Array[Byte](65536) - - @tailrec def rec(): Unit = { - val read = from.read(buffer) - if (read > 0) { - to.write(buffer, 0, read) - rec() - } else if (read == 0) - throw new IllegalStateException("InputStream.read returned 0") - } - rec() - } -} diff --git a/sbt-dependency-graph/src/main/scala/sbt/dependencygraph/SbtAccess.scala b/sbt-dependency-graph/src/main/scala/sbt/dependencygraph/SbtAccess.scala deleted file mode 100644 index d1f4e596e..000000000 --- a/sbt-dependency-graph/src/main/scala/sbt/dependencygraph/SbtAccess.scala +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2015 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 sbt -package dependencygraph - -import Def._ - -/** Accessors to private[sbt] symbols. */ -object SbtAccess { - val unmanagedScalaInstanceOnly = Defaults.unmanagedScalaInstanceOnly - - def getTerminalWidth: Int = sbt.internal.util.JLine.usingTerminal(_.getWidth) - - def inTask[T](t: Scoped, i: Initialize[T]): Initialize[T] = _root_.sbt.inTask(t, i) -} diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/cachedResolution/project/plugins.sbt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/cachedResolution/project/plugins.sbt deleted file mode 100644 index 6fdebb6d6..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/cachedResolution/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % sys.props("project.version")) diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/plugins.sbt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/plugins.sbt deleted file mode 120000 index 0caf1de77..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -../../plugins.sbt \ No newline at end of file diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt deleted file mode 100644 index b417c9e3b..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt +++ /dev/null @@ -1,25 +0,0 @@ -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") := { - 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.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")) - require(sanitize(graph) == sanitize(expectedGraph), "Graph for report %s was '\n%s' but should have been '\n%s'" format (report, sanitize(graph), sanitize(expectedGraph))) - () -} diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt deleted file mode 120000 index 0caf1de77..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -../../plugins.sbt \ No newline at end of file diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/plugins.sbt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/plugins.sbt deleted file mode 100644 index 6fdebb6d6..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % sys.props("project.version")) diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt deleted file mode 120000 index 0caf1de77..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -../../plugins.sbt \ No newline at end of file diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/showMissingUpdates/test b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/showMissingUpdates/test deleted file mode 100644 index a5912a391..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/showMissingUpdates/test +++ /dev/null @@ -1 +0,0 @@ -> check \ No newline at end of file diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/build.sbt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/build.sbt deleted file mode 100644 index bb8469447..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/build.sbt +++ /dev/null @@ -1,68 +0,0 @@ -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_2.9.2
0.1-SNAPSHOT> style=""] - | "just-a-transitive-dependency:just-a-transitive-dependency_2.9.2:0.1-SNAPSHOT"[label=just-a-transitive-dependency_2.9.2
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_2.9.2
0.1-SNAPSHOT> style=""] - | "just-a-dependency:just-a-dependency_2.9.2:0.1-SNAPSHOT"[label=just-a-dependency_2.9.2
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 -} \ No newline at end of file diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/plugins.sbt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/plugins.sbt deleted file mode 120000 index 0caf1de77..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -../../plugins.sbt \ No newline at end of file diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/test b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/test deleted file mode 100644 index f9fa19e83..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/test +++ /dev/null @@ -1,2 +0,0 @@ -> project test-dot-file-generation -> check diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/licenses.txt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/licenses.txt deleted file mode 100644 index 826ed0153..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/licenses.txt +++ /dev/null @@ -1,9 +0,0 @@ -No license specified - org.example:blubber_2.12:0.1 - -The Apache Software License, Version 2.0 - org.codehaus.jackson:jackson-mapper-asl:1.9.11 - org.codehaus.jackson:jackson-core-asl:1.9.11 - -The MIT License - com.codahale:jerkson_2.9.1:0.5.0 \ No newline at end of file diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/list.txt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/list.txt deleted file mode 100644 index 4bf401868..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/list.txt +++ /dev/null @@ -1,4 +0,0 @@ -com.codahale:jerkson_2.9.1:0.5.0 -org.codehaus.jackson:jackson-core-asl:1.9.11 -org.codehaus.jackson:jackson-mapper-asl:1.9.11 -org.example:blubber_2.12:0.1 \ No newline at end of file diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/stats.txt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/stats.txt deleted file mode 100644 index 6a76e3522..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/stats.txt +++ /dev/null @@ -1,12 +0,0 @@ - TotSize JarSize #TDe #Dep Module - 1.754 MB ------- MB 3 1 org.example:blubber_2.12:0.1 - 1.754 MB 0.741 MB 2 2 com.codahale:jerkson_2.9.1:0.5.0 - 1.013 MB 0.780 MB 1 1 org.codehaus.jackson:jackson-mapper-asl:1.9.11 - 0.232 MB 0.232 MB 0 0 org.codehaus.jackson:jackson-core-asl:1.9.11 - -Columns are - - Jar-Size including dependencies - - Jar-Size - - Number of transitive dependencies - - Number of direct dependencies - - ModuleID \ No newline at end of file diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/tree.txt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/tree.txt deleted file mode 100644 index 5b1f1aa5e..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/expected/tree.txt +++ /dev/null @@ -1,6 +0,0 @@ -org.example:blubber_2.12:0.1 [S] - +-com.codahale:jerkson_2.9.1:0.5.0 [S] - +-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 - \ No newline at end of file diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/project/plugins.sbt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/project/plugins.sbt deleted file mode 100644 index 6fdebb6d6..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % sys.props("project.version")) diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/test b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/test deleted file mode 100644 index 83d872e3e..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/test +++ /dev/null @@ -1,5 +0,0 @@ -> dependencyTree::toFile target/tree.txt -> dependencyList::toFile target/list.txt -> dependencyStats::toFile target/stats.txt -> dependencyLicenseInfo::toFile target/licenses.txt -> check diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn-without-previous-initialization/project/plugins.sbt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn-without-previous-initialization/project/plugins.sbt deleted file mode 100644 index 6fdebb6d6..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn-without-previous-initialization/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % sys.props("project.version")) diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn/project/plugins.sbt b/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn/project/plugins.sbt deleted file mode 100644 index 6fdebb6d6..000000000 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % sys.props("project.version")) diff --git a/sbt-dependency-graph/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala b/sbt-dependency-graph/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala deleted file mode 100644 index 097b7adf6..000000000 --- a/sbt-dependency-graph/src/test/scala/net/virtualvoid/sbt/graph/util/AsciiTreeLayoutSpecs.scala +++ /dev/null @@ -1,94 +0,0 @@ -package net.virtualvoid.sbt.graph.util - -import org.specs2.mutable.Specification - -class AsciiTreeLayoutSpecs extends Specification { - sealed trait Tree - case class Branch(left: Tree, right: Tree) extends Tree - case class Leaf(i: Int) extends Tree - - def children(t: Tree): Seq[Tree] = t match { - case Branch(left, right) ⇒ Seq(left, right) - case _: Leaf ⇒ Nil - } - def display(t: Tree): String = t match { - case Branch(left, right) ⇒ "Branch" - case Leaf(value) ⇒ value.toString * value - } - - "Graph" should { - "layout simple graphs" in { - val simple = Branch(Branch(Leaf(1), Leaf(2)), Leaf(3)) - AsciiTreeLayout.toAscii(simple, children, display, 20) === - """Branch - | +-Branch - | | +-1 - | | +-22 - | |\u0020 - | +-333 - | """.stripMargin - } - "add separator lines where applicable" in { - val simple = Branch(Branch(Leaf(1), Branch(Leaf(2), Leaf(3))), Leaf(4)) - AsciiTreeLayout.toAscii(simple, children, display, 20) === - """Branch - | +-Branch - | | +-1 - | | +-Branch - | | +-22 - | | +-333 - | |\u0020\u0020\u0020 - | +-4444 - | """.stripMargin - } - "layout deep graphs" in { - val simple = Branch(Branch(Branch(Branch(Branch(Branch(Leaf(1), Leaf(1)), Leaf(1)), Leaf(1)), Leaf(2)), Leaf(3)), Leaf(4)) - AsciiTreeLayout.toAscii(simple, children, display, 10) === - """Branch - | +-Branch - | | +-Br.. - | | | +-.. - | | | | .. - | | | | .. - | | | | .. - | | | | .. - | | | | | |\u0020 - | | | | .. - | | | | |\u0020 - | | | | .. - | | | |\u0020 - | | | +-22 - | | |\u0020 - | | +-333 - | |\u0020 - | +-4444 - | """.stripMargin - } - "cut off cycles" in { - AsciiTreeLayout.toAscii[Int](1, Map( - 1 -> Seq(2, 3, 4), - 2 -> Seq(4, 5), - 3 -> Seq(), - 4 -> Seq(3), - 5 -> Seq(1, 4, 6, 7), - 6 -> Seq(), - 7 -> Seq()), _.toString).trim === - """1 - | +-2 - | | +-4 - | | | +-3 - | | |\u0020 - | | +-5 - | | #-1 (cycle) - | | +-4 - | | | +-3 - | | |\u0020 - | | +-6 - | | +-7 - | |\u0020\u0020\u0020 - | +-3 - | +-4 - | +-3""".stripMargin.trim - } - } -} diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/cachedResolution/build.sbt b/sbt/src/sbt-test/dependency-graph/cachedResolution/build.sbt similarity index 85% rename from sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/cachedResolution/build.sbt rename to sbt/src/sbt-test/dependency-graph/cachedResolution/build.sbt index e9aef9b55..82144c4a0 100644 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/cachedResolution/build.sbt +++ b/sbt/src/sbt-test/dependency-graph/cachedResolution/build.sbt @@ -4,8 +4,8 @@ libraryDependencies += "org.slf4j" % "slf4j-api" % "1.7.28" updateOptions := updateOptions.value.withCachedResolution(true) TaskKey[Unit]("check") := { - val report = (ivyReport in Test).value - val graph = (asciiTree in Test).value + val report = (Test / ivyReport).value + val graph = (Test / dependencyTree / asString).value def sanitize(str: String): String = str.split('\n').drop(1).mkString("\n") val expectedGraph = diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/cachedResolution/test b/sbt/src/sbt-test/dependency-graph/cachedResolution/test similarity index 100% rename from sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/cachedResolution/test rename to sbt/src/sbt-test/dependency-graph/cachedResolution/test diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt b/sbt/src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt similarity index 91% rename from sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt rename to sbt/src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt index 1d004c5b6..7e9f4cce2 100644 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt +++ b/sbt/src/sbt-test/dependency-graph/ignoreScalaLibrary/build.sbt @@ -6,8 +6,8 @@ libraryDependencies ++= Seq( ) TaskKey[Unit]("check") := { - val report = (ivyReport in Test).value - val graph = (asciiTree in Test).value + val report = updateFull.value + val graph = (Test / dependencyTree / asString).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] diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/test b/sbt/src/sbt-test/dependency-graph/ignoreScalaLibrary/test similarity index 100% rename from sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/test rename to sbt/src/sbt-test/dependency-graph/ignoreScalaLibrary/test diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt b/sbt/src/sbt-test/dependency-graph/showMissingUpdates/build.sbt similarity index 86% rename from sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt rename to sbt/src/sbt-test/dependency-graph/showMissingUpdates/build.sbt index da6ad1a2a..192ecb0a9 100644 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt +++ b/sbt/src/sbt-test/dependency-graph/showMissingUpdates/build.sbt @@ -4,8 +4,8 @@ libraryDependencies += "at.blub" % "blib" % "1.2.3" % "test" TaskKey[Unit]("check") := { - val report = (ivyReport in Test).value - val graph = (asciiTree in Test).value + val report = updateFull.value + val graph = (Test / dependencyTree / asString).value def sanitize(str: String): String = str.split('\n').drop(1).mkString("\n") val expectedGraph = diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/test b/sbt/src/sbt-test/dependency-graph/showMissingUpdates/disabled similarity index 100% rename from sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/test rename to sbt/src/sbt-test/dependency-graph/showMissingUpdates/disabled diff --git a/sbt/src/sbt-test/dependency-graph/testDotFileGeneration/build.sbt b/sbt/src/sbt-test/dependency-graph/testDotFileGeneration/build.sbt new file mode 100644 index 000000000..313bcc9d7 --- /dev/null +++ b/sbt/src/sbt-test/dependency-graph/testDotFileGeneration/build.sbt @@ -0,0 +1,53 @@ +import scala.collection.mutable.ListBuffer + +ThisBuild / scalaVersion := "2.9.2" +ThisBuild / version := "0.1-SNAPSHOT" + +lazy val justATransiviteDependencyEndpointProject = project + +lazy val justATransitiveDependencyProject = project + .dependsOn(justATransiviteDependencyEndpointProject) + +lazy val justADependencyProject = project + +lazy val test_project = project + .dependsOn(justADependencyProject, justATransitiveDependencyProject) + .settings( + TaskKey[Unit]("check") := { + val dotFile = (dependencyDot in Compile).value + val expectedGraph = + """digraph "dependency-graph" { + | graph[rankdir="LR"] + | edge [ + | arrowtail="none" + | ] + | "test_project:test_project_2.9.2:0.1-SNAPSHOT"[label=test_project_2.9.2
0.1-SNAPSHOT> style=""] + | "justatransitivedependencyproject:justatransitivedependencyproject_2.9.2:0.1-SNAPSHOT"[label=justatransitivedependencyproject_2.9.2
0.1-SNAPSHOT> style=""] + | "justatransivitedependencyendpointproject:justatransivitedependencyendpointproject_2.9.2:0.1-SNAPSHOT"[label=justatransivitedependencyendpointproject_2.9.2
0.1-SNAPSHOT> style=""] + | "justadependencyproject:justadependencyproject_2.9.2:0.1-SNAPSHOT"[label=justadependencyproject_2.9.2
0.1-SNAPSHOT> style=""] + | "test_project:test_project_2.9.2:0.1-SNAPSHOT" -> "justatransitivedependencyproject:justatransitivedependencyproject_2.9.2:0.1-SNAPSHOT" + | "justatransitivedependencyproject:justatransitivedependencyproject_2.9.2:0.1-SNAPSHOT" -> "justatransivitedependencyendpointproject:justatransivitedependencyendpointproject_2.9.2:0.1-SNAPSHOT" + | "test_project:test_project_2.9.2:0.1-SNAPSHOT" -> "justadependencyproject:justadependencyproject_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")) + () + } + ) + +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 +} \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-graph/testDotFileGeneration/test b/sbt/src/sbt-test/dependency-graph/testDotFileGeneration/test new file mode 100644 index 000000000..cc5aac014 --- /dev/null +++ b/sbt/src/sbt-test/dependency-graph/testDotFileGeneration/test @@ -0,0 +1 @@ +> test_project/check diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/build.sbt b/sbt/src/sbt-test/dependency-graph/toFileSubTask/build.sbt similarity index 73% rename from sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/build.sbt rename to sbt/src/sbt-test/dependency-graph/toFileSubTask/build.sbt index d34ee89e9..6b66e7321 100644 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/toFileSubTask/build.sbt +++ b/sbt/src/sbt-test/dependency-graph/toFileSubTask/build.sbt @@ -1,15 +1,10 @@ -scalaVersion := "2.12.6" - -organization := "org.example" +// ThisBuild / useCoursier := false +ThisBuild / scalaVersion := "2.12.6" +ThisBuild / organization := "org.example" +ThisBuild / version := "0.1" name := "blubber" - -version := "0.1" - -libraryDependencies ++= Seq( - "com.codahale" % "jerkson_2.9.1" % "0.5.0" -) - +libraryDependencies += "org.typelevel" %% "cats-effect" % "2.2.0" TaskKey[Unit]("check") := { val candidates = "tree list stats licenses".split(' ').map(_.trim) candidates.foreach { c => diff --git a/sbt/src/sbt-test/dependency-graph/toFileSubTask/expected/licenses.txt b/sbt/src/sbt-test/dependency-graph/toFileSubTask/expected/licenses.txt new file mode 100644 index 000000000..012b770f5 --- /dev/null +++ b/sbt/src/sbt-test/dependency-graph/toFileSubTask/expected/licenses.txt @@ -0,0 +1,9 @@ +No license specified + org.example:blubber_2.12:0.1 + +Apache-2.0 + org.typelevel:cats-effect_2.12:2.2.0 + +MIT + org.typelevel:cats-kernel_2.12:2.2.0 + org.typelevel:cats-core_2.12:2.2.0 \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-graph/toFileSubTask/expected/list.txt b/sbt/src/sbt-test/dependency-graph/toFileSubTask/expected/list.txt new file mode 100644 index 000000000..1a356d64b --- /dev/null +++ b/sbt/src/sbt-test/dependency-graph/toFileSubTask/expected/list.txt @@ -0,0 +1,4 @@ +org.example:blubber_2.12:0.1 +org.typelevel:cats-core_2.12:2.2.0 +org.typelevel:cats-effect_2.12:2.2.0 +org.typelevel:cats-kernel_2.12:2.2.0 \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-graph/toFileSubTask/expected/stats.txt b/sbt/src/sbt-test/dependency-graph/toFileSubTask/expected/stats.txt new file mode 100644 index 000000000..3f3c415f0 --- /dev/null +++ b/sbt/src/sbt-test/dependency-graph/toFileSubTask/expected/stats.txt @@ -0,0 +1,12 @@ + TotSize JarSize #TDe #Dep Module + 11.177 MB ------- MB 3 1 org.example:blubber_2.12:0.1 + 11.177 MB 1.185 MB 2 1 org.typelevel:cats-effect_2.12:2.2.0 + 9.992 MB 5.034 MB 1 1 org.typelevel:cats-core_2.12:2.2.0 + 4.958 MB 4.958 MB 0 0 org.typelevel:cats-kernel_2.12:2.2.0 + +Columns are + - Jar-Size including dependencies + - Jar-Size + - Number of transitive dependencies + - Number of direct dependencies + - ModuleID \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-graph/toFileSubTask/expected/tree.txt b/sbt/src/sbt-test/dependency-graph/toFileSubTask/expected/tree.txt new file mode 100644 index 000000000..d639a0acb --- /dev/null +++ b/sbt/src/sbt-test/dependency-graph/toFileSubTask/expected/tree.txt @@ -0,0 +1,5 @@ +org.example:blubber_2.12:0.1 [S] + +-org.typelevel:cats-effect_2.12:2.2.0 [S] + +-org.typelevel:cats-core_2.12:2.2.0 [S] + +-org.typelevel:cats-kernel_2.12:2.2.0 [S] + \ No newline at end of file diff --git a/sbt/src/sbt-test/dependency-graph/toFileSubTask/test b/sbt/src/sbt-test/dependency-graph/toFileSubTask/test new file mode 100644 index 000000000..b905a41b8 --- /dev/null +++ b/sbt/src/sbt-test/dependency-graph/toFileSubTask/test @@ -0,0 +1,5 @@ +> dependencyTree/toFile target/tree.txt +> dependencyList/toFile target/list.txt +> dependencyStats/toFile target/stats.txt +> dependencyLicenseInfo/toFile target/licenses.txt +> check diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn-without-previous-initialization/build.sbt b/sbt/src/sbt-test/dependency-graph/whatDependsOn-without-previous-initialization/build.sbt similarity index 98% rename from sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn-without-previous-initialization/build.sbt rename to sbt/src/sbt-test/dependency-graph/whatDependsOn-without-previous-initialization/build.sbt index 92bb3b2dd..0586054cd 100644 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn-without-previous-initialization/build.sbt +++ b/sbt/src/sbt-test/dependency-graph/whatDependsOn-without-previous-initialization/build.sbt @@ -1,3 +1,5 @@ +ThisBuild / useCoursier := false + version := "0.1.0-SNAPSHOT" organization := "default" diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn-without-previous-initialization/test b/sbt/src/sbt-test/dependency-graph/whatDependsOn-without-previous-initialization/test similarity index 100% rename from sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn-without-previous-initialization/test rename to sbt/src/sbt-test/dependency-graph/whatDependsOn-without-previous-initialization/test diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn/build.sbt b/sbt/src/sbt-test/dependency-graph/whatDependsOn/build.sbt similarity index 58% rename from sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn/build.sbt rename to sbt/src/sbt-test/dependency-graph/whatDependsOn/build.sbt index 19c9108a1..8b3a0d5e1 100644 --- a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn/build.sbt +++ b/sbt/src/sbt-test/dependency-graph/whatDependsOn/build.sbt @@ -1,6 +1,7 @@ -version := "0.1.0-SNAPSHOT" +ThisBuild / version := "0.1.0-SNAPSHOT" +ThisBuild / scalaVersion := "2.9.1" -scalaVersion := "2.9.1" +name := "whatDependsOn" resolvers += "typesafe maven" at "https://repo.typesafe.com/typesafe/maven-releases/" @@ -18,18 +19,18 @@ check := { val withVersion = (whatDependsOn in Compile) - .toTask(" org.codehaus.jackson jackson-core-asl 1.9.11") + .toTask(" org.codehaus.jackson jackson-core-asl 1.9.10") .value val expectedGraphWithVersion = - """org.codehaus.jackson:jackson-core-asl:1.9.11 + """org.codehaus.jackson:jackson-core-asl:1.9.10 | +-com.codahale:jerkson_2.9.1:0.5.0 [S] - | | +-default:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] + | | +-whatdependson:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] | | - | +-org.codehaus.jackson:jackson-mapper-asl:1.9.11 + | +-org.codehaus.jackson:jackson-mapper-asl:1.9.10 | +-com.codahale:jerkson_2.9.1:0.5.0 [S] - | | +-default:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] + | | +-whatdependson:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] | | - | +-default:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] + | +-whatdependson:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] | """.stripMargin checkOutput(withVersion, expectedGraphWithVersion) @@ -39,14 +40,15 @@ check := { .toTask(" org.codehaus.jackson jackson-mapper-asl") .value val expectedGraphWithoutVersion = - """org.codehaus.jackson:jackson-mapper-asl:1.9.11 + """org.codehaus.jackson:jackson-mapper-asl:1.9.10 | +-com.codahale:jerkson_2.9.1:0.5.0 [S] - | | +-default:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] + | | +-whatdependson:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] | | - | +-default:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] + | +-whatdependson: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] + |org.codehaus.jackson:jackson-mapper-asl:[1.9.0,2.0.0) (evicted by: 1.9.10) + | +-com.codahale:jerkson_2.9.1:0.5.0 [S] + | +-whatdependson:whatdependson_2.9.1:0.1.0-SNAPSHOT [S] | """.stripMargin checkOutput(withoutVersion, expectedGraphWithoutVersion) } diff --git a/sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn/test b/sbt/src/sbt-test/dependency-graph/whatDependsOn/test similarity index 100% rename from sbt-dependency-graph/src/sbt-test/sbt-dependency-graph/whatDependsOn/test rename to sbt/src/sbt-test/dependency-graph/whatDependsOn/test