From b453af7c45842ae2170c299fa48740aba3269239 Mon Sep 17 00:00:00 2001 From: Mark Harrah Date: Mon, 20 Aug 2012 15:55:51 -0400 Subject: [PATCH] Properly apply transformations to dynamic tasks. That is, implement Initialize[Task[T]].flatten correctly. This requires preserving the transformations applied in a scope so that they can be applied to an Initialize value after static settings have been evaluated. --- main/settings/TaskMacro.scala | 6 +++--- util/collection/INode.scala | 1 + util/collection/Settings.scala | 24 ++++++++++++++++++++---- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/main/settings/TaskMacro.scala b/main/settings/TaskMacro.scala index 25307bd02..37d517887 100644 --- a/main/settings/TaskMacro.scala +++ b/main/settings/TaskMacro.scala @@ -32,10 +32,10 @@ object FullInstance extends Instance.Composed[Initialize, Task](InitializeInstan def flatten[T](in: Initialize[Task[Initialize[Task[T]]]]): Initialize[Task[T]] = { import Scoped._ - (in,settingsData) apply{ - (a: Task[Initialize[Task[T]]], data: Task[SS]) => + (in,settingsData, Def.capturedTransformations) apply{ + (a: Task[Initialize[Task[T]]], data: Task[SS], f) => import TaskExtra.multT2Task - (a, data) flatMap { case (a,d) => a evaluate d } + (a, data) flatMap { case (a,d) => f(a) evaluate d } } } } diff --git a/util/collection/INode.scala b/util/collection/INode.scala index 1ac9152a2..86ddff060 100644 --- a/util/collection/INode.scala +++ b/util/collection/INode.scala @@ -27,6 +27,7 @@ abstract class EvaluateSettings[Scope] case a: Apply[k,T] => new MixedNode[k,T]( a.alist.transform[Initialize, INode](a.inputs, transform), a.f, a.alist) case b: Bind[s,T] => new BindNode[s,T]( transform(b.in), x => transform(b.f(x))) case v: Value[T] => constant(v.value) + case t: TransformCapture => constant(() => t.f) case o: Optional[s,T] => o.a match { case None => constant( () => o.f(None) ) case Some(i) => single[s,T](transform(i), x => o.f(Some(x))) diff --git a/util/collection/Settings.scala b/util/collection/Settings.scala index 783956f2a..faa2577cf 100644 --- a/util/collection/Settings.scala +++ b/util/collection/Settings.scala @@ -58,6 +58,9 @@ trait Init[Scope] type ScopeLocal = ScopedKey[_] => Seq[Setting[_]] type MapConstant = ScopedKey ~> Option + /** The result of this initialization is the composition of applied transformations. + * This can be useful when dealing with dynamic Initialize values. */ + lazy val capturedTransformations: Initialize[Initialize ~> Initialize] = new TransformCapture(idK[Initialize]) def setting[T](key: ScopedKey[T], init: Initialize[T], pos: SourcePosition = NoPosition): Setting[T] = new Setting[T](key, init, pos) def valueStrict[T](value: T): Initialize[T] = pure(() => value) def value[T](value: => T): Initialize[T] = pure(value _) @@ -264,6 +267,14 @@ trait Init[Scope] override def toString = "setting(" + key + ") at " + pos } + private[this] def handleUndefined[T](vr: ValidatedInit[T]): Initialize[T] = vr match { + case Left(undefs) => throw new RuntimeUndefined(undefs) + case Right(x) => x + } + + private[this] lazy val getValidated = + new (ValidatedInit ~> Initialize) { def apply[T](v: ValidatedInit[T]) = handleUndefined[T](v) } + // mainly for reducing generated class count private[this] def validateReferencedT(g: ValidateRef) = new (Initialize ~> ValidatedInit) { def apply[T](i: Initialize[T]) = i validateReferenced g } @@ -302,6 +313,15 @@ trait Init[Scope] trait KeyedInitialize[T] extends Keyed[T, T] { final val transform = idFun[T] } + private[sbt] final class TransformCapture(val f: Initialize ~> Initialize) extends Initialize[Initialize ~> Initialize] + { + def dependencies = Nil + def apply[Z](g2: (Initialize ~> Initialize) => Z): Initialize[Z] = map(this)(g2) + def evaluate(ss: Settings[Scope]): Initialize ~> Initialize = f + def mapReferenced(g: MapScoped) = new TransformCapture(mapReferencedT(g) ∙ f) + def mapConstant(g: MapConstant) = new TransformCapture(mapConstantT(g) ∙ f) + def validateReferenced(g: ValidateRef) = Right(new TransformCapture(getValidated ∙ validateReferencedT(g) ∙ f)) + } private[sbt] final class Bind[S,T](val f: S => Initialize[T], val in: Initialize[S]) extends Initialize[T] { def dependencies = in.dependencies @@ -311,10 +331,6 @@ trait Init[Scope] def validateReferenced(g: ValidateRef) = (in validateReferenced g).right.map { validIn => new Bind[S,T](s => handleUndefined( f(s) validateReferenced g), validIn) } - def handleUndefined(vr: ValidatedInit[T]): Initialize[T] = vr match { - case Left(undefs) => throw new RuntimeUndefined(undefs) - case Right(x) => x - } def mapConstant(g: MapConstant) = new Bind[S,T](s => f(s) mapConstant g, in mapConstant g) } private[sbt] final class Optional[S,T](val a: Option[Initialize[S]], val f: Option[S] => T) extends Initialize[T]