mirror of https://github.com/sbt/sbt.git
Use ClassTag instead of Manifest
This commit is contained in:
parent
ecd59bd3e1
commit
fbc98ed72e
|
|
@ -16,7 +16,7 @@ import sbt.ConcurrentRestrictions.Tag
|
|||
import sbt.Def.{ Initialize, ScopedKey, Setting, setting }
|
||||
import std.TaskMacro
|
||||
import std.TaskExtra.{ task => mktask, _ }
|
||||
import scala.reflect.ManifestFactory
|
||||
import scala.reflect.{ ClassTag, ManifestFactory }
|
||||
|
||||
/** An abstraction on top of Settings for build configuration and task definition. */
|
||||
sealed trait Scoped extends Equals:
|
||||
|
|
@ -261,6 +261,11 @@ object Scoped:
|
|||
implicit def inputScopedToKey[T](s: InputKey[T]): ScopedKey[InputTask[T]] =
|
||||
ScopedKey(s.scope, s.key)
|
||||
|
||||
private[sbt] def coerceTag[A1: ClassTag]: Manifest[A1] =
|
||||
summon[ClassTag[A1]] match
|
||||
case mf: Manifest[A1] => mf
|
||||
case tag => ManifestFactory.classType[A1](tag.runtimeClass)
|
||||
|
||||
/**
|
||||
* Mixin trait for adding convenience vocabulary associated with specifying the [[Scope]] of a setting.
|
||||
* Allows specification of the Scope or part of the [[Scope]] of a setting being referenced.
|
||||
|
|
@ -593,6 +598,12 @@ object Scoped:
|
|||
// format: off
|
||||
|
||||
type ST[X] = Taskable[X]
|
||||
final class RichTaskable1[A1](t1: ST[A1]) extends RichTaskables[[F[_]] =>> F[A1]](t1)(using AList.single[A1]):
|
||||
type Fun[M[_], Ret] = M[A1] => Ret
|
||||
def identityMap = mapN(identity)
|
||||
protected def convert[M[_], R](f: M[A1] => R) = f
|
||||
end RichTaskable1
|
||||
|
||||
final class RichTaskable2[A, B](t2: (ST[A], ST[B])) extends RichTaskables[AList.Tuple2K[A, B]](t2)(using AList.tuple2[A, B]) {
|
||||
type Fun[M[_], Ret] = (M[A], M[B]) => Ret
|
||||
def identityMap = mapN(mkTuple2)
|
||||
|
|
@ -736,6 +747,7 @@ trait TupleSyntax:
|
|||
|
||||
// this is the least painful arrangement I came up with
|
||||
type ST[T] = Taskable[T]
|
||||
implicit def taskableToTable1[A1](t1: ST[A1]): RichTaskable1[A1] = new RichTaskable1(t1)
|
||||
implicit def t2ToTable2[A, B](t2: (ST[A], ST[B])): RichTaskable2[A, B] = new RichTaskable2(t2)
|
||||
implicit def t3ToTable3[A, B, C](t3: (ST[A], ST[B], ST[C])): RichTaskable3[A, B, C] = new RichTaskable3(t3)
|
||||
implicit def t4ToTable4[A, B, C, D](t4: (ST[A], ST[B], ST[C], ST[D])): RichTaskable4[A, B, C, D] = new RichTaskable4(t4)
|
||||
|
|
@ -763,35 +775,36 @@ end TupleSyntax
|
|||
|
||||
object TupleSyntax extends TupleSyntax
|
||||
|
||||
import Scoped.extendScoped
|
||||
import Scoped.{ coerceTag, extendScoped }
|
||||
|
||||
/** Constructs InputKeys, which are associated with input tasks to define a setting. */
|
||||
object InputKey:
|
||||
def apply[A1: Manifest](
|
||||
|
||||
def apply[A1: ClassTag](
|
||||
label: String,
|
||||
description: String = "",
|
||||
rank: Int = KeyRanks.DefaultInputRank
|
||||
): InputKey[A1] =
|
||||
given mf: Manifest[InputTask[A1]] =
|
||||
ManifestFactory.classType[InputTask[A1]](classOf[InputTask[A1]], manifest[A1])
|
||||
given mf: ClassTag[InputTask[A1]] =
|
||||
ManifestFactory.classType[InputTask[A1]](classOf[InputTask[A1]], coerceTag[A1])
|
||||
apply(AttributeKey[InputTask[A1]](label, description, rank))
|
||||
|
||||
def apply[A1: Manifest](
|
||||
def apply[A1: ClassTag](
|
||||
label: String,
|
||||
description: String,
|
||||
extend1: Scoped,
|
||||
extendN: Scoped*
|
||||
): InputKey[A1] = apply(label, description, KeyRanks.DefaultInputRank, extend1, extendN: _*)
|
||||
|
||||
def apply[A1: Manifest](
|
||||
def apply[A1: ClassTag](
|
||||
label: String,
|
||||
description: String,
|
||||
rank: Int,
|
||||
extend1: Scoped,
|
||||
extendN: Scoped*
|
||||
): InputKey[A1] =
|
||||
given mf: Manifest[InputTask[A1]] =
|
||||
ManifestFactory.classType[InputTask[A1]](classOf[InputTask[A1]], manifest[A1])
|
||||
given mf: ClassTag[InputTask[A1]] =
|
||||
ManifestFactory.classType[InputTask[A1]](classOf[InputTask[A1]], coerceTag[A1])
|
||||
apply(AttributeKey[InputTask[A1]](label, description, extendScoped(extend1, extendN), rank))
|
||||
|
||||
def apply[A1](akey: AttributeKey[InputTask[A1]]): InputKey[A1] =
|
||||
|
|
@ -801,49 +814,63 @@ end InputKey
|
|||
|
||||
/** Constructs TaskKeys, which are associated with tasks to define a setting. */
|
||||
object TaskKey:
|
||||
def apply[A1: Manifest](
|
||||
def apply[A1: ClassTag](label: String): TaskKey[A1] =
|
||||
apply[A1](
|
||||
label = label,
|
||||
description = "",
|
||||
rank = Int.MaxValue,
|
||||
)
|
||||
|
||||
def apply[A1: ClassTag](label: String, description: String): TaskKey[A1] =
|
||||
apply[A1](
|
||||
label = label,
|
||||
description = description,
|
||||
rank = Int.MaxValue,
|
||||
)
|
||||
|
||||
def apply[A1: ClassTag](
|
||||
label: String,
|
||||
description: String = "",
|
||||
rank: Int = KeyRanks.DefaultTaskRank
|
||||
description: String,
|
||||
rank: Int,
|
||||
): TaskKey[A1] =
|
||||
given mf: Manifest[Task[A1]] =
|
||||
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], manifest[A1])
|
||||
given mf: ClassTag[Task[A1]] =
|
||||
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], coerceTag[A1])
|
||||
apply(AttributeKey[Task[A1]](label, description, rank))
|
||||
|
||||
def apply[A1: Manifest](
|
||||
def apply[A1: ClassTag](
|
||||
label: String,
|
||||
description: String,
|
||||
extend1: Scoped,
|
||||
extendN: Scoped*
|
||||
): TaskKey[A1] =
|
||||
given mf: Manifest[Task[A1]] =
|
||||
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], manifest[A1])
|
||||
given mf: ClassTag[Task[A1]] =
|
||||
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], coerceTag[A1])
|
||||
apply(AttributeKey[Task[A1]](label, description, extendScoped(extend1, extendN)))
|
||||
|
||||
def apply[A1: Manifest](
|
||||
def apply[A1: ClassTag](
|
||||
label: String,
|
||||
description: String,
|
||||
rank: Int,
|
||||
extend1: Scoped,
|
||||
extendN: Scoped*
|
||||
): TaskKey[A1] =
|
||||
given mf: Manifest[Task[A1]] =
|
||||
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], manifest[A1])
|
||||
given mf: ClassTag[Task[A1]] =
|
||||
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], coerceTag[A1])
|
||||
apply(AttributeKey[Task[A1]](label, description, extendScoped(extend1, extendN), rank))
|
||||
|
||||
def apply[A1](akey: AttributeKey[Task[A1]]): TaskKey[A1] =
|
||||
Scoped.scopedTask(Scope.ThisScope, akey)
|
||||
|
||||
def local[A1: Manifest]: TaskKey[A1] =
|
||||
given mf: Manifest[Task[A1]] =
|
||||
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], manifest[A1])
|
||||
def local[A1: ClassTag]: TaskKey[A1] =
|
||||
given mf: ClassTag[Task[A1]] =
|
||||
ManifestFactory.classType[Task[A1]](classOf[Task[A1]], coerceTag[A1])
|
||||
apply[A1](AttributeKey.local[Task[A1]])
|
||||
|
||||
end TaskKey
|
||||
|
||||
/** Constructs SettingKeys, which are associated with a value to define a basic setting. */
|
||||
object SettingKey:
|
||||
def apply[A1: Manifest: OptJsonWriter](
|
||||
def apply[A1: ClassTag: OptJsonWriter](
|
||||
label: String,
|
||||
): SettingKey[A1] =
|
||||
apply[A1](
|
||||
|
|
@ -852,7 +879,7 @@ object SettingKey:
|
|||
rank = KeyRanks.DefaultSettingRank
|
||||
)
|
||||
|
||||
def apply[A1: Manifest: OptJsonWriter](
|
||||
def apply[A1: ClassTag: OptJsonWriter](
|
||||
label: String,
|
||||
description: String,
|
||||
): SettingKey[A1] =
|
||||
|
|
@ -862,14 +889,14 @@ object SettingKey:
|
|||
rank = KeyRanks.DefaultSettingRank,
|
||||
)
|
||||
|
||||
def apply[A1: Manifest: OptJsonWriter](
|
||||
def apply[A1: ClassTag: OptJsonWriter](
|
||||
label: String,
|
||||
description: String,
|
||||
rank: Int
|
||||
): SettingKey[A1] =
|
||||
apply(AttributeKey[A1](label, description, rank))
|
||||
|
||||
def apply[A1: Manifest: OptJsonWriter](
|
||||
def apply[A1: ClassTag: OptJsonWriter](
|
||||
label: String,
|
||||
description: String,
|
||||
extend1: Scoped,
|
||||
|
|
@ -877,7 +904,7 @@ object SettingKey:
|
|||
): SettingKey[A1] =
|
||||
apply(AttributeKey[A1](label, description, extendScoped(extend1, extendN)))
|
||||
|
||||
def apply[A1: Manifest: OptJsonWriter](
|
||||
def apply[A1: ClassTag: OptJsonWriter](
|
||||
label: String,
|
||||
description: String,
|
||||
rank: Int,
|
||||
|
|
@ -889,7 +916,8 @@ object SettingKey:
|
|||
def apply[A1](akey: AttributeKey[A1]): SettingKey[A1] =
|
||||
Scoped.scopedSetting(Scope.ThisScope, akey)
|
||||
|
||||
def local[A1: Manifest: OptJsonWriter]: SettingKey[A1] = apply[A1](AttributeKey.local[A1])
|
||||
def local[A1: ClassTag: OptJsonWriter]: SettingKey[A1] =
|
||||
apply[A1](AttributeKey.local[A1])
|
||||
|
||||
end SettingKey
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ package std
|
|||
import java.io.File
|
||||
import scala.annotation.tailrec
|
||||
import scala.quoted.*
|
||||
import scala.reflect.ClassTag
|
||||
|
||||
import sbt.util.OptJsonWriter
|
||||
|
||||
|
|
@ -42,21 +43,21 @@ private[sbt] object KeyMacro:
|
|||
}
|
||||
|
||||
private def keyImpl[A1: Type, A2: Type](methodName: String)(
|
||||
f: (String, Expr[Manifest[A1]]) => Expr[A2]
|
||||
f: (String, Expr[ClassTag[A1]]) => Expr[A2]
|
||||
)(using qctx: Quotes): Expr[A2] =
|
||||
val tpe = summon[Type[A1]]
|
||||
f(
|
||||
definingValName(errorMsg(methodName)),
|
||||
Expr.summon[Manifest[A1]].getOrElse(sys.error("Manifest[A] not found for $tpe"))
|
||||
Expr.summon[ClassTag[A1]].getOrElse(sys.error("ClassTag[A] not found for $tpe"))
|
||||
)
|
||||
|
||||
private def keyImpl2[A1: Type, A2: Type](methodName: String)(
|
||||
f: (String, Expr[Manifest[A1]], Expr[OptJsonWriter[A1]]) => Expr[A2]
|
||||
f: (String, Expr[ClassTag[A1]], Expr[OptJsonWriter[A1]]) => Expr[A2]
|
||||
)(using qctx: Quotes): Expr[A2] =
|
||||
val tpe = summon[Type[A1]]
|
||||
f(
|
||||
definingValName(errorMsg(methodName)),
|
||||
Expr.summon[Manifest[A1]].getOrElse(sys.error("Manifest[A] not found for $tpe")),
|
||||
Expr.summon[ClassTag[A1]].getOrElse(sys.error("ClassTag[A] not found for $tpe")),
|
||||
Expr.summon[OptJsonWriter[A1]].getOrElse(sys.error("OptJsonWriter[A] not found for $tpe")),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import xsbti.compile.CompilerCache
|
|||
import scala.annotation.{ nowarn, tailrec }
|
||||
import scala.concurrent.ExecutionContext
|
||||
import scala.concurrent.duration.Duration
|
||||
import scala.reflect.ClassTag
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
/** This class is the entry point for sbt. */
|
||||
|
|
@ -517,11 +518,14 @@ object BuiltinCommands {
|
|||
def sortByRank(keys: Seq[AttributeKey[_]]): Seq[AttributeKey[_]] = keys.sortBy(_.rank)
|
||||
def withDescription(keys: Seq[AttributeKey[_]]): Seq[AttributeKey[_]] =
|
||||
keys.filter(_.description.isDefined)
|
||||
|
||||
def isTask(
|
||||
mf: Manifest[_]
|
||||
)(implicit taskMF: Manifest[Task[_]], inputMF: Manifest[InputTask[_]]): Boolean =
|
||||
mf: ClassTag[_]
|
||||
)(using taskMF: ClassTag[Task[_]], inputMF: ClassTag[InputTask[_]]): Boolean =
|
||||
mf.runtimeClass == taskMF.runtimeClass || mf.runtimeClass == inputMF.runtimeClass
|
||||
|
||||
def topNRanked(n: Int) = (keys: Seq[AttributeKey[_]]) => sortByRank(keys).take(n)
|
||||
|
||||
def highPass(rankCutoff: Int) =
|
||||
(keys: Seq[AttributeKey[_]]) => sortByRank(keys).takeWhile(_.rank <= rankCutoff)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,11 +22,10 @@ final case class ScopedKeyData[A](scoped: ScopedKey[A], value: Any) {
|
|||
"Setting: %s = %s" format (key.manifest.toString, value.toString)
|
||||
)
|
||||
def fold[T](targ: OptManifest[_] => T, itarg: OptManifest[_] => T, s: => T): T =
|
||||
key.manifest.runtimeClass match {
|
||||
key.manifest.runtimeClass match
|
||||
case TaskClass => targ(key.manifest.typeArguments.head)
|
||||
case InputTaskClass => itarg(key.manifest.typeArguments.head)
|
||||
case _ => s
|
||||
}
|
||||
def fmtMf(s: String): OptManifest[_] => String = s format _
|
||||
|
||||
private val TaskClass = classOf[Task[_]]
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import Types.idFun
|
|||
import complete._
|
||||
import DefaultParsers._
|
||||
import scala.annotation.nowarn
|
||||
import scala.reflect.ClassTag
|
||||
|
||||
/**
|
||||
* The resulting `session` and verbose and quiet summaries of the result of a set operation.
|
||||
|
|
@ -352,32 +353,33 @@ private[sbt] object SettingCompletions {
|
|||
def configScalaID(c: String): String = Util.quoteIfKeyword(c.capitalize)
|
||||
|
||||
/** Applies a function on the underlying manifest for T for `key` depending if it is for a `Setting[T]`, `Task[T]`, or `InputTask[T]`. */
|
||||
@nowarn
|
||||
def keyType[S](key: AttributeKey[_])(
|
||||
onSetting: Manifest[_] => S,
|
||||
onTask: Manifest[_] => S,
|
||||
onInput: Manifest[_] => S
|
||||
)(implicit tm: Manifest[Task[_]], im: Manifest[InputTask[_]]): S = {
|
||||
def argTpe = key.manifest.typeArguments.head
|
||||
onSetting: ClassTag[_] => S,
|
||||
onTask: ClassTag[_] => S,
|
||||
onInput: ClassTag[_] => S
|
||||
)(using tm: ClassTag[Task[_]], im: ClassTag[InputTask[_]]): S =
|
||||
def argTpe = key.manifest.typeArguments.head match
|
||||
case m: Manifest[_] => m
|
||||
case _ => sys.error(s"Manifest not found for ${key} typeArgument")
|
||||
val TaskClass = tm.runtimeClass
|
||||
val InputTaskClass = im.runtimeClass
|
||||
key.manifest.runtimeClass match {
|
||||
key.manifest.runtimeClass match
|
||||
case TaskClass => onTask(argTpe)
|
||||
case InputTaskClass => onInput(argTpe)
|
||||
case _ => onSetting(key.manifest)
|
||||
}
|
||||
}
|
||||
|
||||
/** For a Task[T], InputTask[T], or Setting[T], this returns the manifest for T. */
|
||||
def keyUnderlyingType(key: AttributeKey[_]): Manifest[_] = keyType(key)(idFun, idFun, idFun)
|
||||
def keyUnderlyingType(key: AttributeKey[_]): ClassTag[_] =
|
||||
keyType(key)(idFun, idFun, idFun)
|
||||
|
||||
/**
|
||||
* Returns a string representation of the underlying type T for a `key` representing a `Setting[T]`, `Task[T]`, or `InputTask[T]`.
|
||||
* This string representation is currently a cleaned up toString of the underlying Manifest.
|
||||
* This string representation is currently a cleaned up toString of the underlying ClassTag.
|
||||
*/
|
||||
def keyTypeString[T](key: AttributeKey[_]): String = {
|
||||
val mfToString = (mf: Manifest[_]) => complete.TypeString.cleanup(mf.toString)
|
||||
keyType(key)(mfToString, mfToString, mfToString)
|
||||
}
|
||||
def keyTypeString[T](key: AttributeKey[_]): String =
|
||||
val tagToString = (tag: ClassTag[_]) => complete.TypeString.cleanup(tag.toString)
|
||||
keyType(key)(tagToString, tagToString, tagToString)
|
||||
|
||||
/** True if the `key` represents a setting or task that may be appended using an assignment method such as `+=`. */
|
||||
def appendable(key: AttributeKey[_]): Boolean = {
|
||||
|
|
|
|||
|
|
@ -93,15 +93,15 @@ private[sbt] object Settings {
|
|||
addTaskDefinition(Def.setting[Task[Seq[Path]]](key, init, setting.pos)) ::
|
||||
outputsAndStamps(taskKey)
|
||||
}
|
||||
ak.manifest.typeArguments match {
|
||||
case t :: Nil if seqClass.isAssignableFrom(t.runtimeClass) =>
|
||||
ak.manifest.typeArguments match
|
||||
case (t: Manifest[_]) :: Nil if seqClass.isAssignableFrom(t.runtimeClass) =>
|
||||
t.typeArguments match {
|
||||
case p :: Nil if pathClass.isAssignableFrom(p.runtimeClass) => mkSetting[Seq[Path]]
|
||||
case _ => default
|
||||
}
|
||||
case t :: Nil if pathClass.isAssignableFrom(t.runtimeClass) => mkSetting[Path]
|
||||
case _ => default
|
||||
}
|
||||
case (t: Manifest[_]) :: Nil if pathClass.isAssignableFrom(t.runtimeClass) =>
|
||||
mkSetting[Path]
|
||||
case _ => default
|
||||
case _ => Nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ object Dependencies {
|
|||
// val lmCoursierShaded = "io.get-coursier" %% "lm-coursier-shaded" % "2.0.10"
|
||||
val lmCoursierShaded = "org.scala-sbt" %% "librarymanagement-coursier" % "2.0.0-alpha2"
|
||||
|
||||
lazy val sjsonNewVersion = "0.10.0"
|
||||
lazy val sjsonNewVersion = "0.11.0"
|
||||
def sjsonNew(n: String) = Def.setting(
|
||||
"com.eed3si9n" %% n % sjsonNewVersion
|
||||
) // contrabandSjsonNewVersion.value
|
||||
|
|
|
|||
|
|
@ -1,19 +1,21 @@
|
|||
import sbt._, Keys._
|
||||
import Def.Initialize
|
||||
import sbt.TupleSyntax.*
|
||||
|
||||
object Marker extends AutoPlugin {
|
||||
object Marker extends AutoPlugin:
|
||||
override def trigger = allRequirements
|
||||
override def requires = sbt.plugins.JvmPlugin
|
||||
object autoImport {
|
||||
final lazy val Mark = TaskKey[Unit]("mark")
|
||||
final def mark: Initialize[Task[Unit]] = mark(baseDirectory)
|
||||
final def mark(project: Reference): Initialize[Task[Unit]] = mark(baseDirectory in project)
|
||||
final def mark(baseKey: SettingKey[File]): Initialize[Task[Unit]] = baseKey map { base =>
|
||||
val toMark = base / "ran"
|
||||
if(toMark.exists)
|
||||
sys.error("Already ran (" + toMark + " exists)")
|
||||
else
|
||||
IO touch toMark
|
||||
final def mark(project: Reference): Initialize[Task[Unit]] = mark(project / baseDirectory)
|
||||
final def mark(baseKey: SettingKey[File]): Initialize[Task[Unit]] = baseKey.toTaskable mapN {
|
||||
base =>
|
||||
val toMark = base / "ran"
|
||||
if (toMark.exists)
|
||||
sys.error("Already ran (" + toMark + " exists)")
|
||||
else
|
||||
IO touch toMark
|
||||
}
|
||||
}
|
||||
}
|
||||
end Marker
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ $ exists ran
|
|||
$ delete ran
|
||||
|
||||
# single project, aggregate = true on Mark
|
||||
> set aggregate in Mark := true
|
||||
> set Mark / aggregate := true
|
||||
> mark
|
||||
$ exists ran
|
||||
$ delete ran
|
||||
|
||||
# single project, aggregate = false on Mark
|
||||
> set aggregate in Mark := false
|
||||
> set Mark / aggregate := false
|
||||
> mark
|
||||
$ exists ran
|
||||
$ delete ran
|
||||
|
|
@ -58,8 +58,8 @@ $ touch aggregate
|
|||
> reload
|
||||
|
||||
# add tasks to each subproject
|
||||
> set Mark in sub := mark(sub).value
|
||||
> set Mark in sub2 := mark(sub2).value
|
||||
> set sub / Mark := mark(sub).value
|
||||
> set sub2 / Mark := mark(sub2).value
|
||||
|
||||
# check that aggregation works when root project has no task
|
||||
> mark
|
||||
|
|
@ -77,15 +77,15 @@ $ delete sub/ran sub/sub/ran
|
|||
> set Mark := mark.value
|
||||
|
||||
# disable aggregation for sub/mark so that sub2/mark doesn't run
|
||||
> set aggregate in (sub,Mark) := false
|
||||
> set sub / Mark / aggregate := false
|
||||
> mark
|
||||
$ exists ran sub/ran
|
||||
$ absent sub/sub/ran
|
||||
$ delete ran sub/ran
|
||||
|
||||
# the aggregation setting in a leaf shouldn't affect whether it can be run directly
|
||||
> set aggregate in (sub2, Mark) := false
|
||||
> set sub2 / Mark / aggregate := false
|
||||
> sub2/mark
|
||||
$ exists sub/sub/ran
|
||||
$ absent ran sub/ran
|
||||
$ delete sub/sub/ran
|
||||
$ delete sub/sub/ran
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import sbt.util.OptJsonWriter
|
|||
sealed trait AttributeKey[A]:
|
||||
|
||||
/** The runtime evidence for `A`. */
|
||||
def manifest: Manifest[A]
|
||||
def manifest: ClassTag[A]
|
||||
// def classTag: ClassTag[A]
|
||||
|
||||
/** The label is the identifier for the key and is camelCase by convention. */
|
||||
|
|
@ -52,7 +52,7 @@ sealed trait AttributeKey[A]:
|
|||
|
||||
end AttributeKey
|
||||
|
||||
private[sbt] abstract class SharedAttributeKey[T] extends AttributeKey[T] {
|
||||
private[sbt] abstract class SharedAttributeKey[A] extends AttributeKey[A]:
|
||||
override final def toString = label
|
||||
override final def hashCode = label.hashCode
|
||||
override final def equals(o: Any) =
|
||||
|
|
@ -61,74 +61,72 @@ private[sbt] abstract class SharedAttributeKey[T] extends AttributeKey[T] {
|
|||
case _ => false
|
||||
})
|
||||
final def isLocal: Boolean = false
|
||||
}
|
||||
end SharedAttributeKey
|
||||
|
||||
object AttributeKey {
|
||||
def apply[T: Manifest: OptJsonWriter](name: String): AttributeKey[T] =
|
||||
def apply[A: ClassTag: OptJsonWriter](name: String): AttributeKey[A] =
|
||||
make(name, None, Nil, Int.MaxValue)
|
||||
|
||||
def apply[T: Manifest: OptJsonWriter](name: String, rank: Int): AttributeKey[T] =
|
||||
def apply[A: ClassTag: OptJsonWriter](name: String, rank: Int): AttributeKey[A] =
|
||||
make(name, None, Nil, rank)
|
||||
|
||||
def apply[T: Manifest: OptJsonWriter](name: String, description: String): AttributeKey[T] =
|
||||
def apply[A: ClassTag: OptJsonWriter](name: String, description: String): AttributeKey[A] =
|
||||
apply(name, description, Nil)
|
||||
|
||||
def apply[T: Manifest: OptJsonWriter](
|
||||
def apply[A: ClassTag: OptJsonWriter](
|
||||
name: String,
|
||||
description: String,
|
||||
rank: Int
|
||||
): AttributeKey[T] =
|
||||
): AttributeKey[A] =
|
||||
apply(name, description, Nil, rank)
|
||||
|
||||
def apply[T: Manifest: OptJsonWriter](
|
||||
def apply[A: ClassTag: OptJsonWriter](
|
||||
name: String,
|
||||
description: String,
|
||||
extend: Seq[AttributeKey[_]]
|
||||
): AttributeKey[T] =
|
||||
): AttributeKey[A] =
|
||||
apply(name, description, extend, Int.MaxValue)
|
||||
|
||||
def apply[T: Manifest: OptJsonWriter](
|
||||
def apply[A: ClassTag: OptJsonWriter](
|
||||
name: String,
|
||||
description: String,
|
||||
extend: Seq[AttributeKey[_]],
|
||||
rank: Int
|
||||
): AttributeKey[T] =
|
||||
): AttributeKey[A] =
|
||||
make(name, Some(description), extend, rank)
|
||||
|
||||
private[sbt] def copyWithRank[T](a: AttributeKey[T], rank: Int): AttributeKey[T] =
|
||||
make(a.label, a.description, a.extend, rank)(a.manifest, a.optJsonWriter)
|
||||
private[sbt] def copyWithRank[A](a: AttributeKey[A], rank: Int): AttributeKey[A] =
|
||||
make(a.label, a.description, a.extend, rank)(using a.manifest, a.optJsonWriter)
|
||||
|
||||
private[this] def make[T](
|
||||
private[this] def make[A](
|
||||
name: String,
|
||||
description0: Option[String],
|
||||
extend0: Seq[AttributeKey[_]],
|
||||
rank0: Int
|
||||
)(implicit mf: Manifest[T], ojw: OptJsonWriter[T]): AttributeKey[T] =
|
||||
new SharedAttributeKey[T] {
|
||||
)(using mf: ClassTag[A], ojw: OptJsonWriter[A]): AttributeKey[A] =
|
||||
new SharedAttributeKey[A]:
|
||||
require(
|
||||
name.headOption.exists(_.isLower),
|
||||
s"A named attribute key must start with a lowercase letter: $name"
|
||||
)
|
||||
|
||||
def manifest = mf
|
||||
val label = Util.hyphenToCamel(name)
|
||||
def description = description0
|
||||
def extend = extend0
|
||||
def rank = rank0
|
||||
def optJsonWriter = ojw
|
||||
}
|
||||
override def manifest: ClassTag[A] = mf
|
||||
override val label: String = Util.hyphenToCamel(name)
|
||||
override def description: Option[String] = description0
|
||||
override def extend: Seq[AttributeKey[_]] = extend0
|
||||
override def rank: Int = rank0
|
||||
override def optJsonWriter: OptJsonWriter[A] = ojw
|
||||
|
||||
private[sbt] def local[T](implicit mf: Manifest[T], ojw: OptJsonWriter[T]): AttributeKey[T] =
|
||||
new AttributeKey[T] {
|
||||
def manifest = mf
|
||||
def label = LocalLabel
|
||||
def description = None
|
||||
def extend = Nil
|
||||
private[sbt] def local[A](using ct: ClassTag[A], ojw: OptJsonWriter[A]): AttributeKey[A] =
|
||||
new AttributeKey[A]:
|
||||
override def manifest: ClassTag[A] = ct
|
||||
override def label: String = LocalLabel
|
||||
override def description: Option[String] = None
|
||||
override def extend: Seq[AttributeKey[_]] = Nil
|
||||
override def toString = label
|
||||
def isLocal: Boolean = true
|
||||
def rank = Int.MaxValue
|
||||
val optJsonWriter = ojw
|
||||
}
|
||||
override def isLocal: Boolean = true
|
||||
override def rank: Int = Int.MaxValue
|
||||
override val optJsonWriter: OptJsonWriter[A] = ojw
|
||||
|
||||
private[sbt] final val LocalLabel = "$" + "local"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue