mirror of https://github.com/sbt/sbt.git
Migrates Treeview.scala to use Contraband
Migrates TreeView.scala to use Contraband from scala.util.parsing.json, because this is now deprecated. The TreeView logic is used in the dependencyBrowseTree task.
This commit is contained in:
parent
bcbef795e7
commit
3c81e08fa2
|
|
@ -10,24 +10,20 @@ package internal
|
|||
package graph
|
||||
package rendering
|
||||
|
||||
import sbt.internal.graph.codec.JsonProtocol.ModuleModelFormat
|
||||
import sbt.io.IO
|
||||
import sjsonnew.support.scalajson.unsafe.{ CompactPrinter, Converter }
|
||||
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.io.{ File, FileOutputStream, InputStream, OutputStream }
|
||||
import java.net.URI
|
||||
import scala.annotation.nowarn
|
||||
import scala.annotation.tailrec
|
||||
import scala.util.parsing.json.JSONArray
|
||||
import scala.util.parsing.json.JSONObject
|
||||
import scala.annotation.{ nowarn, tailrec }
|
||||
|
||||
@nowarn object TreeView {
|
||||
def createJson(graph: ModuleGraph): String = {
|
||||
val trees = graph.roots
|
||||
val moduleModels = graph.roots
|
||||
.map(module => processSubtree(graph, module))
|
||||
.toList
|
||||
JSONArray(trees).toString
|
||||
val js = moduleModels.map(Converter.toJsonUnsafe(_))
|
||||
js.map(CompactPrinter).mkString("[", ",", "]")
|
||||
}
|
||||
|
||||
def createLink(graphJson: String, targetDirectory: File): URI = {
|
||||
|
|
@ -43,24 +39,26 @@ import scala.util.parsing.json.JSONObject
|
|||
graph: ModuleGraph,
|
||||
module: Module,
|
||||
parents: Set[GraphModuleId] = Set()
|
||||
): JSONObject = {
|
||||
): ModuleModel = {
|
||||
val cycle = parents.contains(module.id)
|
||||
val dependencies = if (cycle) List() else graph.dependencyMap.getOrElse(module.id, List())
|
||||
val children =
|
||||
dependencies.map(dependency => processSubtree(graph, dependency, parents + module.id)).toList
|
||||
moduleAsJson(module, cycle, children)
|
||||
dependencies
|
||||
.map(dependency => processSubtree(graph, dependency, parents + module.id))
|
||||
.toVector
|
||||
moduleAsModuleAgain(module, cycle, children)
|
||||
}
|
||||
|
||||
private def moduleAsJson(
|
||||
private def moduleAsModuleAgain(
|
||||
module: Module,
|
||||
isCycle: Boolean,
|
||||
children: List[JSONObject]
|
||||
): JSONObject = {
|
||||
children: Vector[ModuleModel]
|
||||
): ModuleModel = {
|
||||
val eviction = module.evictedByVersion.map(version => s" (evicted by $version)").getOrElse("")
|
||||
val cycle = if (isCycle) " (cycle)" else ""
|
||||
val error = module.error.map(err => s" (errors: $err)").getOrElse("")
|
||||
val text = module.id.idString + eviction + error + cycle
|
||||
JSONObject(Map("text" -> text, "children" -> JSONArray(children)))
|
||||
ModuleModel(text, children)
|
||||
}
|
||||
|
||||
def saveResource(resourcePath: String, to: File): Unit = {
|
||||
|
|
|
|||
|
|
@ -5,51 +5,48 @@
|
|||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt
|
||||
package internal
|
||||
package graph
|
||||
package rendering
|
||||
package sbt.internal.graph.rendering
|
||||
|
||||
import org.scalatest.DiagrammedAssertions
|
||||
import org.scalatest.FunSuite
|
||||
|
||||
import scala.annotation.nowarn
|
||||
import scala.util.parsing.json.JSONArray
|
||||
import scala.util.parsing.json.JSONObject
|
||||
|
||||
@nowarn("msg=class JSONObject in package json is deprecated")
|
||||
class TreeViewTest extends FunSuite with DiagrammedAssertions {
|
||||
import org.scalatest.{ FlatSpec, Matchers }
|
||||
import sbt.internal.graph.rendering.TreeView.createJson
|
||||
import sbt.internal.graph.{ GraphModuleId, Module, ModuleGraph, ModuleModel }
|
||||
|
||||
class TreeViewTest extends FlatSpec with Matchers {
|
||||
val modA = GraphModuleId("orgA", "nameA", "1.0")
|
||||
val modB = GraphModuleId("orgB", "nameB", "2.0")
|
||||
val modC = GraphModuleId("orgC", "nameC", "3.0")
|
||||
|
||||
val graph = ModuleGraph(
|
||||
nodes = Seq(Module(modA), Module(modB)),
|
||||
nodes = Seq(Module(modA), Module(modB), Module(modC)),
|
||||
edges = Seq(
|
||||
modA -> modA,
|
||||
modA -> modB,
|
||||
modC -> modA,
|
||||
)
|
||||
)
|
||||
|
||||
test("TreeView should detect cycles and truncate") {
|
||||
val json = TreeView.processSubtree(graph, Module(modA))
|
||||
val (rootText, children) = parseTree(json)
|
||||
assert(rootText == modA.idString)
|
||||
|
||||
val childrenText = children.map(parseTree).map(_._1)
|
||||
val expected = List(s"${modA.idString} (cycle)", modB.idString)
|
||||
assert(childrenText == expected)
|
||||
"createJson" should "convert ModuleGraph into JSON correctly" in {
|
||||
val expected =
|
||||
"[{\"text\":\"orgC:nameC:3.0\",\"children\":[{\"text\":\"orgA:nameA:1.0\",\"children\":[{\"text\":\"orgA:nameA:1.0 (cycle)\",\"children\":[]},{\"text\":\"orgB:nameB:2.0\",\"children\":[]}]}]}]"
|
||||
Predef.assert(
|
||||
createJson(graph) == expected,
|
||||
s"Expected $expected, but got ${createJson(graph)}"
|
||||
)
|
||||
}
|
||||
|
||||
@nowarn("cat=unchecked")
|
||||
def parseTree(json: JSONObject): (String, List[JSONObject]) = {
|
||||
(json.obj.get("text"), json.obj.get("children")) match {
|
||||
case (Some(text: String), Some(JSONArray(children: List[JSONObject])))
|
||||
if children.forall(_.isInstanceOf[JSONObject]) =>
|
||||
text -> children
|
||||
case _ =>
|
||||
fail("a string field 'text' and an array of objects in 'children' field were expected!")
|
||||
}
|
||||
"processSubtree" should "detect cycles and truncate" in {
|
||||
val expected = ModuleModel(
|
||||
"orgC:nameC:3.0",
|
||||
Vector(
|
||||
ModuleModel(
|
||||
"orgA:nameA:1.0",
|
||||
Vector(
|
||||
ModuleModel("orgA:nameA:1.0 (cycle)", Vector()),
|
||||
ModuleModel("orgB:nameB:2.0", Vector())
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
assert(TreeView.processSubtree(graph, Module(modC), Set()) == expected)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,3 +11,4 @@ addSbtPlugin("com.lightbend" % "sbt-whitesource" % "0.1.14")
|
|||
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.9")
|
||||
addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.8.1")
|
||||
addSbtPlugin("com.swoval" % "sbt-java-format" % "0.3.1")
|
||||
addDependencyTreePlugin
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.internal.graph
|
||||
final class ModuleModel private (
|
||||
val text: String,
|
||||
val children: Vector[sbt.internal.graph.ModuleModel]) extends Serializable {
|
||||
|
||||
|
||||
|
||||
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
|
||||
case x: ModuleModel => (this.text == x.text) && (this.children == x.children)
|
||||
case _ => false
|
||||
})
|
||||
override def hashCode: Int = {
|
||||
37 * (37 * (37 * (17 + "sbt.internal.graph.ModuleModel".##) + text.##) + children.##)
|
||||
}
|
||||
override def toString: String = {
|
||||
"ModuleModel(" + text + ", " + children + ")"
|
||||
}
|
||||
private[this] def copy(text: String = text, children: Vector[sbt.internal.graph.ModuleModel] = children): ModuleModel = {
|
||||
new ModuleModel(text, children)
|
||||
}
|
||||
def withText(text: String): ModuleModel = {
|
||||
copy(text = text)
|
||||
}
|
||||
def withChildren(children: Vector[sbt.internal.graph.ModuleModel]): ModuleModel = {
|
||||
copy(children = children)
|
||||
}
|
||||
}
|
||||
object ModuleModel {
|
||||
|
||||
def apply(text: String, children: Vector[sbt.internal.graph.ModuleModel]): ModuleModel = new ModuleModel(text, children)
|
||||
}
|
||||
9
protocol/src/main/contraband-scala/sbt/internal/graph/codec/JsonProtocol.scala
generated
Normal file
9
protocol/src/main/contraband-scala/sbt/internal/graph/codec/JsonProtocol.scala
generated
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.internal.graph.codec
|
||||
trait JsonProtocol extends sjsonnew.BasicJsonProtocol
|
||||
with sbt.internal.graph.codec.ModuleModelFormats
|
||||
object JsonProtocol extends JsonProtocol
|
||||
29
protocol/src/main/contraband-scala/sbt/internal/graph/codec/ModuleModelFormats.scala
generated
Normal file
29
protocol/src/main/contraband-scala/sbt/internal/graph/codec/ModuleModelFormats.scala
generated
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
|
||||
*/
|
||||
|
||||
// DO NOT EDIT MANUALLY
|
||||
package sbt.internal.graph.codec
|
||||
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
|
||||
trait ModuleModelFormats { self: sbt.internal.graph.codec.ModuleModelFormats with sjsonnew.BasicJsonProtocol =>
|
||||
implicit lazy val ModuleModelFormat: JsonFormat[sbt.internal.graph.ModuleModel] = new JsonFormat[sbt.internal.graph.ModuleModel] {
|
||||
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.internal.graph.ModuleModel = {
|
||||
__jsOpt match {
|
||||
case Some(__js) =>
|
||||
unbuilder.beginObject(__js)
|
||||
val text = unbuilder.readField[String]("text")
|
||||
val children = unbuilder.readField[Vector[sbt.internal.graph.ModuleModel]]("children")
|
||||
unbuilder.endObject()
|
||||
sbt.internal.graph.ModuleModel(text, children)
|
||||
case None =>
|
||||
deserializationError("Expected JsObject but found None")
|
||||
}
|
||||
}
|
||||
override def write[J](obj: sbt.internal.graph.ModuleModel, builder: Builder[J]): Unit = {
|
||||
builder.beginObject()
|
||||
builder.addField("text", obj.text)
|
||||
builder.addField("children", obj.children)
|
||||
builder.endObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package sbt.internal.graph
|
||||
@target(Scala)
|
||||
@codecPackage("sbt.internal.graph.codec")
|
||||
@fullCodec("JsonProtocol")
|
||||
|
||||
type ModuleModel {
|
||||
text: String!
|
||||
children: [sbt.internal.graph.ModuleModel]
|
||||
}
|
||||
Loading…
Reference in New Issue