half-broken initial attempt at sbt 1.0.0 support

This commit is contained in:
Johannes Rudolph 2017-08-29 16:48:27 +02:00
parent 279dea3514
commit 0e20a090f3
6 changed files with 156 additions and 86 deletions

View File

@ -1,7 +1,8 @@
ScriptedPlugin.scriptedSettings
libraryDependencies ++= {
if (sbtVersion.value startsWith "0.13")
println(s"Evaluated ${sbtVersion in pluginCrossBuild value}")
if ((sbtVersion in pluginCrossBuild).value startsWith "0.13")
Seq("com.github.mdr" %% "ascii-graphs" % "0.0.3")
else
Nil
@ -12,3 +13,19 @@ libraryDependencies += "org.specs2" %% "specs2-core" % "3.9.1" % "test"
scalacOptions ++= Seq("-deprecation", "-unchecked")
ScalariformSupport.formatSettings
crossSbtVersions := Seq("1.0.1", "0.13.16")
//sbtVersion in pluginCrossBuild := "1.0.0"
/*
Try to prevent silly warnings
libraryDependencies += ("org.scala-sbt" %% "main-settings" % "1.0.1-SNAPSHOT")//.excludeAll(ExclusionRule(organization = "org.scala-sbt"))
libraryDependencies += "org.scala-sbt" %% "command" % "1.0.0"force()
libraryDependencies += "org.scala-sbt" %% "completion" % "1.0.0"force()
libraryDependencies += "org.scala-sbt" %% "task-system" % "1.0.0"force()
libraryDependencies += "org.scala-sbt" %% "core-macros" % "1.0.0" force()
*/

View File

@ -0,0 +1,11 @@
package sbt.compat
object SbtCompat {
object librarymanagement
object internal {
object librarymanagement
object util {
val JLine: { def usingTerminal[T](f: jline.Terminal => T): T } = sbt.JLine
}
}
}

View File

@ -0,0 +1,3 @@
package sbt.compat
object SbtCompat

View File

@ -25,48 +25,58 @@ import net.virtualvoid.sbt.graph.backend.{ IvyReport, SbtUpdateReport }
import net.virtualvoid.sbt.graph.rendering.{ AsciiGraph, DagreHTML }
import net.virtualvoid.sbt.graph.util.IOUtil
import sbt.compat.SbtCompat._
import internal.librarymanagement._
import librarymanagement._
object DependencyGraphSettings {
import DependencyGraphKeys._
import ModuleGraphProtocol._
def graphSettings = Seq(
ivyReportFunction <<= ivyReportFunctionTask,
updateConfiguration in ignoreMissingUpdate <<= updateConfiguration(config new UpdateConfiguration(config.retrieve, true, config.logging)),
ignoreMissingUpdateT,
ivyReportFunction := ivyReportFunctionTask.value,
updateConfiguration in ignoreMissingUpdate := updateConfiguration.value.withMissingOk(true),
ignoreMissingUpdate := update.value,
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 :=
ignoreMissingUpdate.value.configuration(configuration.value).map(report SbtUpdateReport.fromConfigurationReport(report, crossProjectId.value)).getOrElse(ModuleGraph.empty),
moduleGraphIvyReport := IvyReport.fromReportFile(absoluteReportPath(ivyReport.value)),
moduleGraph := {
sbtVersion.value match {
case Version(0, 13, x, _) if x >= 6 moduleGraphSbt.value
case Version(1, _, _, _) moduleGraphSbt.value
}
},
moduleGraph <<= (scalaVersion, moduleGraph, filterScalaLibrary) map { (scalaV, graph, filter)
if (filter) GraphTransformations.ignoreScalaLibrary(scalaV, graph)
else graph
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,
asciiTree <<= moduleGraph map rendering.AsciiTree.asciiTree,
dependencyTree <<= print(asciiTree),
dependencyGraphMLFile <<= target / "dependencies-%s.graphml".format(config.toString),
dependencyGraphML <<= dependencyGraphMLTask,
dependencyDotFile <<= target / "dependencies-%s.dot".format(config.toString),
dependencyDotString <<= dependencyDotStringTask,
dependencyDot <<= writeToFile(dependencyDotString, dependencyDotFile),
dependencyBrowseGraphTarget <<= target / "browse-dependency-graph",
dependencyBrowseGraphHTML <<= browseGraphHTMLTask,
dependencyBrowseGraph <<= (dependencyBrowseGraphHTML, streams).map { (uri, streams)
streams.log.info("Opening in browser...")
moduleGraphStore := (moduleGraph storeAs moduleGraphStore triggeredBy moduleGraph).value,
asciiTree := rendering.AsciiTree.asciiTree(moduleGraph.value),
dependencyTree := print(asciiTree).value,
dependencyGraphMLFile := { target.value / "dependencies-%s.graphml".format(config.toString) },
dependencyGraphML := dependencyGraphMLTask.value,
dependencyDotFile := { target.value / "dependencies-%s.dot".format(config.toString) },
dependencyDotString := rendering.DOT.dotGraph(moduleGraph.value, dependencyDotHeader.value, dependencyDotNodeLabel.value, rendering.DOT.AngleBrackets),
dependencyDot := writeToFile(dependencyDotString, dependencyDotFile).value,
dependencyBrowseGraphTarget := { target.value / "browse-dependency-graph" },
dependencyBrowseGraphHTML := browseGraphHTMLTask.value,
dependencyBrowseGraph := {
val uri = dependencyBrowseGraphHTML.value
streams.value.log.info("Opening in browser...")
java.awt.Desktop.getDesktop.browse(uri)
uri
},
dependencyList <<= printFromGraph(rendering.FlatList.render(_, _.id.idString)),
dependencyStats <<= printFromGraph(rendering.Statistics.renderModuleStatsList),
dependencyList := printFromGraph(rendering.FlatList.render(_, _.id.idString)).value,
dependencyStats := printFromGraph(rendering.Statistics.renderModuleStatsList).value,
dependencyDotHeader := """digraph "dependency-graph" {
| graph[rankdir="LR"]
| edge [
@ -75,79 +85,71 @@ object DependencyGraphSettings {
dependencyDotNodeLabel := { (organisation: String, name: String, version: String)
"""%s<BR/><B>%s</B><BR/>%s""".format(organisation, name, version)
},
whatDependsOn <<= InputTask(artifactIdParser) { module
(module, streams, moduleGraph) map { (module, streams, graph)
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) ++ AsciiGraph.asciiGraphSetttings)
licenseInfo := showLicenseInfo(moduleGraph.value, streams.value)) ++ AsciiGraph.asciiGraphSetttings)
def ivyReportFunctionTask =
(sbtVersion, target, projectID, ivyModule, appConfiguration, streams) map { (sbtV, target, projectID, ivyModule, config, streams)
sbtV match {
case Version(0, min, fix, _) if min > 12 || (min == 12 && fix >= 3)
(c: String) file("%s/resolution-cache/reports/%s-%s-%s.xml".format(target, projectID.organization, crossName(ivyModule), c))
case Version(0, min, fix, _) if min == 12 && fix >= 1 && fix < 3
ivyModule.withModule(streams.log) { (i, moduleDesc, _)
val id = ResolveOptions.getDefaultResolveId(moduleDesc)
(c: String) file("%s/resolution-cache/reports/%s/%s-resolved.xml" format (target, id, c))
}
case _
val home = config.provider.scalaProvider.launcher.ivyHome
(c: String) file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c))
}
def ivyReportFunctionTask = Def.task {
// FIXME: and remove busywork after https://github.com/sbt/sbt/issues/3299 is fixed
val target = Keys.target.value
val projectID = Keys.projectID.value
val ivyModule = Keys.ivyModule.value
sbtVersion.value 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.value.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 = appConfiguration.value.provider.scalaProvider.launcher.ivyHome
(c: String) file("%s/cache/%s-%s-%s.xml" format (home, projectID.organization, crossName(ivyModule), c))
}
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 =
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("\t %s" format _.id.idString).mkString("\n")
}.mkString("\n\n")
streams.log.info(output)
}
@ -159,7 +161,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)
@ -197,11 +199,17 @@ object DependencyGraphSettings {
}
/**
* This is copied directly from sbt/main/Defaults.java and then changed to update the UpdateConfiguration
* This is copied directly from sbt/main/Defaults.scala and then changed to update the UpdateConfiguration
* to ignore missing artifacts.
*/
def ignoreMissingUpdateT =
ignoreMissingUpdate <<= Def.task {
/*def ignoreMissingUpdateT =
ignoreMissingUpdate := {
// FIXME: remove busywork
val scalaVersion = Keys.scalaVersion.value
val unmanagedScalaInstanceOnly = SbtAccess.unmanagedScalaInstanceOnly.value
val scalaOrganization = Keys.scalaOrganization.value
val depsUpdated = transitiveUpdate.value.exists(!_.stats.cached)
val isRoot = executionRoots.value contains resolvedScoped.value
val s = streams.value
@ -211,18 +219,19 @@ object DependencyGraphSettings {
// 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 {
(partialVersion(sv), partialVersion(subVersion), partialVersion(scalaVersion)) 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)
val subScalaJars: String Seq[File] = unmanagedScalaInstanceOnly 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 transform: UpdateReport UpdateReport = r Classpaths.substituteScalaFiles(scalaOrganization, 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)
}
SbtAccess.cachedUpdater(
s.cacheDirectory, show, ivyModule.value, (updateConfiguration in ignoreMissingUpdate).value, transform, skip = (skip in update).value, force = isRoot, depsUpdated = depsUpdated, log = s.log)
}*/
}

View File

@ -16,9 +16,13 @@
package net.virtualvoid.sbt.graph
import java.io.File
import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, File }
import java.util.Base64
import scala.collection.mutable.{ MultiMap, HashMap, Set }
import sbinary.{ JavaInput, JavaOutput }
import sjsonnew.{ Builder, Unbuilder }
import scala.collection.mutable.{ HashMap, MultiMap, Set }
case class ModuleId(organisation: String,
name: String,
@ -71,4 +75,21 @@ object ModuleGraphProtocol extends DefaultProtocol {
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)
//
implicit def sjsonNewAndShinyTransformAndTranspileAdapterFactoryModuleImplementation[T](implicit format: Format[T]): sjsonnew.JsonFormat[T] =
new sjsonnew.JsonFormat[T] {
// note, how this is simpler to write than to learn any sjonnew protocol syntax
def write[J](obj: T, builder: Builder[J]): Unit = {
val baos = new ByteArrayOutputStream()
format.writes(new JavaOutput(baos), obj)
val str = Base64.getEncoder.encodeToString(baos.toByteArray)
builder.writeString(str)
}
def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): T = {
val str = unbuilder.readString(jsOpt.get)
val bais = new ByteArrayInputStream(Base64.getDecoder.decode(str))
format.reads(new JavaInput(bais))
}
}
}

View File

@ -16,9 +16,18 @@
package sbt
import sbt.compat.SbtCompat._
import librarymanagement._
import internal._
import librarymanagement._
import Classpaths._
import LibraryManagement._
import internal.util.JLine
/** Accessors to private[sbt] symbols. */
object SbtAccess {
val unmanagedScalaInstanceOnly = Defaults.unmanagedScalaInstanceOnly
def getTerminalWidth: Int = JLine.usingTerminal(_.getWidth)
}