2011-11-23 06:49:27 +01:00
|
|
|
/* sbt -- Simple Build Tool
|
|
|
|
|
* Copyright 2011 Mark Harrah, Eugene Yokota
|
|
|
|
|
*/
|
|
|
|
|
package sbt
|
|
|
|
|
|
|
|
|
|
import java.net.URI
|
|
|
|
|
import java.io.File
|
2012-07-31 17:52:10 +02:00
|
|
|
import Def.{compiled,flattenLocals,ScopedKey}
|
2011-11-23 06:49:27 +01:00
|
|
|
import Predef.{any2stringadd => _, _}
|
|
|
|
|
|
|
|
|
|
object SettingGraph
|
|
|
|
|
{
|
|
|
|
|
def apply(structure: BuildStructure, basedir: File, scoped: ScopedKey[_], generation: Int)
|
|
|
|
|
(implicit display: Show[ScopedKey[_]]): SettingGraph =
|
|
|
|
|
{
|
|
|
|
|
val key = scoped.key
|
|
|
|
|
val scope = scoped.scope
|
|
|
|
|
val definedIn = structure.data.definingScope(scope, key) map { sc => display(ScopedKey(sc, key)) }
|
|
|
|
|
val cMap = flattenLocals(compiled(structure.settings, false)(structure.delegates, structure.scopeLocal, display))
|
|
|
|
|
// val related = cMap.keys.filter(k => k.key == key && k.scope != scope)
|
|
|
|
|
val depends = cMap.get(scoped) match { case Some(c) => c.dependencies.toSet; case None => Set.empty }
|
|
|
|
|
// val reverse = reverseDependencies(cMap, scoped)
|
|
|
|
|
|
2011-11-24 01:53:20 +01:00
|
|
|
SettingGraph(display(scoped), definedIn,
|
|
|
|
|
Project.scopedKeyData(structure, scope, key),
|
|
|
|
|
key.description, basedir,
|
2012-07-31 17:52:10 +02:00
|
|
|
depends map { (x: ScopedKey[_]) => apply(structure, basedir, x, generation + 1) })
|
2011-11-23 06:49:27 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case class SettingGraph(name: String,
|
|
|
|
|
definedIn: Option[String],
|
2011-11-24 01:53:20 +01:00
|
|
|
data: Option[ScopedKeyData[_]],
|
2011-11-23 06:49:27 +01:00
|
|
|
description: Option[String],
|
|
|
|
|
basedir: File,
|
|
|
|
|
depends: Set[SettingGraph])
|
|
|
|
|
{
|
2011-11-24 01:53:20 +01:00
|
|
|
def dataString: String =
|
|
|
|
|
data map { d =>
|
|
|
|
|
d.settingValue map {
|
|
|
|
|
case f: File => IO.relativize(basedir, f) getOrElse {f.toString}
|
|
|
|
|
case x => x.toString
|
|
|
|
|
} getOrElse {d.typeName}
|
|
|
|
|
} getOrElse {""}
|
|
|
|
|
|
2011-11-23 06:49:27 +01:00
|
|
|
def dependsAscii: String = Graph.toAscii(this,
|
|
|
|
|
(x: SettingGraph) => x.depends.toSeq,
|
2011-11-24 01:53:20 +01:00
|
|
|
(x: SettingGraph) => "%s = %s" format(x.definedIn getOrElse {""}, x.dataString))
|
2011-11-23 06:49:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object Graph
|
|
|
|
|
{
|
|
|
|
|
// [info] foo
|
|
|
|
|
// [info] +-bar
|
|
|
|
|
// [info] | +-baz
|
|
|
|
|
// [info] |
|
|
|
|
|
// [info] +-quux
|
|
|
|
|
def toAscii[A](top: A, children: A => Seq[A], display: A => String): String = {
|
2012-05-24 02:13:52 +02:00
|
|
|
val maxColumn = JLine.usingTerminal(_.getTerminalWidth) - 8
|
2011-11-23 06:49:27 +01:00
|
|
|
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 =
|
|
|
|
|
s.slice(0, at) +
|
|
|
|
|
(s(at).toString match {
|
|
|
|
|
case " " => "|"
|
|
|
|
|
case x => x
|
|
|
|
|
}) +
|
|
|
|
|
s.slice(at + 1, s.length)
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
line +: withBar
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
toAsciiLines(top, 0).mkString("\n")
|
|
|
|
|
}
|
|
|
|
|
}
|