mirror of https://github.com/sbt/sbt.git
Fix todos in actions/compile-clean
This commit is contained in:
parent
e1cf43c6bd
commit
ab1aa6d001
|
|
@ -12,70 +12,54 @@ import java.io.File
|
||||||
import scala.quoted.*
|
import scala.quoted.*
|
||||||
import scala.reflect.ClassTag
|
import scala.reflect.ClassTag
|
||||||
|
|
||||||
import sbt.util.OptJsonWriter
|
import sbt.util.{ NoJsonWriter, OptJsonWriter }
|
||||||
|
import sbt.internal.util.{ AttributeKey, KeyTag }
|
||||||
|
|
||||||
private[sbt] object KeyMacro:
|
private[sbt] object KeyMacro:
|
||||||
def settingKeyImpl[A1: Type](
|
def settingKeyImpl[A1: Type](description: Expr[String])(using Quotes): Expr[SettingKey[A1]] =
|
||||||
description: Expr[String]
|
val name = definingValName(errorMsg("settingKey"))
|
||||||
)(using qctx: Quotes): Expr[SettingKey[A1]] =
|
val tag = '{ KeyTag.Setting[A1](${ summonRuntimeClass[A1] }) }
|
||||||
keyImpl2[A1, SettingKey[A1]]("settingKey") { (name, mf, ojw) =>
|
val ojw = Expr
|
||||||
val n = Expr(name)
|
.summon[OptJsonWriter[A1]]
|
||||||
'{
|
.getOrElse(errorAndAbort(s"OptJsonWriter[A] not found for ${Type.show[A1]}"))
|
||||||
SettingKey[A1]($n, $description)($mf, $ojw)
|
'{ SettingKey(AttributeKey($name, $description, Int.MaxValue)(using $tag, $ojw)) }
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def taskKeyImpl[A1: Type](description: Expr[String])(using qctx: Quotes): Expr[TaskKey[A1]] =
|
def taskKeyImpl[A1: Type](description: Expr[String])(using Quotes): Expr[TaskKey[A1]] =
|
||||||
keyImpl[A1, TaskKey[A1]]("taskKey") { (name, mf) =>
|
val name = definingValName(errorMsg("taskKey"))
|
||||||
val n = Expr(name)
|
val tag: Expr[KeyTag[Task[A1]]] = Type.of[A1] match
|
||||||
'{
|
case '[Seq[a]] =>
|
||||||
TaskKey[A1]($n, $description)($mf)
|
'{ KeyTag.SeqTask(${ summonRuntimeClass[a] }) }
|
||||||
}
|
case _ => '{ KeyTag.Task(${ summonRuntimeClass[A1] }) }
|
||||||
}
|
'{ TaskKey(AttributeKey($name, $description, Int.MaxValue)(using $tag, NoJsonWriter())) }
|
||||||
|
|
||||||
def inputKeyImpl[A1: Type](description: Expr[String])(using qctx: Quotes): Expr[InputKey[A1]] =
|
def inputKeyImpl[A1: Type](description: Expr[String])(using Quotes): Expr[InputKey[A1]] =
|
||||||
keyImpl[A1, InputKey[A1]]("inputKey") { (name, mf) =>
|
val name = definingValName(errorMsg("inputTaskKey"))
|
||||||
val n = Expr(name)
|
val tag: Expr[KeyTag[InputTask[A1]]] = '{ KeyTag.InputTask(${ summonRuntimeClass[A1] }) }
|
||||||
'{
|
'{ InputKey(AttributeKey($name, $description, Int.MaxValue)(using $tag, NoJsonWriter())) }
|
||||||
InputKey[A1]($n, $description)($mf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def keyImpl[A1: Type, A2: Type](methodName: String)(
|
def projectImpl(using Quotes): Expr[Project] =
|
||||||
f: (String, Expr[ClassTag[A1]]) => Expr[A2]
|
val name = definingValName(errorMsg2)
|
||||||
)(using qctx: Quotes): Expr[A2] =
|
'{ Project($name, new File($name)) }
|
||||||
val tpe = summon[Type[A1]]
|
|
||||||
f(
|
|
||||||
definingValName(errorMsg(methodName)),
|
|
||||||
Expr.summon[ClassTag[A1]].getOrElse(sys.error("ClassTag[A] not found for $tpe"))
|
|
||||||
)
|
|
||||||
|
|
||||||
private def keyImpl2[A1: Type, A2: Type](methodName: String)(
|
private def summonRuntimeClass[A: Type](using Quotes): Expr[Class[?]] =
|
||||||
f: (String, Expr[ClassTag[A1]], Expr[OptJsonWriter[A1]]) => Expr[A2]
|
val classTag = Expr
|
||||||
)(using qctx: Quotes): Expr[A2] =
|
.summon[ClassTag[A]]
|
||||||
val tpe = summon[Type[A1]]
|
.getOrElse(errorAndAbort(s"ClassTag[${Type.show[A]}] not found"))
|
||||||
f(
|
'{ $classTag.runtimeClass }
|
||||||
definingValName(errorMsg(methodName)),
|
|
||||||
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")),
|
|
||||||
)
|
|
||||||
|
|
||||||
def projectImpl(using qctx: Quotes): Expr[Project] =
|
private def errorAndAbort(msg: String)(using q: Quotes): Nothing =
|
||||||
val name = Expr(definingValName(errorMsg2("project")))
|
q.reflect.report.errorAndAbort(msg)
|
||||||
'{
|
|
||||||
Project($name, new File($name))
|
|
||||||
}
|
|
||||||
|
|
||||||
private def errorMsg(methodName: String): String =
|
private def errorMsg(methodName: String): String =
|
||||||
s"""$methodName must be directly assigned to a val, such as `val x = $methodName[Int]("description")`."""
|
s"""$methodName must be directly assigned to a val, such as `val x = $methodName[Int]("description")`."""
|
||||||
|
|
||||||
private def errorMsg2(methodName: String): String =
|
private def errorMsg2: String =
|
||||||
s"""$methodName must be directly assigned to a val, such as `val x = ($methodName in file("core"))`."""
|
"""project must be directly assigned to a val, such as `val x = project.in(file("core"))`."""
|
||||||
|
|
||||||
private def definingValName(errorMsg: String)(using qctx: Quotes): String =
|
private def definingValName(errorMsg: String)(using qctx: Quotes): Expr[String] =
|
||||||
val term = enclosingTerm
|
val term = enclosingTerm
|
||||||
if term.isValDef then term.name
|
if term.isValDef then Expr(term.name)
|
||||||
else sys.error(errorMsg)
|
else errorAndAbort(errorMsg)
|
||||||
|
|
||||||
def enclosingTerm(using qctx: Quotes) =
|
def enclosingTerm(using qctx: Quotes) =
|
||||||
import qctx.reflect._
|
import qctx.reflect._
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ final case class ScopedKeyData[A](scoped: ScopedKey[A], value: Any) {
|
||||||
def description: String =
|
def description: String =
|
||||||
key.tag match
|
key.tag match
|
||||||
case KeyTag.Task(typeArg) => s"Task: $typeArg"
|
case KeyTag.Task(typeArg) => s"Task: $typeArg"
|
||||||
|
case KeyTag.SeqTask(typeArg) => s"Task: Seq[$typeArg]"
|
||||||
case KeyTag.InputTask(typeArg) => s"Input task: $typeArg"
|
case KeyTag.InputTask(typeArg) => s"Input task: $typeArg"
|
||||||
case KeyTag.Setting(typeArg) => s"Setting: $typeArg = $value"
|
case KeyTag.Setting(typeArg) => s"Setting: $typeArg = $value"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import sbt.nio.file.Glob.{ GlobOps }
|
||||||
import sbt.util.Level
|
import sbt.util.Level
|
||||||
import sjsonnew.JsonFormat
|
import sjsonnew.JsonFormat
|
||||||
import scala.annotation.nowarn
|
import scala.annotation.nowarn
|
||||||
|
import xsbti.{ PathBasedFile, VirtualFileRef }
|
||||||
|
|
||||||
private[sbt] object Clean {
|
private[sbt] object Clean {
|
||||||
|
|
||||||
|
|
@ -142,8 +143,13 @@ private[sbt] object Clean {
|
||||||
private[sbt] object ToSeqPath:
|
private[sbt] object ToSeqPath:
|
||||||
given identitySeqPath: ToSeqPath[Seq[Path]] = identity[Seq[Path]](_)
|
given identitySeqPath: ToSeqPath[Seq[Path]] = identity[Seq[Path]](_)
|
||||||
given seqFile: ToSeqPath[Seq[File]] = _.map(_.toPath)
|
given seqFile: ToSeqPath[Seq[File]] = _.map(_.toPath)
|
||||||
|
given virtualFileRefSeq: ToSeqPath[Seq[VirtualFileRef]] =
|
||||||
|
_.collect { case f: PathBasedFile => f.toPath }
|
||||||
given path: ToSeqPath[Path] = _ :: Nil
|
given path: ToSeqPath[Path] = _ :: Nil
|
||||||
given file: ToSeqPath[File] = _.toPath :: Nil
|
given file: ToSeqPath[File] = _.toPath :: Nil
|
||||||
|
given virtualFileRef: ToSeqPath[VirtualFileRef] =
|
||||||
|
case f: PathBasedFile => Seq(f.toPath)
|
||||||
|
case _ => Nil
|
||||||
end ToSeqPath
|
end ToSeqPath
|
||||||
|
|
||||||
private[this] implicit class ToSeqPathOps[T](val t: T) extends AnyVal {
|
private[this] implicit class ToSeqPathOps[T](val t: T) extends AnyVal {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import sbt.io.IO
|
||||||
import sbt.nio.file.FileAttributes
|
import sbt.nio.file.FileAttributes
|
||||||
import sjsonnew.{ Builder, JsonFormat, Unbuilder, deserializationError }
|
import sjsonnew.{ Builder, JsonFormat, Unbuilder, deserializationError }
|
||||||
import xsbti.compile.analysis.{ Stamp => XStamp }
|
import xsbti.compile.analysis.{ Stamp => XStamp }
|
||||||
|
import xsbti.VirtualFileRef
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A trait that indicates what file stamping implementation should be used to track the state of
|
* A trait that indicates what file stamping implementation should be used to track the state of
|
||||||
|
|
@ -102,65 +103,49 @@ object FileStamp {
|
||||||
private[sbt] final case class Error(exception: IOException) extends FileStamp
|
private[sbt] final case class Error(exception: IOException) extends FileStamp
|
||||||
|
|
||||||
object Formats {
|
object Formats {
|
||||||
implicit val seqPathJsonFormatter: JsonFormat[Seq[Path]] = new JsonFormat[Seq[Path]] {
|
implicit val seqPathJsonFormatter: JsonFormat[Seq[Path]] =
|
||||||
override def write[J](obj: Seq[Path], builder: Builder[J]): Unit = {
|
asStringArray(_.toString, Paths.get(_))
|
||||||
builder.beginArray()
|
implicit val seqFileJsonFormatter: JsonFormat[Seq[File]] =
|
||||||
obj.foreach { path =>
|
asStringArray(_.toString, new File(_))
|
||||||
builder.writeString(path.toString)
|
implicit val seqVirtualFileRefJsonFormatter: JsonFormat[Seq[VirtualFileRef]] =
|
||||||
|
asStringArray(_.id, VirtualFileRef.of)
|
||||||
|
|
||||||
|
implicit val fileJsonFormatter: JsonFormat[File] = fromSeqJsonFormat[File]
|
||||||
|
implicit val pathJsonFormatter: JsonFormat[Path] = fromSeqJsonFormat[Path]
|
||||||
|
implicit val virtualFileRefJsonFormatter: JsonFormat[VirtualFileRef] =
|
||||||
|
fromSeqJsonFormat[VirtualFileRef]
|
||||||
|
|
||||||
|
private def asStringArray[T](toStr: T => String, fromStr: String => T): JsonFormat[Seq[T]] =
|
||||||
|
new JsonFormat[Seq[T]] {
|
||||||
|
override def write[J](obj: Seq[T], builder: Builder[J]): Unit = {
|
||||||
|
builder.beginArray()
|
||||||
|
obj.foreach { x => builder.writeString(toStr(x)) }
|
||||||
|
builder.endArray()
|
||||||
}
|
}
|
||||||
builder.endArray()
|
|
||||||
|
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): Seq[T] =
|
||||||
|
jsOpt match {
|
||||||
|
case Some(js) =>
|
||||||
|
val size = unbuilder.beginArray(js)
|
||||||
|
val res = (1 to size) map { _ =>
|
||||||
|
fromStr(unbuilder.readString(unbuilder.nextElement))
|
||||||
|
}
|
||||||
|
unbuilder.endArray()
|
||||||
|
res
|
||||||
|
case None =>
|
||||||
|
deserializationError("Expected JsArray but found None")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): Seq[Path] =
|
private def fromSeqJsonFormat[T](using seqJsonFormat: JsonFormat[Seq[T]]): JsonFormat[T] =
|
||||||
jsOpt match {
|
new JsonFormat[T] {
|
||||||
case Some(js) =>
|
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): T =
|
||||||
val size = unbuilder.beginArray(js)
|
seqJsonFormat.read(jsOpt, unbuilder).head
|
||||||
val res = (1 to size) map { _ =>
|
|
||||||
Paths.get(unbuilder.readString(unbuilder.nextElement))
|
|
||||||
}
|
|
||||||
unbuilder.endArray()
|
|
||||||
res
|
|
||||||
case None =>
|
|
||||||
deserializationError("Expected JsArray but found None")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
implicit val seqFileJsonFormatter: JsonFormat[Seq[File]] = new JsonFormat[Seq[File]] {
|
override def write[J](obj: T, builder: Builder[J]): Unit =
|
||||||
override def write[J](obj: Seq[File], builder: Builder[J]): Unit = {
|
seqJsonFormat.write(obj :: Nil, builder)
|
||||||
builder.beginArray()
|
|
||||||
obj.foreach { file =>
|
|
||||||
builder.writeString(file.toString)
|
|
||||||
}
|
|
||||||
builder.endArray()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): Seq[File] =
|
|
||||||
jsOpt match {
|
|
||||||
case Some(js) =>
|
|
||||||
val size = unbuilder.beginArray(js)
|
|
||||||
val res = (1 to size) map { _ =>
|
|
||||||
new File(unbuilder.readString(unbuilder.nextElement))
|
|
||||||
}
|
|
||||||
unbuilder.endArray()
|
|
||||||
res
|
|
||||||
case None =>
|
|
||||||
deserializationError("Expected JsArray but found None")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
implicit val fileJsonFormatter: JsonFormat[File] = new JsonFormat[File] {
|
|
||||||
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): File =
|
|
||||||
seqFileJsonFormatter.read(jsOpt, unbuilder).head
|
|
||||||
|
|
||||||
override def write[J](obj: File, builder: Builder[J]): Unit =
|
|
||||||
seqFileJsonFormatter.write(obj :: Nil, builder)
|
|
||||||
}
|
|
||||||
implicit val pathJsonFormatter: JsonFormat[Path] = new JsonFormat[Path] {
|
|
||||||
override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): Path =
|
|
||||||
seqPathJsonFormatter.read(jsOpt, unbuilder).head
|
|
||||||
|
|
||||||
override def write[J](obj: Path, builder: Builder[J]): Unit =
|
|
||||||
seqPathJsonFormatter.write(obj :: Nil, builder)
|
|
||||||
}
|
|
||||||
implicit val seqPathFileStampJsonFormatter: JsonFormat[Seq[(Path, FileStamp)]] =
|
implicit val seqPathFileStampJsonFormatter: JsonFormat[Seq[(Path, FileStamp)]] =
|
||||||
new JsonFormat[Seq[(Path, FileStamp)]] {
|
new JsonFormat[Seq[(Path, FileStamp)]] {
|
||||||
override def write[J](obj: Seq[(Path, FileStamp)], builder: Builder[J]): Unit = {
|
override def write[J](obj: Seq[(Path, FileStamp)], builder: Builder[J]): Unit = {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ import sjsonnew.JsonFormat
|
||||||
|
|
||||||
import scala.annotation.nowarn
|
import scala.annotation.nowarn
|
||||||
import scala.collection.immutable.VectorBuilder
|
import scala.collection.immutable.VectorBuilder
|
||||||
|
import java.io.File
|
||||||
|
import xsbti.VirtualFileRef
|
||||||
|
|
||||||
private[sbt] object Settings {
|
private[sbt] object Settings {
|
||||||
private[sbt] def inject(transformed: Seq[Def.Setting[_]]): Seq[Def.Setting[_]] = {
|
private[sbt] def inject(transformed: Seq[Def.Setting[_]]): Seq[Def.Setting[_]] = {
|
||||||
|
|
@ -68,45 +70,55 @@ private[sbt] object Settings {
|
||||||
setting: Def.Setting[_],
|
setting: Def.Setting[_],
|
||||||
fileOutputScopes: Set[Scope]
|
fileOutputScopes: Set[Scope]
|
||||||
): List[Def.Setting[_]] = {
|
): List[Def.Setting[_]] = {
|
||||||
val attributeKey = setting.key.key
|
setting.key.key.tag match {
|
||||||
attributeKey.tag match {
|
|
||||||
case tag: KeyTag.Task[?] =>
|
case tag: KeyTag.Task[?] =>
|
||||||
def default: List[Def.Setting[_]] = {
|
if pathClass.isAssignableFrom(tag.typeArg) then addOutputAndStampTasks[Path](setting)
|
||||||
val scope = setting.key.scope.copy(task = Select(attributeKey))
|
else if fileClass.isAssignableFrom(tag.typeArg) then addOutputAndStampTasks[File](setting)
|
||||||
if (fileOutputScopes.contains(scope)) {
|
else if virtualFileRefClass.isAssignableFrom(tag.typeArg) then
|
||||||
val sk = setting.asInstanceOf[Def.Setting[Task[Any]]].key
|
addOutputAndStampTasks[VirtualFileRef](setting)
|
||||||
val scopedKey = Keys.dynamicFileOutputs in (sk.scope in sk.key)
|
else addDefaultTasks(setting, fileOutputScopes)
|
||||||
addTaskDefinition {
|
case tag: KeyTag.SeqTask[?] =>
|
||||||
val init: Def.Initialize[Task[Seq[Path]]] = sk(_.map(_ => Nil))
|
if pathClass.isAssignableFrom(tag.typeArg) then addOutputAndStampTasks[Seq[Path]](setting)
|
||||||
Def.setting[Task[Seq[Path]]](scopedKey, init, setting.pos)
|
else if fileClass.isAssignableFrom(tag.typeArg) then
|
||||||
} :: allOutputPathsImpl(scope) :: outputFileStampsImpl(scope) :: cleanImpl(scope) :: Nil
|
addOutputAndStampTasks[Seq[File]](setting)
|
||||||
} else Nil
|
else if virtualFileRefClass.isAssignableFrom(tag.typeArg) then
|
||||||
}
|
addOutputAndStampTasks[Seq[VirtualFileRef]](setting)
|
||||||
def mkSetting[T: JsonFormat: ToSeqPath]: List[Def.Setting[_]] = {
|
else addDefaultTasks(setting, fileOutputScopes)
|
||||||
val sk = setting.asInstanceOf[Def.Setting[Task[T]]].key
|
|
||||||
val taskKey = TaskKey(sk.key) in sk.scope
|
|
||||||
// We create a previous reference so that clean automatically works without the
|
|
||||||
// user having to explicitly call previous anywhere.
|
|
||||||
val init = Previous.runtime(taskKey).zip(taskKey) { case (_, t) =>
|
|
||||||
t.map(implicitly[ToSeqPath[T]].apply)
|
|
||||||
}
|
|
||||||
val key = Def.ScopedKey(taskKey.scope in taskKey.key, Keys.dynamicFileOutputs.key)
|
|
||||||
addTaskDefinition(Def.setting[Task[Seq[Path]]](key, init, setting.pos)) ::
|
|
||||||
outputsAndStamps(taskKey)
|
|
||||||
}
|
|
||||||
if seqClass.isAssignableFrom(tag.typeArg) then
|
|
||||||
// TODO fix this: maybe using the taskKey macro to convey the information
|
|
||||||
// t.typeArguments match {
|
|
||||||
// case p :: Nil if pathClass.isAssignableFrom(p.runtimeClass) => mkSetting[Seq[Path]]
|
|
||||||
// case _ => default
|
|
||||||
// }
|
|
||||||
default
|
|
||||||
else if pathClass.isAssignableFrom(tag.typeArg) then mkSetting[Path]
|
|
||||||
else default
|
|
||||||
case _ => Nil
|
case _ => Nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@nowarn
|
||||||
|
private def addDefaultTasks(
|
||||||
|
setting: Def.Setting[_],
|
||||||
|
fileOutputScopes: Set[Scope]
|
||||||
|
): List[Def.Setting[_]] = {
|
||||||
|
val scope = setting.key.scope.copy(task = Select(setting.key.key))
|
||||||
|
if (fileOutputScopes.contains(scope)) {
|
||||||
|
val sk = setting.asInstanceOf[Def.Setting[Task[Any]]].key
|
||||||
|
val scopedKey = Keys.dynamicFileOutputs in (sk.scope in sk.key)
|
||||||
|
val init: Def.Initialize[Task[Seq[Path]]] = sk(_.map(_ => Nil))
|
||||||
|
addTaskDefinition(Def.setting[Task[Seq[Path]]](scopedKey, init, setting.pos)) ::
|
||||||
|
allOutputPathsImpl(scope) :: outputFileStampsImpl(scope) :: cleanImpl(scope) :: Nil
|
||||||
|
} else Nil
|
||||||
|
}
|
||||||
|
|
||||||
|
@nowarn
|
||||||
|
private def addOutputAndStampTasks[T: JsonFormat: ToSeqPath](
|
||||||
|
setting: Def.Setting[_]
|
||||||
|
): List[Def.Setting[_]] = {
|
||||||
|
val sk = setting.asInstanceOf[Def.Setting[Task[T]]].key
|
||||||
|
val taskKey = TaskKey(sk.key) in sk.scope
|
||||||
|
// We create a previous reference so that clean automatically works without the
|
||||||
|
// user having to explicitly call previous anywhere.
|
||||||
|
val init = Previous.runtime(taskKey).zip(taskKey) { case (_, t) =>
|
||||||
|
t.map(implicitly[ToSeqPath[T]].apply)
|
||||||
|
}
|
||||||
|
val key = Def.ScopedKey(taskKey.scope in taskKey.key, Keys.dynamicFileOutputs.key)
|
||||||
|
addTaskDefinition(Def.setting[Task[Seq[Path]]](key, init, setting.pos)) ::
|
||||||
|
outputsAndStamps(taskKey)
|
||||||
|
}
|
||||||
|
|
||||||
private[sbt] val inject: Def.ScopedKey[_] => Seq[Def.Setting[_]] = scopedKey =>
|
private[sbt] val inject: Def.ScopedKey[_] => Seq[Def.Setting[_]] = scopedKey =>
|
||||||
scopedKey.key match {
|
scopedKey.key match {
|
||||||
case transitiveDynamicInputs.key =>
|
case transitiveDynamicInputs.key =>
|
||||||
|
|
@ -161,7 +173,9 @@ private[sbt] object Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
private[this] val seqClass = classOf[Seq[_]]
|
private[this] val seqClass = classOf[Seq[_]]
|
||||||
private[this] val pathClass = classOf[java.nio.file.Path]
|
private[this] val pathClass = classOf[Path]
|
||||||
|
private val fileClass = classOf[File]
|
||||||
|
private val virtualFileRefClass = classOf[VirtualFileRef]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all of the paths for the regular files described by a glob. Directories and hidden
|
* Returns all of the paths for the regular files described by a glob. Directories and hidden
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,14 @@ $ exists target/out/jvm/scala-2.12.17/compile-clean/test-classes/B.class
|
||||||
|
|
||||||
> Test/clean
|
> Test/clean
|
||||||
$ exists target/cant-touch-this
|
$ exists target/cant-touch-this
|
||||||
# TODO it should clean only test classes
|
$ exists target/out/jvm/scala-2.12.17/compile-clean/classes/A.class
|
||||||
# $ exists target/out/jvm/scala-2.12.17/compile-clean/classes/A.class
|
$ exists target/out/jvm/scala-2.12.17/compile-clean/classes/X.class
|
||||||
# $ exists target/out/jvm/scala-2.12.17/compile-clean/classes/X.class
|
|
||||||
$ absent target/out/jvm/scala-2.12.17/compile-clean/test-classes/B.class
|
$ absent target/out/jvm/scala-2.12.17/compile-clean/test-classes/B.class
|
||||||
|
|
||||||
# compiling everything again, but now cleaning only compile classes
|
# compiling everything again, but now cleaning only compile classes
|
||||||
> Test/products
|
> Test/products
|
||||||
> Compile/clean
|
> Compile/clean
|
||||||
$ exists target/cant-touch-this
|
$ exists target/cant-touch-this
|
||||||
# TODO it should clean only compile classes
|
|
||||||
$ absent target/out/jvm/scala-2.12.17/compile-clean/classes/A.class
|
$ absent target/out/jvm/scala-2.12.17/compile-clean/classes/A.class
|
||||||
# $ exists target/out/jvm/scala-2.12.17/compile-clean/test-classes/B.class
|
$ exists target/out/jvm/scala-2.12.17/compile-clean/test-classes/B.class
|
||||||
# TODO and X has to be kept, because of the cleanKeepFiles override
|
$ exists target/out/jvm/scala-2.12.17/compile-clean/classes/X.class
|
||||||
# $ exists target/out/jvm/scala-2.12.17/compile-clean/classes/X.class
|
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,13 @@ import sjsonnew.*
|
||||||
enum KeyTag[A]:
|
enum KeyTag[A]:
|
||||||
case Setting[A](typeArg: Class[?]) extends KeyTag[A]
|
case Setting[A](typeArg: Class[?]) extends KeyTag[A]
|
||||||
case Task[A](typeArg: Class[?]) extends KeyTag[A]
|
case Task[A](typeArg: Class[?]) extends KeyTag[A]
|
||||||
|
case SeqTask[A](typeArg: Class[?]) extends KeyTag[A]
|
||||||
case InputTask[A](typeArg: Class[?]) extends KeyTag[A]
|
case InputTask[A](typeArg: Class[?]) extends KeyTag[A]
|
||||||
|
|
||||||
override def toString: String = this match
|
override def toString: String = this match
|
||||||
case Setting(typeArg) => typeArg.toString
|
case Setting(typeArg) => typeArg.toString
|
||||||
case Task(typeArg) => s"Task[$typeArg]"
|
case Task(typeArg) => s"Task[$typeArg]"
|
||||||
|
case SeqTask(typeArg) => s"Task[Seq[$typeArg]]"
|
||||||
case InputTask(typeArg) => s"InputTask[$typeArg]"
|
case InputTask(typeArg) => s"InputTask[$typeArg]"
|
||||||
|
|
||||||
def typeArg: Class[?]
|
def typeArg: Class[?]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue