mirror of https://github.com/sbt/sbt.git
Add extension methods for input and output files
It is tedious to write (foo / allInputFiles).value so I added simple extension method macros that expand `foo.inputFiles` to (foo / allInputFiles).value and `foo.outputFiles` to `(foo / allOutputFiles).value`.
This commit is contained in:
parent
f126206231
commit
8e9efbeaac
|
|
@ -34,6 +34,14 @@ object FileChangesMacro {
|
|||
"`changedOutputFiles` can only be called on a task within a task definition macro, such as :=, +=, ++=, or Def.task."
|
||||
)
|
||||
def changedOutputFiles: Option[ChangedFiles] = macro changedOutputFilesImpl[T]
|
||||
@compileTimeOnly(
|
||||
"`inputFiles` can only be called on a task within a task definition macro, such as :=, +=, ++=, or Def.task."
|
||||
)
|
||||
def inputFiles: Seq[NioPath] = macro inputFilesImpl[T]
|
||||
@compileTimeOnly(
|
||||
"`outputFiles` can only be called on a task within a task definition macro, such as :=, +=, ++=, or Def.task."
|
||||
)
|
||||
def outputFiles: Seq[NioPath] = macro outputFilesImpl[T]
|
||||
}
|
||||
def changedInputFilesImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[Option[ChangedFiles]] = {
|
||||
impl[T](c)(c.universe.reify(changedInputFiles), c.universe.reify(inputFileStamps))
|
||||
|
|
@ -50,16 +58,28 @@ object FileChangesMacro {
|
|||
mapKey: c.Expr[TaskKey[Seq[(NioPath, FileStamp)]]]
|
||||
): c.Expr[Option[ChangedFiles]] = {
|
||||
import c.universe._
|
||||
val taskTpe = c.weakTypeOf[TaskKey[T]]
|
||||
lazy val err = "Couldn't expand file change macro."
|
||||
val taskKey = c.Expr[TaskKey[T]](c.macroApplication match {
|
||||
case Select(Apply(_, k :: Nil), _) if k.tpe <:< taskTpe => k
|
||||
case _ => c.abort(c.enclosingPosition, err)
|
||||
})
|
||||
val taskKey = getTaskKey(c)
|
||||
reify {
|
||||
val changes = (changeKey.splice in taskKey.splice).value
|
||||
import sbt.nio.FileStamp.Formats._
|
||||
Previous.runtimeInEnclosingTask(mapKey.splice in taskKey.splice).value.flatMap(changes)
|
||||
}
|
||||
}
|
||||
def inputFilesImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[Seq[NioPath]] = {
|
||||
val taskKey = getTaskKey(c)
|
||||
c.universe.reify((allInputFiles in taskKey.splice).value)
|
||||
}
|
||||
def outputFilesImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[Seq[NioPath]] = {
|
||||
val taskKey = getTaskKey(c)
|
||||
c.universe.reify((allOutputFiles in taskKey.splice).value)
|
||||
}
|
||||
private def getTaskKey[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[TaskKey[T]] = {
|
||||
import c.universe._
|
||||
val taskTpe = c.weakTypeOf[TaskKey[T]]
|
||||
lazy val err = "Couldn't expand file change macro."
|
||||
c.Expr[TaskKey[T]](c.macroApplication match {
|
||||
case Select(Apply(_, k :: Nil), _) if k.tpe <:< taskTpe => k
|
||||
case _ => c.abort(c.enclosingPosition, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ copyFile := Def.task {
|
|||
prev match {
|
||||
case Some(v: Int) if changes.isEmpty => v
|
||||
case _ =>
|
||||
changes.getOrElse((copyFile / allInputFiles).value).foreach { p =>
|
||||
changes.getOrElse(copyFile.inputFiles).foreach { p =>
|
||||
val outDir = baseDirectory.value / "out"
|
||||
IO.createDirectory(outDir)
|
||||
IO.copyFile(p.toFile, outDir / p.getFileName.toString)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ foo / fileInputs += baseDirectory.value.toGlob / "base" / "*.txt"
|
|||
foo / target := baseDirectory.value / "out"
|
||||
foo := {
|
||||
val out = baseDirectory.value / "out"
|
||||
((foo / allInputFiles).value: Seq[Path]).map { p =>
|
||||
foo.inputFiles.map { p =>
|
||||
val f = p.toFile
|
||||
val target = out / f.getName
|
||||
IO.copyFile (f, target)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ checkModified := {
|
|||
val changes = foo.changedInputFiles
|
||||
val modified = changes.map(_.updated).getOrElse(Nil)
|
||||
println(modified)
|
||||
val allFiles = (foo / allInputFiles).value
|
||||
val allFiles = foo.inputFiles
|
||||
if (modified.isEmpty) assert(true)
|
||||
else {
|
||||
assert(modified != allFiles)
|
||||
|
|
@ -21,7 +21,7 @@ checkModified := {
|
|||
|
||||
val checkRemoved = taskKey[Unit]("check that removed files are returned")
|
||||
checkRemoved := Def.taskDyn {
|
||||
val files = (foo / allInputFiles).value
|
||||
val files = foo.inputFiles
|
||||
val removed = foo.changedInputFiles.map(_.deleted).getOrElse(Nil)
|
||||
if (removed.isEmpty) Def.task(assert(true))
|
||||
else Def.task {
|
||||
|
|
@ -32,7 +32,7 @@ checkRemoved := Def.taskDyn {
|
|||
|
||||
val checkAdded = taskKey[Unit]("check that modified files are returned")
|
||||
checkAdded := Def.taskDyn {
|
||||
val files = (foo / allInputFiles).value
|
||||
val files = foo.inputFiles
|
||||
val added = foo.changedInputFiles.map(_.created).getOrElse(Nil)
|
||||
if (added.isEmpty || (files.toSet == added.toSet)) Def.task(assert(true))
|
||||
else Def.task {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ val foo = taskKey[Seq[File]]("Retrieve Foo.txt")
|
|||
|
||||
foo / fileInputs += baseDirectory.value.toGlob / ** / "*.txt"
|
||||
|
||||
foo := (foo / allInputFiles).value.map(_.toFile)
|
||||
foo := foo.inputFiles.map(_.toFile)
|
||||
|
||||
val checkFoo = taskKey[Unit]("Check that the Foo.txt file is retrieved")
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ val bar = taskKey[Seq[File]]("Retrieve Bar.md")
|
|||
|
||||
bar / fileInputs += baseDirectory.value.toGlob / "base" / "subdir" / "nested-subdir" / "*.md"
|
||||
|
||||
bar := (bar / allInputFiles).value.map(_.toFile)
|
||||
bar := bar.inputFiles.map(_.toFile)
|
||||
|
||||
val checkBar = taskKey[Unit]("Check that the Bar.md file is retrieved")
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ val checkAll = taskKey[Unit]("Check that the Bar.md file is retrieved")
|
|||
checkAll := {
|
||||
import sbt.dsl.LinterLevel.Ignore
|
||||
val expected = Set("Foo.txt", "Bar.md").map(baseDirectory.value / "base" / "subdir" / "nested-subdir" / _)
|
||||
val actual = (all / allInputFiles).value.map(_.toFile).toSet
|
||||
val actual = all.inputFiles.map(_.toFile).toSet
|
||||
assert(actual == expected)
|
||||
}
|
||||
|
||||
|
|
@ -55,6 +55,6 @@ depth / fileInputs ++= {
|
|||
|
||||
checkDepth := {
|
||||
val expected = Seq("Bar.md").map(baseDirectory.value / "base/subdir/nested-subdir" / _)
|
||||
val actual = (depth / allInputFiles).value.map(_.toFile)
|
||||
val actual = depth.inputFiles.map(_.toFile)
|
||||
assert(actual == expected)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ compileLib := {
|
|||
val name = path.getFileName.toString
|
||||
objectDir.resolve(name.substring(0, name.lastIndexOf('.')) + ".o")
|
||||
}
|
||||
val allFiles: Seq[Path] = (compileLib / allInputFiles).value
|
||||
val allFiles: Seq[Path] = compileLib.inputFiles
|
||||
val changedFiles: Option[Seq[Path]] = compileLib.changedInputFiles match {
|
||||
case Some(ChangedFiles(c, d, u)) =>
|
||||
d.foreach(p => Files.deleteIfExists(objectPath(p)))
|
||||
|
|
@ -52,7 +52,7 @@ linkLib / target := baseDirectory.value / "out" / "lib"
|
|||
linkLib := {
|
||||
val changedObjects = compileLib.changedOutputFiles
|
||||
val outPath = (linkLib / target).value.toPath
|
||||
val allObjects = (compileLib / allOutputFiles).value.map(_.toString)
|
||||
val allObjects = compileLib.outputFiles.map(_.toString)
|
||||
val logger = streams.value.log
|
||||
linkLib.previous match {
|
||||
case Some(p: Path) if changedObjects.isEmpty =>
|
||||
|
|
@ -90,7 +90,7 @@ compileMain := {
|
|||
logger.info(s"Not building $outPath: no dependencies have changed")
|
||||
p
|
||||
case _ =>
|
||||
(compileMain / allInputFiles).value match {
|
||||
compileMain.inputFiles match {
|
||||
case Seq(main) =>
|
||||
Files.createDirectories(outDir)
|
||||
logger.info(s"Building executable $outPath")
|
||||
|
|
@ -112,7 +112,7 @@ compileMain := {
|
|||
val executeMain = inputKey[Unit]("run the main method")
|
||||
executeMain := {
|
||||
val args = Def.spaceDelimited("<arguments>").parsed
|
||||
val binary: Seq[Path] = (compileMain / allOutputFiles).value
|
||||
val binary: Seq[Path] = compileMain.outputFiles
|
||||
val logger = streams.value.log
|
||||
binary match {
|
||||
case Seq(b) =>
|
||||
|
|
@ -131,7 +131,7 @@ executeMain := {
|
|||
val checkOutput = inputKey[Unit]("check the output value")
|
||||
checkOutput := {
|
||||
val args @ Seq(arg, res) = Def.spaceDelimited("").parsed
|
||||
val binary: Path = (compileMain / allOutputFiles).value.head
|
||||
val binary: Path = compileMain.outputFiles.head
|
||||
val output = RunBinary(binary, args, linkLib.value)
|
||||
assert(output.contains(s"f($arg) = $res"))
|
||||
()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import scala.collection.JavaConverters._
|
|||
val foo = taskKey[Unit]("foo")
|
||||
foo := {
|
||||
val fooTxt = baseDirectory.value / "foo.txt"
|
||||
val _ = println(s"foo inputs: ${(foo / allInputFiles).value}")
|
||||
val _ = println(s"foo inputs: ${foo.inputFiles}")
|
||||
IO.write(fooTxt, "foo")
|
||||
println(s"foo wrote to $foo")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ object Build {
|
|||
lazy val root = (project in file(".")).settings(
|
||||
reloadFile := baseDirectory.value / "reload",
|
||||
foo / fileInputs += baseDirectory.value.toGlob / "foo.txt",
|
||||
foo := (foo / allInputFiles).value,
|
||||
foo := foo.inputFiles,
|
||||
setStringValue := Def.taskDyn {
|
||||
// This hides foo / fileInputs from the input graph
|
||||
Def.taskDyn {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ foo / watchForceTriggerOnAnyChange := true
|
|||
foo / fileInputs := baseDirectory.value.toGlob / "files" / "foo.txt" :: Nil
|
||||
foo / watchTriggers := baseDirectory.value.toGlob / ** / "foo.txt" :: Nil
|
||||
foo := {
|
||||
(foo / allInputFiles).value.foreach { p =>
|
||||
foo.inputFiles.foreach { p =>
|
||||
Files.setLastModifiedTime(p, FileTime.fromMillis(Files.getLastModifiedTime(p).toMillis + 3000))
|
||||
}
|
||||
sbt.nio.Stamps.check(foo).value
|
||||
|
|
|
|||
Loading…
Reference in New Issue