mirror of https://github.com/sbt/sbt.git
Port Settings
This commit is contained in:
parent
202cd92f0f
commit
f3d61a2106
|
|
@ -58,6 +58,36 @@ object AList:
|
||||||
// givens for tuple map
|
// givens for tuple map
|
||||||
given [Tup <: Tuple]: AList[[F[_]] =>> Tuple.Map[Tup, F]] = tuple[Tup]
|
given [Tup <: Tuple]: AList[[F[_]] =>> Tuple.Map[Tup, F]] = tuple[Tup]
|
||||||
|
|
||||||
|
type Empty = AList[[F[_]] =>> Unit]
|
||||||
|
|
||||||
|
lazy val empty: Empty = new Empty:
|
||||||
|
override def transform[F1[_], F2[_]](value: Unit)(f: [x] => F1[x] => F2[x]): Unit = ()
|
||||||
|
override def traverse[F1[_], F2[_]: Applicative](value: Unit)(
|
||||||
|
f: [a] => F1[a] => F2[a]
|
||||||
|
): F2[Unit] = summon[Applicative[F2]].pure(())
|
||||||
|
override def traverseX[F1[_], F2[_]: Applicative, P[_]](value: Unit)(
|
||||||
|
f: [a] => F1[a] => F2[P[a]]
|
||||||
|
): F2[Unit] = summon[Applicative[F2]].pure(())
|
||||||
|
override def foldr[F1[_], A2](value: Unit, init: A2)(
|
||||||
|
f: [a] => (F1[a], A2) => A2
|
||||||
|
): A2 = init
|
||||||
|
|
||||||
|
def single[A1]: AList[[F[_]] =>> F[A1]] =
|
||||||
|
new AList[[F[_]] =>> F[A1]]:
|
||||||
|
override def transform[F1[_], F2[_]](value: F1[A1])(f: [x] => F1[x] => F2[x]): F2[A1] =
|
||||||
|
f(value)
|
||||||
|
override def traverse[F1[_], F2[_]: Applicative](value: F1[A1])(
|
||||||
|
f: [a] => F1[a] => F2[a]
|
||||||
|
): F2[A1] = f(value)
|
||||||
|
override def traverseX[F1[_], F2[_]: Applicative, P[_]](value: F1[A1])(
|
||||||
|
f: [a] => F1[a] => F2[P[a]]
|
||||||
|
): F2[P[A1]] = f(value)
|
||||||
|
override def foldr[F1[_], A2](value: F1[A1], init: A2)(
|
||||||
|
f: [a] => (F1[a], A2) => A2
|
||||||
|
): A2 = f(value, init)
|
||||||
|
|
||||||
|
def tuple2[A1, A2]: AList[[F[_]] =>> Tuple.Map[(A1, A2), F]] = tuple[(A1, A2)]
|
||||||
|
|
||||||
def tuple[Tup <: Tuple]: AList[[F[_]] =>> Tuple.Map[Tup, F]] =
|
def tuple[Tup <: Tuple]: AList[[F[_]] =>> Tuple.Map[Tup, F]] =
|
||||||
new AList[[F[_]] =>> Tuple.Map[Tup, F]]:
|
new AList[[F[_]] =>> Tuple.Map[Tup, F]]:
|
||||||
override def transform[F1[_], F2[_]](value: Tuple.Map[Tup, F1])(
|
override def transform[F1[_], F2[_]](value: Tuple.Map[Tup, F1])(
|
||||||
|
|
|
||||||
|
|
@ -10,51 +10,56 @@ package sbt.internal.util
|
||||||
import java.lang.Runnable
|
import java.lang.Runnable
|
||||||
import java.util.concurrent.{ atomic, Executor, LinkedBlockingQueue }
|
import java.util.concurrent.{ atomic, Executor, LinkedBlockingQueue }
|
||||||
import atomic.{ AtomicBoolean, AtomicInteger }
|
import atomic.{ AtomicBoolean, AtomicInteger }
|
||||||
import Types.{ ConstK, Id }
|
import Types.Id
|
||||||
|
|
||||||
object EvaluationState extends Enumeration {
|
enum EvaluationState:
|
||||||
val New, Blocked, Ready, Calling, Evaluated = Value
|
case New
|
||||||
}
|
case Blocked
|
||||||
|
case Ready
|
||||||
|
case Calling
|
||||||
|
case Evaluated
|
||||||
|
|
||||||
/*
|
abstract class EvaluateSettings[ScopeType]:
|
||||||
abstract class EvaluateSettings[ScopeType] {
|
|
||||||
protected val init: Init[ScopeType]
|
protected val init: Init[ScopeType]
|
||||||
import init._
|
import init._
|
||||||
|
|
||||||
protected def executor: Executor
|
protected def executor: Executor
|
||||||
protected def compiledSettings: Seq[Compiled[_]]
|
protected def compiledSettings: Seq[Compiled[_]]
|
||||||
|
|
||||||
import EvaluationState.{ Value => EvaluationState, _ }
|
import EvaluationState.*
|
||||||
|
|
||||||
private[this] val complete = new LinkedBlockingQueue[Option[Throwable]]
|
private[this] val complete = new LinkedBlockingQueue[Option[Throwable]]
|
||||||
private[this] val static = PMap.empty[ScopedKey, INode]
|
private[this] val static = PMap.empty[ScopedKey, INode]
|
||||||
private[this] val allScopes: Set[ScopeType] = compiledSettings.map(_.key.scope).toSet
|
private[this] val allScopes: Set[ScopeType] = compiledSettings.map(_.key.scope).toSet
|
||||||
|
|
||||||
private[this] def getStatic[T](key: ScopedKey[T]): INode[T] =
|
private[this] def getStatic[A](key: ScopedKey[A]): INode[A] =
|
||||||
static get key getOrElse sys.error("Illegal reference to key " + key)
|
static.get(key).getOrElse { sys.error("Illegal reference to key " + key) }
|
||||||
|
|
||||||
private[this] val transform: Initialize ~> INode = λ[Initialize ~> INode] {
|
private[this] val transform: [A] => Initialize[A] => INode[A] = [A] =>
|
||||||
case k: Keyed[s, A1$] @unchecked => single(getStatic(k.scopedKey), k.transform)
|
(fa: Initialize[A]) =>
|
||||||
case a: Apply[k, A1$] @unchecked =>
|
fa match
|
||||||
new MixedNode[k, A1$](
|
case k: Keyed[s, A] @unchecked => single(getStatic(k.scopedKey), k.transform)
|
||||||
a.alist.transform[Initialize, INode](a.inputs, transform),
|
case a: Apply[k, A] @unchecked =>
|
||||||
a.f,
|
MixedNode[k, A](
|
||||||
a.alist
|
a.alist.transform[Initialize, INode](a.inputs) { transform },
|
||||||
)
|
a.f,
|
||||||
case b: Bind[s, A1$] @unchecked => new BindNode[s, A1$](transform(b.in), x => transform(b.f(x)))
|
a.alist
|
||||||
case v: Value[A1$] @unchecked => constant(v.value)
|
)
|
||||||
case v: ValidationCapture[A1$] @unchecked => strictConstant(v.key: A1$)
|
case b: Bind[s, A] @unchecked =>
|
||||||
case t: TransformCapture => strictConstant(t.f: A1$)
|
new BindNode[s, A](transform(b.in), x => transform(b.f(x)))
|
||||||
case o: Optional[s, A1$] @unchecked =>
|
case v: Value[A] @unchecked => constant(v.value)
|
||||||
o.a match {
|
case v: ValidationCapture[A] @unchecked => strictConstant(v.key: A)
|
||||||
case None => constant(() => o.f(None))
|
case t: TransformCapture => strictConstant(t.f: A)
|
||||||
case Some(i) => single[s, A1$](transform(i), x => o.f(Some(x)))
|
case o: Optional[s, A] @unchecked =>
|
||||||
}
|
o.a match
|
||||||
case x if x == StaticScopes =>
|
case None => constant(() => o.f(None))
|
||||||
strictConstant(allScopes.asInstanceOf[A1$]) // can't convince scalac that StaticScopes => T == Set[Scope]
|
case Some(i) => single[s, A](transform(i), x => o.f(Some(x)))
|
||||||
}
|
case x if x == StaticScopes =>
|
||||||
|
// can't convince scalac that StaticScopes => T == Set[Scope]
|
||||||
|
strictConstant(allScopes.asInstanceOf[A])
|
||||||
|
// allScopes.asInstanceOf[A]
|
||||||
|
|
||||||
private[this] lazy val roots: Seq[INode[_]] = compiledSettings flatMap { cs =>
|
private[this] lazy val roots: Seq[INode[_]] = compiledSettings.flatMap { cs =>
|
||||||
(cs.settings map { s =>
|
(cs.settings map { s =>
|
||||||
val t = transform(s.init)
|
val t = transform(s.init)
|
||||||
static(s.key) = t
|
static(s.key) = t
|
||||||
|
|
@ -78,54 +83,52 @@ abstract class EvaluateSettings[ScopeType] {
|
||||||
}
|
}
|
||||||
|
|
||||||
private[this] def getResults(implicit delegates: ScopeType => Seq[ScopeType]) =
|
private[this] def getResults(implicit delegates: ScopeType => Seq[ScopeType]) =
|
||||||
static.toTypedSeq.foldLeft(empty) {
|
static.toTypedSeq.foldLeft(empty) { case (ss, static.TPair(key, node)) =>
|
||||||
case (ss, static.TPair(key, node)) =>
|
if key.key.isLocal then ss
|
||||||
if (key.key.isLocal) ss else ss.set(key.scope, key.key, node.get)
|
else ss.set(key.scope, key.key, node.get)
|
||||||
}
|
}
|
||||||
|
|
||||||
private[this] val getValue = λ[INode ~> Id](_.get)
|
private[this] lazy val getValue: [A] => INode[A] => Id[A] = [A] => (fa: INode[A]) => fa.get
|
||||||
|
|
||||||
private[this] def submitEvaluate(node: INode[_]) = submit(node.evaluate())
|
private[this] def submitEvaluate(node: INode[_]) = submit(node.evaluate())
|
||||||
|
|
||||||
private[this] def submitCallComplete[T](node: BindNode[_, T], value: T) =
|
private[this] def submitCallComplete[A](node: BindNode[_, A], value: A) =
|
||||||
submit(node.callComplete(value))
|
submit(node.callComplete(value))
|
||||||
|
|
||||||
private[this] def submit(work: => Unit): Unit = {
|
private[this] def submit(work: => Unit): Unit =
|
||||||
startWork()
|
startWork()
|
||||||
executor.execute(new Runnable { def run = if (!cancel.get()) run0(work) })
|
// new Runnable { def run = if (!cancel.get()) run0(work) }
|
||||||
}
|
executor.execute(() => if !cancel.get() then run0(work) else ())
|
||||||
|
|
||||||
private[this] def run0(work: => Unit): Unit = {
|
private[this] def run0(work: => Unit): Unit =
|
||||||
try {
|
try {
|
||||||
work
|
work
|
||||||
} catch { case e: Throwable => complete.put(Some(e)) }
|
} catch { case e: Throwable => complete.put(Some(e)) }
|
||||||
workComplete()
|
workComplete()
|
||||||
}
|
|
||||||
|
|
||||||
private[this] def startWork(): Unit = { running.incrementAndGet(); () }
|
private[this] def startWork(): Unit = { running.incrementAndGet(); () }
|
||||||
|
|
||||||
private[this] def workComplete(): Unit =
|
private[this] def workComplete(): Unit =
|
||||||
if (running.decrementAndGet() == 0)
|
if running.decrementAndGet() == 0 then complete.put(None)
|
||||||
complete.put(None)
|
else ()
|
||||||
|
|
||||||
private[this] sealed abstract class INode[T] {
|
private[this] sealed abstract class INode[A1]:
|
||||||
private[this] var state: EvaluationState = New
|
private[this] var state: EvaluationState = New
|
||||||
private[this] var value: T = _
|
private[this] var value: A1 = _
|
||||||
private[this] val blocking = new collection.mutable.ListBuffer[INode[_]]
|
private[this] val blocking = new collection.mutable.ListBuffer[INode[_]]
|
||||||
private[this] var blockedOn: Int = 0
|
private[this] var blockedOn: Int = 0
|
||||||
private[this] val calledBy = new collection.mutable.ListBuffer[BindNode[_, T]]
|
private[this] val calledBy = new collection.mutable.ListBuffer[BindNode[_, A1]]
|
||||||
|
|
||||||
override def toString =
|
override def toString(): String =
|
||||||
getClass.getName + " (state=" + state + ",blockedOn=" + blockedOn + ",calledBy=" + calledBy.size + ",blocking=" + blocking.size + "): " +
|
getClass.getName + " (state=" + state + ",blockedOn=" + blockedOn + ",calledBy=" + calledBy.size + ",blocking=" + blocking.size + "): " +
|
||||||
keyString
|
keyString
|
||||||
|
|
||||||
private[this] def keyString =
|
private[this] def keyString =
|
||||||
(static.toSeq.flatMap {
|
(static.toSeq.flatMap { case (key, value) =>
|
||||||
case (key, value) =>
|
if (value eq this) init.showFullKey.show(key) :: Nil else List.empty[String]
|
||||||
if (value eq this) init.showFullKey.show(key) :: Nil else List.empty[String]
|
|
||||||
}).headOption getOrElse "non-static"
|
}).headOption getOrElse "non-static"
|
||||||
|
|
||||||
final def get: T = synchronized {
|
final def get: A1 = synchronized {
|
||||||
assert(value != null, toString + " not evaluated")
|
assert(value != null, toString + " not evaluated")
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
|
|
@ -149,10 +152,8 @@ abstract class EvaluateSettings[ScopeType] {
|
||||||
assert(state == New, "Already registered and: " + toString)
|
assert(state == New, "Already registered and: " + toString)
|
||||||
val deps = dependsOn
|
val deps = dependsOn
|
||||||
blockedOn = deps.size - deps.count(_.doneOrBlock(this))
|
blockedOn = deps.size - deps.count(_.doneOrBlock(this))
|
||||||
if (blockedOn == 0)
|
if blockedOn == 0 then schedule()
|
||||||
schedule()
|
else state = Blocked
|
||||||
else
|
|
||||||
state = Blocked
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final def schedule(): Unit = synchronized {
|
final def schedule(): Unit = synchronized {
|
||||||
|
|
@ -170,13 +171,13 @@ abstract class EvaluateSettings[ScopeType] {
|
||||||
|
|
||||||
final def evaluate(): Unit = synchronized { evaluate0() }
|
final def evaluate(): Unit = synchronized { evaluate0() }
|
||||||
|
|
||||||
protected final def makeCall(source: BindNode[_, T], target: INode[T]): Unit = {
|
protected final def makeCall(source: BindNode[_, A1], target: INode[A1]): Unit = {
|
||||||
assert(state == Ready, "Invalid state for call to makeCall: " + toString)
|
assert(state == Ready, "Invalid state for call to makeCall: " + toString)
|
||||||
state = Calling
|
state = Calling
|
||||||
target.call(source)
|
target.call(source)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final def setValue(v: T): Unit = {
|
protected final def setValue(v: A1): Unit = {
|
||||||
assert(
|
assert(
|
||||||
state != Evaluated,
|
state != Evaluated,
|
||||||
"Already evaluated (trying to set value to " + v + "): " + toString
|
"Already evaluated (trying to set value to " + v + "): " + toString
|
||||||
|
|
@ -192,7 +193,7 @@ abstract class EvaluateSettings[ScopeType] {
|
||||||
calledBy.clear()
|
calledBy.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
final def call(by: BindNode[_, T]): Unit = synchronized {
|
final def call(by: BindNode[_, A1]): Unit = synchronized {
|
||||||
registerIfNew()
|
registerIfNew()
|
||||||
state match {
|
state match {
|
||||||
case Evaluated => submitCallComplete(by, value)
|
case Evaluated => submitCallComplete(by, value)
|
||||||
|
|
@ -204,29 +205,29 @@ abstract class EvaluateSettings[ScopeType] {
|
||||||
|
|
||||||
protected def dependsOn: Seq[INode[_]]
|
protected def dependsOn: Seq[INode[_]]
|
||||||
protected def evaluate0(): Unit
|
protected def evaluate0(): Unit
|
||||||
}
|
end INode
|
||||||
|
|
||||||
private[this] def strictConstant[T](v: T): INode[T] = constant(() => v)
|
private[this] def strictConstant[A1](v: A1): INode[A1] = constant(() => v)
|
||||||
|
|
||||||
private[this] def constant[T](f: () => T): INode[T] =
|
private[this] def constant[A1](f: () => A1): INode[A1] =
|
||||||
new MixedNode[ConstK[Unit]#l, T]((), _ => f(), AList.empty)
|
MixedNode[[F[_]] =>> Unit, A1]((), _ => f(), AList.empty)
|
||||||
|
|
||||||
private[this] def single[S, T](in: INode[S], f: S => T): INode[T] =
|
private[this] def single[A1, A2](in: INode[A1], f: A1 => A2): INode[A2] =
|
||||||
new MixedNode[λ[L[x] => L[S]], T](in, f, AList.single[S])
|
MixedNode[[F[_]] =>> F[A1], A2](in, f, AList.single[A1])
|
||||||
|
|
||||||
private[this] final class BindNode[S, T](in: INode[S], f: S => INode[T]) extends INode[T] {
|
private[this] final class BindNode[A1, A2](in: INode[A1], f: A1 => INode[A2]) extends INode[A2]:
|
||||||
protected def dependsOn = in :: Nil
|
protected def dependsOn: Seq[INode[_]] = in :: Nil
|
||||||
protected def evaluate0(): Unit = makeCall(this, f(in.get))
|
protected def evaluate0(): Unit = makeCall(this, f(in.get))
|
||||||
def callComplete(value: T): Unit = synchronized {
|
def callComplete(value: A2): Unit = synchronized {
|
||||||
assert(isCalling, "Invalid state for callComplete(" + value + "): " + toString)
|
assert(isCalling, "Invalid state for callComplete(" + value + "): " + toString)
|
||||||
setValue(value)
|
setValue(value)
|
||||||
}
|
}
|
||||||
}
|
end BindNode
|
||||||
|
|
||||||
private[this] final class MixedNode[K[L[x]], T](in: K[INode], f: K[Id] => T, alist: AList[K])
|
private[this] final class MixedNode[K[L[x]], A1](in: K[INode], f: K[Id] => A1, alist: AList[K])
|
||||||
extends INode[T] {
|
extends INode[A1]:
|
||||||
protected def dependsOn = alist.toList(in)
|
protected override def dependsOn: Seq[INode[_]] = alist.toList(in)
|
||||||
protected def evaluate0(): Unit = setValue(f(alist.transform(in, getValue)))
|
protected override def evaluate0(): Unit = setValue(f(alist.transform(in) { getValue }))
|
||||||
}
|
end MixedNode
|
||||||
}
|
|
||||||
*/
|
end EvaluateSettings
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -15,7 +15,9 @@ trait TypeFunctions:
|
||||||
import TypeFunctions._
|
import TypeFunctions._
|
||||||
sealed trait Const[A] { type Apply[B] = A }
|
sealed trait Const[A] { type Apply[B] = A }
|
||||||
sealed trait ConstK[A] { type l[L[x]] = A }
|
sealed trait ConstK[A] { type l[L[x]] = A }
|
||||||
|
type ConstK[A] = [F[_]] =>> A
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sealed trait Compose[A[_], B[_]] { type Apply[T] = A[B[T]] }
|
sealed trait Compose[A[_], B[_]] { type Apply[T] = A[B[T]] }
|
||||||
|
|
||||||
sealed trait ∙[A[_], B[_]] { type l[T] = A[B[T]] }
|
sealed trait ∙[A[_], B[_]] { type l[T] = A[B[T]] }
|
||||||
|
|
@ -47,7 +49,6 @@ trait TypeFunctions:
|
||||||
type ~>|[A[_], B[_]] = A ~> Compose[Option, B]#Apply
|
type ~>|[A[_], B[_]] = A ~> Compose[Option, B]#Apply
|
||||||
*/
|
*/
|
||||||
type ~>|[F1[_], F2[_]] = [A] => F1[A] => Option[F2[A]]
|
type ~>|[F1[_], F2[_]] = [A] => F1[A] => Option[F2[A]]
|
||||||
|
|
||||||
end TypeFunctions
|
end TypeFunctions
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,11 @@ case class SettingsExample() extends Init[Scope] {
|
||||||
})
|
})
|
||||||
|
|
||||||
// A sample delegation function that delegates to a Scope with a lower index.
|
// A sample delegation function that delegates to a Scope with a lower index.
|
||||||
val delegates: Scope => Seq[Scope] = {
|
val delegates: Scope => Seq[Scope] = { case s @ Scope(index, proj) =>
|
||||||
case s @ Scope(index, proj) =>
|
s +: (if (index <= 0) Nil
|
||||||
s +: (if (index <= 0) Nil
|
else {
|
||||||
else {
|
(if (proj > 0) List(Scope(index)) else Nil) ++: delegates(Scope(index - 1))
|
||||||
(if (proj > 0) List(Scope(index)) else Nil) ++: delegates(Scope(index - 1))
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not using this feature in this example.
|
// Not using this feature in this example.
|
||||||
|
|
@ -39,7 +38,7 @@ case class SettingsExample() extends Init[Scope] {
|
||||||
// These three functions + a scope (here, Scope) are sufficient for defining our settings system.
|
// These three functions + a scope (here, Scope) are sufficient for defining our settings system.
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Usage Example **/
|
/** Usage Example * */
|
||||||
case class SettingsUsage(val settingsExample: SettingsExample) {
|
case class SettingsUsage(val settingsExample: SettingsExample) {
|
||||||
import settingsExample._
|
import settingsExample._
|
||||||
|
|
||||||
|
|
@ -73,25 +72,25 @@ case class SettingsUsage(val settingsExample: SettingsExample) {
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Output:
|
* Output:
|
||||||
* For the None results, we never defined the value and there was no value to delegate to.
|
* For the None results, we never defined the value and there was no value to delegate to.
|
||||||
* For a3, we explicitly defined it to be 3.
|
* For a3, we explicitly defined it to be 3.
|
||||||
* a4 wasn't defined, so it delegates to a3 according to our delegates function.
|
* a4 wasn't defined, so it delegates to a3 according to our delegates function.
|
||||||
* b4 gets the value for a4 (which delegates to a3, so it is 3) and multiplies by 3
|
* b4 gets the value for a4 (which delegates to a3, so it is 3) and multiplies by 3
|
||||||
* a5 is defined as the previous value of a5 + 1 and
|
* a5 is defined as the previous value of a5 + 1 and
|
||||||
* since no previous value of a5 was defined, it delegates to a4, resulting in 3+1=4.
|
* since no previous value of a5 was defined, it delegates to a4, resulting in 3+1=4.
|
||||||
* b5 isn't defined explicitly, so it delegates to b4 and is therefore equal to 9 as well
|
* b5 isn't defined explicitly, so it delegates to b4 and is therefore equal to 9 as well
|
||||||
* a0 = None
|
* a0 = None
|
||||||
* b0 = None
|
* b0 = None
|
||||||
* a1 = None
|
* a1 = None
|
||||||
* b1 = None
|
* b1 = None
|
||||||
* a2 = None
|
* a2 = None
|
||||||
* b2 = None
|
* b2 = None
|
||||||
* a3 = Some(3)
|
* a3 = Some(3)
|
||||||
* b3 = None
|
* b3 = None
|
||||||
* a4 = Some(3)
|
* a4 = Some(3)
|
||||||
* b4 = Some(9)
|
* b4 = Some(9)
|
||||||
* a5 = Some(4)
|
* a5 = Some(4)
|
||||||
* b5 = Some(9)
|
* b5 = Some(9)
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue