From 8591a5adaeac38abaaf51ac3409d0f702ea506d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20Mass=C3=A9?= Date: Mon, 16 Oct 2017 13:32:54 +0200 Subject: [PATCH 1/2] Bump to sbt 0.13.16, drop support for sbt 0.12.x --- README.md | 23 +- build.sbt | 15 +- project/Helpers.scala | 16 -- project/build.properties | 2 +- project/pgp.sbt | 2 +- publish.sbt | 29 ++- .../sbt/graph/DependencyGraphSettings.scala | 218 ++++++++++-------- .../sbt/graph/backend/SbtUpdateReport.scala | 3 + .../sbt-dependency-graph/build.properties | 2 +- .../ignoreScalaLibrary/build.sbt | 26 ++- .../intervalRangedVersions/build.sbt | 17 +- .../showMissingUpdates/build.sbt | 8 +- .../testDotFileGeneration/build.sbt | 65 ++++++ .../testDotFileGeneration/project/Build.scala | 68 ------ 14 files changed, 262 insertions(+), 232 deletions(-) delete mode 100644 project/Helpers.scala create mode 100644 src/sbt-test/sbt-dependency-graph/testDotFileGeneration/build.sbt delete mode 100644 src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala diff --git a/README.md b/README.md index 1e86e5f96..f8893990b 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,6 @@ Visualize your project's dependencies. -## Preliminaries - -The plugin works best with sbt >= 0.13.6. See the [compatibility notes](#compatibility-notes) to use this plugin with an older version of sbt. - ## Usage Instructions Since sbt-dependency-graph is an informational tool rather than one that changes your build, you will more than likely wish to @@ -20,8 +16,6 @@ addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.2") 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. - ## Main Tasks * `dependencyTree`: Shows an ASCII tree representation of the project's dependencies @@ -66,20 +60,6 @@ dependencyDotFile := file("dependencies.dot") //render dot file to `./dependenci * [#19]: There's an unfixed bug with graph generation for particular layouts. Workaround: Use `dependency-tree` instead of `dependency-graph`. - * [#39]: When using sbt-dependency-graph with sbt < 0.13.6. - -## Compatibility notes - - * sbt < 0.13.6: The plugin will fall back on the old ivy report XML backend which suffers from [#39]. - * sbt < 0.13.5: Old versions of sbt have no `AutoPlugin` support, you need to add - -```scala -net.virtualvoid.sbt.graph.DependencyGraphSettings.graphSettings -``` - - to your `build.sbt` or (`~/.sbt/0.13/user.sbt` for global configuration) to enable the plugin. - * sbt <= 0.12.x: Old versions of sbt are not actively supported any more. Please use the old version from the [0.7 branch](https://github.com/jrudolph/sbt-dependency-graph/tree/0.7). - ## License @@ -87,5 +67,4 @@ Published under the [Apache License 2.0](http://en.wikipedia.org/wiki/Apache_lic [global plugin]: http://www.scala-sbt.org/0.13/tutorial/Using-Plugins.html#Global+plugins [global build configuration]: http://www.scala-sbt.org/0.13/docs/Global-Settings.html -[#19]: https://github.com/jrudolph/sbt-dependency-graph/issues/19 -[#39]: https://github.com/jrudolph/sbt-dependency-graph/issues/39 +[#19]: https://github.com/jrudolph/sbt-dependency-graph/issues/19 \ No newline at end of file diff --git a/build.sbt b/build.sbt index 6b4943943..3659705f3 100644 --- a/build.sbt +++ b/build.sbt @@ -1,9 +1,16 @@ ScriptedPlugin.scriptedSettings -libraryDependencies += "com.github.mdr" %% "ascii-graphs" % "0.0.3" +libraryDependencies ++= Seq( + "com.github.mdr" %% "ascii-graphs" % "0.0.3", + "org.specs2" %% "specs2" % "2.3.11" % Test +) -libraryDependencies += "org.specs2" %% "specs2" % "2.3.11" % "test" - -scalacOptions ++= Seq("-deprecation", "-unchecked") +scalacOptions ++= Seq( + "-deprecation", + "-encoding", + "UTF-8", + "-feature", + "-unchecked" +) ScalariformSupport.formatSettings diff --git a/project/Helpers.scala b/project/Helpers.scala deleted file mode 100644 index 4c426be62..000000000 --- a/project/Helpers.scala +++ /dev/null @@ -1,16 +0,0 @@ -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/build.properties b/project/build.properties index a6e117b61..406a7d255 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.8 +sbt.version=0.13.16 \ No newline at end of file diff --git a/project/pgp.sbt b/project/pgp.sbt index 4ce4d9ed4..2efcc4b69 100644 --- a/project/pgp.sbt +++ b/project/pgp.sbt @@ -1 +1 @@ -addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") +addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.0") diff --git a/publish.sbt b/publish.sbt index 9d44a4f3a..65b3c0489 100644 --- a/publish.sbt +++ b/publish.sbt @@ -1,7 +1,11 @@ -publishTo <<= version { v: String => +publishTo := { val nexus = "https://oss.sonatype.org/" - if (v.trim.endsWith("SNAPSHOT")) Some("snapshots" at nexus + "content/repositories/snapshots") - else Some("releases" at nexus + "service/local/staging/deploy/maven2") + if (version.value.trim.endsWith("SNAPSHOT")) { + Some("snapshots" at nexus + "content/repositories/snapshots") + } + else { + Some("releases" at nexus + "service/local/staging/deploy/maven2") + } } publishMavenStyle := true @@ -10,9 +14,20 @@ publishArtifact in Test := false pomIncludeRepository := { _ => false } -pomExtra := - Helpers.generatePomExtra("git@github.com:jrudolph/sbt-dependency-graph.git", - "scm:git:git@github.com:jrudolph/sbt-dependency-graph.git", - "jrudolph", "Johannes Rudolph") +scmInfo := Some( + ScmInfo( + browseUrl = url("https://github.com/jrudolph/sbt-dependency-graph"), + connection = "scm:git:git@github.com:jrudolph/sbt-dependency-graph.git" + ) +) + +developers := List( + Developer( + "jrudolph", + "Johannes Rudolph", + "johannes.rudolph@gmail.com", + url("http://virtual-void.net") + ) +) useGpg := true diff --git a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala index ab0fd6779..5c66eb37f 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -29,139 +29,154 @@ import net.virtualvoid.sbt.graph.backend.{ IvyReport, SbtUpdateReport } import net.virtualvoid.sbt.graph.rendering.DagreHTML import net.virtualvoid.sbt.graph.util.IOUtil +import scala.language.reflectiveCalls + object DependencyGraphSettings { import DependencyGraphKeys._ import ModuleGraphProtocol._ def graphSettings = Seq( - ivyReportFunction <<= ivyReportFunctionTask, - updateConfiguration in ignoreMissingUpdate <<= updateConfiguration(config ⇒ new UpdateConfiguration(config.retrieve, true, config.logging)), + ivyReportFunction := ivyReportFunctionTask.value, + updateConfiguration in ignoreMissingUpdate := { + val config = updateConfiguration.value + new UpdateConfiguration(config.retrieve, true, config.logging) + }, ignoreMissingUpdateT, filterScalaLibrary in Global := true) ++ Seq(Compile, Test, IntegrationTest, Runtime, Provided, Optional).flatMap(ivyReportForConfig) def ivyReportForConfig(config: Configuration) = inConfig(config)(Seq( - ivyReport <<= ivyReportFunction map (_(config.toString)) dependsOn (ignoreMissingUpdate), - crossProjectId <<= (scalaVersion, scalaBinaryVersion, projectID)((sV, sBV, id) ⇒ CrossVersion(sV, sBV)(id)), - moduleGraphSbt <<= moduleGraphSbtTask, - moduleGraphIvyReport <<= moduleGraphIvyReportTask, - moduleGraph <<= (sbtVersion, moduleGraphSbt, moduleGraphIvyReport) { (version, graphSbt, graphIvy) ⇒ - version match { - case Version(0, 13, x, _) if x >= 6 ⇒ graphSbt - case _ ⇒ graphIvy - } + ivyReport := { + Def.task { + ivyReportFunction.value.apply(config.toString) + }.dependsOn(ignoreMissingUpdate) + }.value, + crossProjectId := sbt.CrossVersion( + scalaVersion.value, + scalaBinaryVersion.value)(projectID.value), + moduleGraphSbt := { + val update = ignoreMissingUpdate.value + val root = crossProjectId.value + val config = configuration.value + + update.configuration(config.name).map(report ⇒ + SbtUpdateReport.fromConfigurationReport(report, root)).getOrElse(ModuleGraph.empty) }, - moduleGraph <<= (scalaVersion, moduleGraph, filterScalaLibrary) map { (scalaV, graph, filter) ⇒ + moduleGraphIvyReport := { + IvyReport.fromReportFile(absoluteReportPath(ivyReport.value)) + }, + moduleGraph := { + val graphSbt = moduleGraphSbt.value + val graphIvy = moduleGraphIvyReport.value + val filter = filterScalaLibrary.value + val scalaV = scalaVersion.value + + val graph = + sbtVersion.value match { + case Version(0, 13, x, _) if x >= 6 ⇒ graphSbt + case Version(1, _, _, _) ⇒ graphSbt + case _ ⇒ graphIvy + } + if (filter) GraphTransformations.ignoreScalaLibrary(scalaV, graph) else graph }, - moduleGraphStore <<= moduleGraph storeAs moduleGraphStore triggeredBy moduleGraph, - asciiGraph <<= moduleGraph map rendering.AsciiGraph.asciiGraph, - dependencyGraph <<= InputTask(shouldForceParser) { force ⇒ - (force, moduleGraph, streams) map { (force, graph, streams) ⇒ - if (force || graph.nodes.size < 15) { - streams.log.info(rendering.AsciiGraph.asciiGraph(graph)) - streams.log.info("\n\n") - streams.log.info("Note: The old tree layout is still available by using `dependency-tree`") - } else { - streams.log.info(rendering.AsciiTree.asciiTree(graph)) + moduleGraphStore := (moduleGraph storeAs moduleGraphStore triggeredBy moduleGraph).value, + asciiGraph := rendering.AsciiGraph.asciiGraph(moduleGraph.value), + dependencyGraph := { + val force = shouldForceParser.parsed + val log = streams.value.log + val graph = moduleGraph.value - if (!force) { - streams.log.info("\n") - streams.log.info("Note: The graph was estimated to be too big to display (> 15 nodes). Use `sbt 'dependency-graph --force'` (with the single quotes) to force graph display.") - } - } + if (force || graph.nodes.size < 15) { + log.info(rendering.AsciiGraph.asciiGraph(graph)) + log.info("\n\n") + log.info("Note: The old tree layout is still available by using `dependency-tree`") + } + + log.info(rendering.AsciiTree.asciiTree(graph)) + + 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.") } }, - asciiTree <<= moduleGraph map rendering.AsciiTree.asciiTree, - dependencyTree <<= print(asciiTree), - dependencyGraphMLFile <<= target / "dependencies-%s.graphml".format(config.toString), - dependencyGraphML <<= dependencyGraphMLTask, - dependencyDotFile <<= target / "dependencies-%s.dot".format(config.toString), - dependencyDotString <<= dependencyDotStringTask, - dependencyDot <<= writeToFile(dependencyDotString, dependencyDotFile), - dependencyBrowseGraphTarget <<= target / "browse-dependency-graph", - dependencyBrowseGraphHTML <<= browseGraphHTMLTask, - dependencyBrowseGraph <<= (dependencyBrowseGraphHTML, streams).map { (uri, streams) ⇒ - streams.log.info("Opening in browser...") + asciiTree := rendering.AsciiTree.asciiTree(moduleGraph.value), + dependencyTree := print(asciiTree).value, + dependencyGraphMLFile := { target.value / "dependencies-%s.graphml".format(config.toString) }, + dependencyGraphML := dependencyGraphMLTask.value, + dependencyDotFile := { target.value / "dependencies-%s.dot".format(config.toString) }, + dependencyDotString := rendering.DOT.dotGraph(moduleGraph.value, dependencyDotHeader.value, dependencyDotNodeLabel.value, rendering.DOT.AngleBrackets), + dependencyDot := writeToFile(dependencyDotString, dependencyDotFile).value, + dependencyBrowseGraphTarget := { target.value / "browse-dependency-graph" }, + dependencyBrowseGraphHTML := browseGraphHTMLTask.value, + dependencyBrowseGraph := { + val uri = dependencyBrowseGraphHTML.value + streams.value.log.info("Opening in browser...") java.awt.Desktop.getDesktop.browse(uri) uri }, - dependencyList <<= printFromGraph(rendering.FlatList.render(_, _.id.idString)), - dependencyStats <<= printFromGraph(rendering.Statistics.renderModuleStatsList), - dependencyDotHeader := """digraph "dependency-graph" { - | graph[rankdir="LR"] - | edge [ - | arrowtail="none" - | ]""".stripMargin, + dependencyList := printFromGraph(rendering.FlatList.render(_, _.id.idString)).value, + dependencyStats := printFromGraph(rendering.Statistics.renderModuleStatsList).value, + dependencyDotHeader := { + """|digraph "dependency-graph" { + | graph[rankdir="LR"] + | edge [ + | arrowtail="none" + | ]""".stripMargin + }, dependencyDotNodeLabel := { (organisation: String, name: String, version: String) ⇒ """%s
%s
%s""".format(organisation, name, version) }, - whatDependsOn <<= InputTask(artifactIdParser) { module ⇒ - (module, streams, moduleGraph) map { (module, streams, graph) ⇒ - streams.log.info(rendering.AsciiTree.asciiTree(GraphTransformations.reverseGraphStartingAt(graph, module))) - } + whatDependsOn := { + val module = artifactIdParser.parsed + streams.value.log.info(rendering.AsciiTree.asciiTree(GraphTransformations.reverseGraphStartingAt(moduleGraph.value, module))) }, - licenseInfo <<= (moduleGraph, streams) map showLicenseInfo)) + licenseInfo := showLicenseInfo(moduleGraph.value, streams.value))) - def ivyReportFunctionTask = - (sbtVersion, target, projectID, ivyModule, appConfiguration, streams) map { (sbtV, target, projectID, ivyModule, config, streams) ⇒ - sbtV match { - case Version(0, min, fix, _) if min > 12 || (min == 12 && fix >= 3) ⇒ - (c: String) ⇒ file("%s/resolution-cache/reports/%s-%s-%s.xml".format(target, projectID.organization, crossName(ivyModule), c)) - case Version(0, min, fix, _) if min == 12 && fix >= 1 && fix < 3 ⇒ - ivyModule.withModule(streams.log) { (i, moduleDesc, _) ⇒ - val id = ResolveOptions.getDefaultResolveId(moduleDesc) - (c: String) ⇒ file("%s/resolution-cache/reports/%s/%s-resolved.xml" format (target, id, c)) - } - case _ ⇒ - val home = config.provider.scalaProvider.launcher.ivyHome - (c: String) ⇒ file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c)) - } + def ivyReportFunctionTask = Def.task { + val crossTarget = Keys.crossTarget.value + val projectID = Keys.projectID.value + val ivyModule = Keys.ivyModule.value + + (config: String) ⇒ { + val org = projectID.organization + val name = crossName(ivyModule) + file(s"${crossTarget}/resolution-cache/reports/$org-$name-$config.xml") } - - def moduleGraphIvyReportTask = ivyReport map (absoluteReportPath.andThen(IvyReport.fromReportFile)) - def moduleGraphSbtTask = - (ignoreMissingUpdate, crossProjectId, configuration) map { (update, root, config) ⇒ - update.configuration(config.name).map(report ⇒ SbtUpdateReport.fromConfigurationReport(report, root)).getOrElse(ModuleGraph.empty) - } - - def printAsciiGraphTask = - (streams, asciiGraph) map (_.log.info(_)) + } def dependencyGraphMLTask = - (moduleGraph, dependencyGraphMLFile, streams) map { (graph, resultFile, streams) ⇒ - rendering.GraphML.saveAsGraphML(graph, resultFile.getAbsolutePath) - streams.log.info("Wrote dependency graph to '%s'" format resultFile) + Def.task { + val resultFile = dependencyGraphMLFile.value + rendering.GraphML.saveAsGraphML(moduleGraph.value, resultFile.getAbsolutePath) + streams.value.log.info("Wrote dependency graph to '%s'" format resultFile) resultFile } - def dependencyDotStringTask = - (moduleGraph, dependencyDotHeader, dependencyDotNodeLabel).map { - (graph, dotHead, nodeLabel) ⇒ rendering.DOT.dotGraph(graph, dotHead, nodeLabel, rendering.DOT.AngleBrackets) - } def browseGraphHTMLTask = - (moduleGraph, dependencyDotHeader, dependencyDotNodeLabel, dependencyBrowseGraphTarget, streams).map { (graph, dotHead, nodeLabel, target, streams) ⇒ - val dotGraph = rendering.DOT.dotGraph(graph, dotHead, nodeLabel, rendering.DOT.LabelTypeHtml) - val link = DagreHTML.createLink(dotGraph, target) - streams.log.info(s"HTML graph written to $link") + Def.task { + val dotGraph = rendering.DOT.dotGraph(moduleGraph.value, dependencyDotHeader.value, dependencyDotNodeLabel.value, rendering.DOT.LabelTypeHtml) + val link = DagreHTML.createLink(dotGraph, target.value) + streams.value.log.info(s"HTML graph written to $link") link } def writeToFile(dataTask: TaskKey[String], fileTask: SettingKey[File]) = - (dataTask, fileTask, streams).map { (data, outFile, streams) ⇒ - IOUtil.writeToFile(data, outFile) + Def.task { + val outFile = fileTask.value + IOUtil.writeToFile(dataTask.value, outFile) - streams.log.info("Wrote dependency graph to '%s'" format outFile) + streams.value.log.info("Wrote dependency graph to '%s'" format outFile) outFile } def absoluteReportPath = (file: File) ⇒ file.getAbsolutePath def print(key: TaskKey[String]) = - (streams, key) map (_.log.info(_)) + Def.task { streams.value.log.info(key.value) } def printFromGraph(f: ModuleGraph ⇒ String) = - (streams, moduleGraph) map ((streams, graph) ⇒ streams.log.info(f(graph))) + Def.task { streams.value.log.info(f(moduleGraph.value)) } def showLicenseInfo(graph: ModuleGraph, streams: TaskStreams) { val output = @@ -180,7 +195,7 @@ object DependencyGraphSettings { (Space ~> token("--force")).?.map(_.isDefined) } - val artifactIdParser: Initialize[State ⇒ Parser[ModuleId]] = + val artifactIdParser: Def.Initialize[State ⇒ Parser[ModuleId]] = resolvedScoped { ctx ⇒ (state: State) ⇒ val graph = loadFromContext(moduleGraphStore, ctx, state) getOrElse ModuleGraph(Nil, Nil) @@ -222,7 +237,7 @@ object DependencyGraphSettings { * to ignore missing artifacts. */ def ignoreMissingUpdateT = - ignoreMissingUpdate <<= Def.task { + ignoreMissingUpdate := Def.task { val depsUpdated = transitiveUpdate.value.exists(!_.stats.cached) val isRoot = executionRoots.value contains resolvedScoped.value val s = streams.value @@ -237,13 +252,26 @@ object DependencyGraphSettings { 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 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) - } -} + + Classpaths.cachedUpdate( + cacheFile = s.cacheDirectory, + label = show, + module = ivyModule.value, + config = (updateConfiguration in ignoreMissingUpdate).value, + transform = transform, + skip = (skip in update).value, + force = isRoot, + depsUpdated = depsUpdated, + log = s.log) + }.value +} \ No newline at end of file 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 f5596269a..9a8c4787a 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/backend/SbtUpdateReport.scala @@ -19,6 +19,9 @@ package backend import sbt._ +import scala.language.implicitConversions +import scala.language.reflectiveCalls + object SbtUpdateReport { type OrganizationArtifactReport = { def modules: Seq[ModuleReport] diff --git a/src/sbt-test/sbt-dependency-graph/build.properties b/src/sbt-test/sbt-dependency-graph/build.properties index df58110af..406a7d255 100644 --- a/src/sbt-test/sbt-dependency-graph/build.properties +++ b/src/sbt-test/sbt-dependency-graph/build.properties @@ -1 +1 @@ -sbt.version=0.13.6 \ No newline at end of file +sbt.version=0.13.16 \ 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 8c47bfc25..bb28eae3d 100644 --- a/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt +++ b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/build.sbt @@ -1,21 +1,27 @@ -scalaVersion := "2.9.2" +scalaVersion := "2.12.3" libraryDependencies ++= Seq( "org.slf4j" % "slf4j-api" % "1.7.2", "ch.qos.logback" % "logback-classic" % "1.0.7" ) -TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, graph) => +TaskKey[Unit]("check") := { + val report = (ivyReport in Test).value + val graph = (asciiTree in Test).value + val scalaV = scalaVersion.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] - | +-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 + s"""|default:default-e95e05_${scalaV}: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) + | | +-org.slf4j:slf4j-api:1.7.2 + | | + | +-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/intervalRangedVersions/build.sbt b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt index 2cec07ae8..4ec5f7d51 100644 --- a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt +++ b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/build.sbt @@ -6,17 +6,24 @@ libraryDependencies ++= Seq( "com.codahale" % "jerkson_2.9.1" % "0.5.0" ) -TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, graph) => +TaskKey[Unit]("check") := { + val report = (ivyReport in Test).value + val graph = (asciiTree in Test).value + def sanitize(str: String): String = str.split('\n').drop(1).map(_.trim).mkString("\n") + + // latest: 1.9.13 + // http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.codehaus.jackson%22%20AND%20a%3A%22jackson-core-asl%22 + val expectedGraph = """default:default-dbc48d_2.9.2:0.1-SNAPSHOT [S] | +-com.codahale:jerkson_2.9.1:0.5.0 [S] - | +-org.codehaus.jackson:jackson-core-asl:1.9.13 - | +-org.codehaus.jackson:jackson-mapper-asl:1.9.13 - | +-org.codehaus.jackson:jackson-core-asl:1.9.13 + | +-org.codehaus.jackson:jackson-core-asl:1.9.11 + | +-org.codehaus.jackson:jackson-mapper-asl:1.9.11 + | +-org.codehaus.jackson:jackson-core-asl:1.9.11 | """.stripMargin IO.writeLines(file("/tmp/blib"), sanitize(graph).split("\n")) IO.writeLines(file("/tmp/blub"), sanitize(expectedGraph).split("\n")) require(sanitize(graph) == sanitize(expectedGraph), "Graph for report %s was '\n%s' but should have been '\n%s'" format (report, sanitize(graph), sanitize(expectedGraph))) () -} +} \ 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 6ca4b0313..86455cc25 100644 --- a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt +++ b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt @@ -3,8 +3,12 @@ scalaVersion := "2.9.2" libraryDependencies += "at.blub" % "blib" % "1.2.3" % "test" -TaskKey[Unit]("check") <<= (ivyReport in Test, asciiTree in Test) map { (report, graph) => - def sanitize(str: String): String = str.split('\n').drop(1).mkString("\n") +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-91180e_2.9.2:0.1-SNAPSHOT | +-%sat.blub:blib:1.2.3 (error: not found)%s diff --git a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/build.sbt b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/build.sbt new file mode 100644 index 000000000..6f3281886 --- /dev/null +++ b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/build.sbt @@ -0,0 +1,65 @@ +import collection.mutable.ListBuffer + +def defaultSettings = Seq(scalaVersion := "2.12.3") + +lazy val `just-a-transitive-dependency-endpoint` = + project + .in(file("a")) + .settings(defaultSettings) + +lazy val `just-a-transitive-dependency` = + project + .in(file("b")) + .settings(defaultSettings) + .dependsOn(`just-a-transitive-dependency-endpoint`) + +lazy val `just-a-dependency` = + project + .in(file("c")) + .settings(defaultSettings) + +lazy val `test-dot-file-generation` = + project + .in(file("d")) + .settings(defaultSettings) + .settings( + TaskKey[Unit]("check") := { + val dotFile = (dependencyDot in Compile).value + val scalaV = scalaBinaryVersion.value + + val expectedGraph = + s"""|digraph "dependency-graph" { + | graph[rankdir="LR"] + | edge [ + | arrowtail="none" + | ] + | "test-dot-file-generation:test-dot-file-generation_${scalaV}:0.1-SNAPSHOT"[label=test-dot-file-generation_${scalaV}
0.1-SNAPSHOT> style=""] + | "just-a-transitive-dependency:just-a-transitive-dependency_${scalaV}:0.1-SNAPSHOT"[label=just-a-transitive-dependency_${scalaV}
0.1-SNAPSHOT> style=""] + | "just-a-transitive-dependency-endpoint:just-a-transitive-dependency-endpoint_${scalaV}:0.1-SNAPSHOT"[label=just-a-transitive-dependency-endpoint_${scalaV}
0.1-SNAPSHOT> style=""] + | "just-a-dependency:just-a-dependency_${scalaV}:0.1-SNAPSHOT"[label=just-a-dependency_${scalaV}
0.1-SNAPSHOT> style=""] + | "test-dot-file-generation:test-dot-file-generation_${scalaV}:0.1-SNAPSHOT" -> "just-a-transitive-dependency:just-a-transitive-dependency_${scalaV}:0.1-SNAPSHOT" + | "just-a-transitive-dependency:just-a-transitive-dependency_${scalaV}:0.1-SNAPSHOT" -> "just-a-transitive-dependency-endpoint:just-a-transitive-dependency-endpoint_${scalaV}:0.1-SNAPSHOT" + | "test-dot-file-generation:test-dot-file-generation_${scalaV}:0.1-SNAPSHOT" -> "just-a-dependency:just-a-dependency_${scalaV}: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(`just-a-dependency`, `just-a-transitive-dependency`) + +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/Build.scala b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala deleted file mode 100644 index d5081feb1..000000000 --- a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/Build.scala +++ /dev/null @@ -1,68 +0,0 @@ -import collection.mutable.ListBuffer - -import sbt._ -import sbt.Keys._ - -import net.virtualvoid.sbt.graph.DependencyGraphKeys._ - -object Build extends sbt.Build { - - def defaultSettings = - Seq(scalaVersion := "2.9.2") - - lazy val justATransiviteDependencyEndpointProject = - Project("just-a-transitive-dependency-endpoint", file("a")) - .settings(defaultSettings: _*) - - lazy val justATransitiveDependencyProject = - Project("just-a-transitive-dependency", file("b")) - .settings(defaultSettings: _*) - .dependsOn(justATransiviteDependencyEndpointProject) - - lazy val justADependencyProject = - Project("just-a-dependency", file("c")) - .settings(defaultSettings: _*) - - lazy val test_project = - Project("test-dot-file-generation", file("d")) - .settings(defaultSettings: _*) - .settings( - TaskKey[Unit]("check") <<= (dependencyDot in Compile) map { (dotFile) => - val expectedGraph = - """digraph "dependency-graph" { - | graph[rankdir="LR"] - | edge [ - | arrowtail="none" - | ] - | "test-dot-file-generation:test-dot-file-generation_2.9.2:0.1-SNAPSHOT"[label=test-dot-file-generation_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 - } -} From 66f801bf92a34a7ffbc045b3875d343ee09ff617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20Mass=C3=A9?= Date: Tue, 17 Oct 2017 00:06:55 +0200 Subject: [PATCH 2/2] Compiles with sbt 1.0 and sbt 0.13 1. ascii-graphs We need a 2.12 version of ascii-graphs. The last commit to the project is in June 2013 (https://github.com/mdr/ascii-graphs/graphs/contributors). We are now in October 2017. I opened a PR (https://github.com/mdr/ascii-graphs/pull/11) but I don't expect any progress on this front. We can maintain a fork or drop ascii-graphs. 2. ignoreMissingUpdate ignoreMissingUpdate is a tricky one. Here is some explanation: we need to duplicate the updateTask in sbt it's define as: ```scala def updateTask: Initialize[Task[UpdateReport]] = Def.task { // ... val uc0 = updateConfiguration.value // ... } ``` since it's not scoped to our task (ex: `updateConfiguration in ignoreMissingUpdate`) we cannot just do ```scala updateConfiguration in ignoreMissingUpdate := { updateConfiguration.value.withMissingOk(true) } ``` For example, the following example yield `"u2: false" ``` val update2 = TaskKey[Unit]("update2", "...") val update2Configuration = SettingKey[Boolean]("...") update2 := Def.task { val u2 = (update2Configuration in update2).value println(s"u2: $u2") }.value update2Configuration := false update2Configuration in update2 := true ``` 3. cross publishing We can use the ^ operator to publish. For example: `sbt "^ publish"` to publish for both sbt 0.13 and 1.0. --- .travis.yml | 10 ++- build.sbt | 15 +++- .../scala/net/virtualvoid/graph/compat.scala | 25 +++++++ .../scala/net/virtualvoid/graph/model.scala | 26 +++++++ .../scala-sbt-0.13/scala/sbt/compat.scala | 48 ++++++++++++ .../scala/net/virtualvoid/graph/compat.scala | 19 +++++ .../scala/net/virtualvoid/graph/model.scala | 70 ++++++++++++++++++ src/main/scala-sbt-1.0/scala/sbt/compat.scala | 62 ++++++++++++++++ .../sbt/graph/DependencyGraphSettings.scala | 74 +++++-------------- .../net/virtualvoid/sbt/graph/model.scala | 10 +-- .../sbt/graph/rendering/AsciiGraph.scala | 7 +- src/main/scala/sbt/SbtAccess.scala | 2 +- .../project/build.properties | 1 - .../project/build.properties | 1 - .../showMissingUpdates/build.sbt | 5 +- .../project/build.properties | 1 - .../project/build.properties | 1 - 17 files changed, 300 insertions(+), 77 deletions(-) create mode 100644 src/main/scala-sbt-0.13/scala/net/virtualvoid/graph/compat.scala create mode 100644 src/main/scala-sbt-0.13/scala/net/virtualvoid/graph/model.scala create mode 100644 src/main/scala-sbt-0.13/scala/sbt/compat.scala create mode 100644 src/main/scala-sbt-1.0/scala/net/virtualvoid/graph/compat.scala create mode 100644 src/main/scala-sbt-1.0/scala/net/virtualvoid/graph/model.scala create mode 100644 src/main/scala-sbt-1.0/scala/sbt/compat.scala delete mode 120000 src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/build.properties delete mode 120000 src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/build.properties delete mode 120000 src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/build.properties delete mode 120000 src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.properties diff --git a/.travis.yml b/.travis.yml index 30f872264..c0d5bcc7b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,12 @@ sudo: false language: scala jdk: oraclejdk7 script: -- sbt test scripted +# pending https://github.com/mdr/ascii-graphs/pull/11 +- git clone git://github.com/MasseGuillaume/ascii-graphs.git +- pushd ascii-graphs +- git checkout 2.12 +- sbt "+ publishLocal" +- popd + +- sbt ";^test ;^scripted" + diff --git a/build.sbt b/build.sbt index 3659705f3..be7047aa0 100644 --- a/build.sbt +++ b/build.sbt @@ -1,10 +1,18 @@ ScriptedPlugin.scriptedSettings libraryDependencies ++= Seq( - "com.github.mdr" %% "ascii-graphs" % "0.0.3", - "org.specs2" %% "specs2" % "2.3.11" % Test + "com.github.mdr" %% "ascii-graphs" % "0.0.7-SNAPSHOT", + "org.specs2" %% "specs2-core" % "3.9.5" % Test ) +libraryDependencies += Defaults.sbtPluginExtra( + "com.dwijnand" % "sbt-compat" % "1.1.0", + (sbtBinaryVersion in pluginCrossBuild).value, + (scalaBinaryVersion in update).value +) + +crossSbtVersions := List("0.13.16", "1.0.2") + scalacOptions ++= Seq( "-deprecation", "-encoding", @@ -14,3 +22,6 @@ scalacOptions ++= Seq( ) ScalariformSupport.formatSettings + +addCommandAlias("c1", ";cls;^^ 1.0.2;compile") +addCommandAlias("c0", ";cls;^^ 0.13.16;compile") \ No newline at end of file diff --git a/src/main/scala-sbt-0.13/scala/net/virtualvoid/graph/compat.scala b/src/main/scala-sbt-0.13/scala/net/virtualvoid/graph/compat.scala new file mode 100644 index 000000000..588bcc270 --- /dev/null +++ b/src/main/scala-sbt-0.13/scala/net/virtualvoid/graph/compat.scala @@ -0,0 +1,25 @@ +package net.virtualvoid.sbt.graph + +import sbt._ +import Keys._ + +import CrossVersion._ +import DependencyGraphKeys._ + +object compat { + def convertConfig(config: sbt.Configuration): String = { + config.toString + } + +/** + * This is copied directly from sbt/main/Defaults.java and then changed to update the UpdateConfiguration + * to ignore missing artifacts. + */ + def ingnoreMissingSettings: Seq[Setting[_]] = Seq( + updateConfiguration in ignoreMissingUpdate := { + val config = updateConfiguration.value + new UpdateConfiguration(config.retrieve, true, config.logging) + }, + ignoreMissingUpdate := sbt.Compat.updateTask(ignoreMissingUpdate).value + ) +} \ No newline at end of file diff --git a/src/main/scala-sbt-0.13/scala/net/virtualvoid/graph/model.scala b/src/main/scala-sbt-0.13/scala/net/virtualvoid/graph/model.scala new file mode 100644 index 000000000..7af90cc3c --- /dev/null +++ b/src/main/scala-sbt-0.13/scala/net/virtualvoid/graph/model.scala @@ -0,0 +1,26 @@ +/* + * 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 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] = asProduct6(Module)(Module.unapply(_).get) + implicit val ModuleGraphFormat: Format[ModuleGraph] = asProduct2(ModuleGraph.apply _)(ModuleGraph.unapply(_).get) +} diff --git a/src/main/scala-sbt-0.13/scala/sbt/compat.scala b/src/main/scala-sbt-0.13/scala/sbt/compat.scala new file mode 100644 index 000000000..962f5e518 --- /dev/null +++ b/src/main/scala-sbt-0.13/scala/sbt/compat.scala @@ -0,0 +1,48 @@ +package sbt + +import Keys._ +import Def.Initialize + +import CrossVersion.partialVersion + +object Compat { + + // https://github.com/sbt/sbt/blob/e3c4db5ae80fa3e2a40b7a81bee0822e49f76aaf/main/src/main/scala/sbt/Defaults.scala#L1471 + 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 show = Reference.display(thisProjectRef.value) + + Classpaths.cachedUpdate( + cacheFile = s.cacheDirectory, + label = show, + module = ivyModule.value, + config = (updateConfiguration in task).value, + transform = transform, + skip = (skip in update).value, + force = isRoot, + depsUpdated = depsUpdated, + log = s.log) + } +} \ No newline at end of file diff --git a/src/main/scala-sbt-1.0/scala/net/virtualvoid/graph/compat.scala b/src/main/scala-sbt-1.0/scala/net/virtualvoid/graph/compat.scala new file mode 100644 index 000000000..33cddb047 --- /dev/null +++ b/src/main/scala-sbt-1.0/scala/net/virtualvoid/graph/compat.scala @@ -0,0 +1,19 @@ +package net.virtualvoid.sbt.graph + +import DependencyGraphKeys._ + +import sbt._ +import Keys._ + +object compat { + def convertConfig(config: sbt.Configuration): sbt.Configuration = { + config + } + + val ingnoreMissingSettings: Seq[Setting[_]] = Seq( + updateConfiguration in ignoreMissingUpdate := { + updateConfiguration.value.withMissingOk(true) + }, + ignoreMissingUpdate := sbt.Compat.updateTask(ignoreMissingUpdate).value + ) +} \ No newline at end of file diff --git a/src/main/scala-sbt-1.0/scala/net/virtualvoid/graph/model.scala b/src/main/scala-sbt-1.0/scala/net/virtualvoid/graph/model.scala new file mode 100644 index 000000000..c14ac8640 --- /dev/null +++ b/src/main/scala-sbt-1.0/scala/net/virtualvoid/graph/model.scala @@ -0,0 +1,70 @@ +/* + * 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 sjsonnew._, LList.:*: + +object ModuleGraphProtocol extends BasicJsonProtocol { + + implicit val ModuleIdFormat: IsoLList[ModuleId] = + LList.isoCurried( + (m: ModuleId) => + ("organisation", m.organisation) :*: + ("name", m.name) :*: + ("version", m.version) :*: + LNil + ) { case + (_, organisation) :*: + (_, name) :*: + (version, _) :*: + LNil => ModuleId(organisation, name, version) + } + + implicit val ModuleFormat: IsoLList[Module] = + LList.isoCurried( + (m: Module) => + ("id", m.id) :*: + ("license", m.license) :*: + ("extraInfo", m.extraInfo) :*: + ("evictedByVersion", m.evictedByVersion) :*: + ("jarFile", m.jarFile) :*: + ("error", m.error) :*: + LNil + ) { + case + (_, id) :*: + (_, license) :*: + (_, extraInfo) :*: + (_, evictedByVersion) :*: + (_, jarFile) :*: + (_, error) :*: + LNil => Module(id, license, extraInfo, evictedByVersion, jarFile, error) + } + + + implicit val ModuleGraphFormat: IsoLList[ModuleGraph] = + LList.isoCurried( + (g: ModuleGraph) => + ("nodes", g.nodes) :*: + ("edges", g.edges) :*: + LNil + ) { case + (_, nodes) :*: + (_, edges) :*: + LNil => ModuleGraph(nodes, edges) + } +} \ No newline at end of file diff --git a/src/main/scala-sbt-1.0/scala/sbt/compat.scala b/src/main/scala-sbt-1.0/scala/sbt/compat.scala new file mode 100644 index 000000000..28cb6b28a --- /dev/null +++ b/src/main/scala-sbt-1.0/scala/sbt/compat.scala @@ -0,0 +1,62 @@ +package sbt + +import Keys._ +import Def.Initialize + +import CrossVersion.partialVersion +import sbt.internal.LibraryManagement + +object Compat { + + // https://github.com/sbt/sbt/blob/4ce4fb72bde3b8acfaf526b79d32ca1463bc687b/main/src/main/scala/sbt/Defaults.scala#L2298 + 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 5c66eb37f..0f3ae5a37 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/DependencyGraphSettings.scala @@ -16,10 +16,13 @@ package net.virtualvoid.sbt.graph +import compat._ +import sbt.librarymanagement._ + import sbt._ import Keys._ -import CrossVersion._ +import sbt.CrossVersion._ import sbt.complete.Parser @@ -35,21 +38,26 @@ object DependencyGraphSettings { import DependencyGraphKeys._ import ModuleGraphProtocol._ - def graphSettings = Seq( + def graphSettings = baseSettings ++ ingnoreMissingSettings ++ reportSettings + + def baseSettings = Seq( ivyReportFunction := ivyReportFunctionTask.value, - updateConfiguration in ignoreMissingUpdate := { - val config = updateConfiguration.value - new UpdateConfiguration(config.retrieve, true, config.logging) - }, - ignoreMissingUpdateT, - filterScalaLibrary in Global := true) ++ Seq(Compile, Test, IntegrationTest, Runtime, Provided, Optional).flatMap(ivyReportForConfig) + filterScalaLibrary in Global := true) + + 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) + val ivyReportF = ivyReportFunction.value + + ivyReportF(config.toString) }.dependsOn(ignoreMissingUpdate) }.value, + + // ivyReport := { Def.task { ivyReportFunction.value.apply(config.toString) } dependsOn (ignoreMissingUpdate) }.value, + crossProjectId := sbt.CrossVersion( scalaVersion.value, scalaBinaryVersion.value)(projectID.value), @@ -58,9 +66,10 @@ object DependencyGraphSettings { val root = crossProjectId.value val config = configuration.value - update.configuration(config.name).map(report ⇒ + update.configuration(convertConfig(config)).map(report ⇒ SbtUpdateReport.fromConfigurationReport(report, root)).getOrElse(ModuleGraph.empty) }, + moduleGraphIvyReport := { IvyReport.fromReportFile(absoluteReportPath(ivyReport.value)) }, @@ -216,7 +225,7 @@ object DependencyGraphSettings { type HasModule = { val module: ModuleID } - def crossName(ivyModule: IvySbt#Module) = + def crossName(ivyModule: ModuleDescriptor) = ivyModule.moduleSettings match { case ic: InlineConfiguration ⇒ ic.module.name case hm: HasModule if hm.getClass.getName == "sbt.InlineConfigurationWithExcludes" ⇒ hm.module.name @@ -231,47 +240,4 @@ object DependencyGraphSettings { case _ ⇒ None } } - - /** - * This is copied directly from sbt/main/Defaults.java and then changed to update the UpdateConfiguration - * to ignore missing artifacts. - */ - def ignoreMissingUpdateT = - ignoreMissingUpdate := Def.task { - val depsUpdated = transitiveUpdate.value.exists(!_.stats.cached) - val isRoot = executionRoots.value contains resolvedScoped.value - val s = streams.value - val scalaProvider = appConfiguration.value.provider.scalaProvider - - // Only substitute unmanaged jars for managed jars when the major.minor parts of the versions the same for: - // the resolved Scala version and the scalaHome version: compatible (weakly- no qualifier checked) - // the resolved Scala version and the declared scalaVersion: assume the user intended scalaHome to override anything with scalaVersion - def subUnmanaged(subVersion: String, jars: Seq[File]) = (sv: String) ⇒ - (partialVersion(sv), partialVersion(subVersion), partialVersion(scalaVersion.value)) match { - case (Some(res), Some(sh), _) if res == sh ⇒ jars - case (Some(res), _, Some(decl)) if res == decl ⇒ jars - case _ ⇒ Nil - } - - val subScalaJars: String ⇒ Seq[File] = SbtAccess.unmanagedScalaInstanceOnly.value match { - case Some(si) ⇒ subUnmanaged(si.version, si.jars) - case None ⇒ sv ⇒ if (scalaProvider.version == sv) scalaProvider.jars else Nil - } - - val transform: UpdateReport ⇒ UpdateReport = - r ⇒ Classpaths.substituteScalaFiles(scalaOrganization.value, r)(subScalaJars) - - val show = Reference.display(thisProjectRef.value) - - Classpaths.cachedUpdate( - cacheFile = s.cacheDirectory, - label = show, - module = ivyModule.value, - config = (updateConfiguration in ignoreMissingUpdate).value, - transform = transform, - skip = (skip in update).value, - force = isRoot, - depsUpdated = depsUpdated, - log = s.log) - }.value } \ No newline at end of file diff --git a/src/main/scala/net/virtualvoid/sbt/graph/model.scala b/src/main/scala/net/virtualvoid/sbt/graph/model.scala index 68b6a8862..04f6b3f30 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/model.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/model.scala @@ -63,12 +63,4 @@ case class ModuleGraph(nodes: Seq[Module], edges: Seq[Edge]) { 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] = asProduct6(Module)(Module.unapply(_).get) - implicit val ModuleGraphFormat: Format[ModuleGraph] = asProduct2(ModuleGraph.apply _)(ModuleGraph.unapply(_).get) -} +} \ No newline at end of file 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 8da025149..c64fdf9e0 100644 --- a/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala +++ b/src/main/scala/net/virtualvoid/sbt/graph/rendering/AsciiGraph.scala @@ -17,11 +17,12 @@ package net.virtualvoid.sbt.graph package rendering -import com.github.mdr.ascii.layout._ +import com.github.mdr.ascii.graph.Graph +import com.github.mdr.ascii.layout.GraphLayout object AsciiGraph { def asciiGraph(graph: ModuleGraph): String = - Layouter.renderGraph(buildAsciiGraph(graph)) + GraphLayout.renderGraph(buildAsciiGraph(graph)) private def buildAsciiGraph(moduleGraph: ModuleGraph): Graph[String] = { def renderVertex(module: Module): String = @@ -31,7 +32,7 @@ object AsciiGraph { module.error.map("\nerror: " + _).getOrElse("") + module.evictedByVersion.map(_ formatted "\nevicted by: %s").getOrElse("") - val vertices = moduleGraph.nodes.map(renderVertex).toList + val vertices = moduleGraph.nodes.map(renderVertex).toSet 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/sbt/SbtAccess.scala b/src/main/scala/sbt/SbtAccess.scala index a75a57c31..1cb984aef 100644 --- a/src/main/scala/sbt/SbtAccess.scala +++ b/src/main/scala/sbt/SbtAccess.scala @@ -20,5 +20,5 @@ package sbt object SbtAccess { val unmanagedScalaInstanceOnly = Defaults.unmanagedScalaInstanceOnly - def getTerminalWidth: Int = JLine.usingTerminal(_.getWidth) + def getTerminalWidth: Int = internal.util.JLine.usingTerminal(_.getWidth) } diff --git a/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/build.properties b/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/build.properties deleted file mode 120000 index fe5407f08..000000000 --- a/src/sbt-test/sbt-dependency-graph/ignoreScalaLibrary/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -../../build.properties \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/build.properties b/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/build.properties deleted file mode 120000 index fe5407f08..000000000 --- a/src/sbt-test/sbt-dependency-graph/intervalRangedVersions/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -../../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 86455cc25..8db54664e 100644 --- a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt +++ b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/build.sbt @@ -1,7 +1,6 @@ -scalaVersion := "2.9.2" +scalaVersion := "2.12.3" -libraryDependencies += - "at.blub" % "blib" % "1.2.3" % "test" +libraryDependencies += "at.blub" % "blib" % "1.2.3" % Test TaskKey[Unit]("check") := { val report = (ivyReport in Test).value diff --git a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/build.properties b/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/build.properties deleted file mode 120000 index fe5407f08..000000000 --- a/src/sbt-test/sbt-dependency-graph/showMissingUpdates/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -../../build.properties \ No newline at end of file diff --git a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.properties b/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.properties deleted file mode 120000 index fe5407f08..000000000 --- a/src/sbt-test/sbt-dependency-graph/testDotFileGeneration/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -../../build.properties \ No newline at end of file