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."
|
"`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]
|
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]] = {
|
def changedInputFilesImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[Option[ChangedFiles]] = {
|
||||||
impl[T](c)(c.universe.reify(changedInputFiles), c.universe.reify(inputFileStamps))
|
impl[T](c)(c.universe.reify(changedInputFiles), c.universe.reify(inputFileStamps))
|
||||||
|
|
@ -50,16 +58,28 @@ object FileChangesMacro {
|
||||||
mapKey: c.Expr[TaskKey[Seq[(NioPath, FileStamp)]]]
|
mapKey: c.Expr[TaskKey[Seq[(NioPath, FileStamp)]]]
|
||||||
): c.Expr[Option[ChangedFiles]] = {
|
): c.Expr[Option[ChangedFiles]] = {
|
||||||
import c.universe._
|
import c.universe._
|
||||||
val taskTpe = c.weakTypeOf[TaskKey[T]]
|
val taskKey = getTaskKey(c)
|
||||||
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)
|
|
||||||
})
|
|
||||||
reify {
|
reify {
|
||||||
val changes = (changeKey.splice in taskKey.splice).value
|
val changes = (changeKey.splice in taskKey.splice).value
|
||||||
import sbt.nio.FileStamp.Formats._
|
import sbt.nio.FileStamp.Formats._
|
||||||
Previous.runtimeInEnclosingTask(mapKey.splice in taskKey.splice).value.flatMap(changes)
|
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 {
|
prev match {
|
||||||
case Some(v: Int) if changes.isEmpty => v
|
case Some(v: Int) if changes.isEmpty => v
|
||||||
case _ =>
|
case _ =>
|
||||||
changes.getOrElse((copyFile / allInputFiles).value).foreach { p =>
|
changes.getOrElse(copyFile.inputFiles).foreach { p =>
|
||||||
val outDir = baseDirectory.value / "out"
|
val outDir = baseDirectory.value / "out"
|
||||||
IO.createDirectory(outDir)
|
IO.createDirectory(outDir)
|
||||||
IO.copyFile(p.toFile, outDir / p.getFileName.toString)
|
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 / target := baseDirectory.value / "out"
|
||||||
foo := {
|
foo := {
|
||||||
val out = baseDirectory.value / "out"
|
val out = baseDirectory.value / "out"
|
||||||
((foo / allInputFiles).value: Seq[Path]).map { p =>
|
foo.inputFiles.map { p =>
|
||||||
val f = p.toFile
|
val f = p.toFile
|
||||||
val target = out / f.getName
|
val target = out / f.getName
|
||||||
IO.copyFile (f, target)
|
IO.copyFile (f, target)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ checkModified := {
|
||||||
val changes = foo.changedInputFiles
|
val changes = foo.changedInputFiles
|
||||||
val modified = changes.map(_.updated).getOrElse(Nil)
|
val modified = changes.map(_.updated).getOrElse(Nil)
|
||||||
println(modified)
|
println(modified)
|
||||||
val allFiles = (foo / allInputFiles).value
|
val allFiles = foo.inputFiles
|
||||||
if (modified.isEmpty) assert(true)
|
if (modified.isEmpty) assert(true)
|
||||||
else {
|
else {
|
||||||
assert(modified != allFiles)
|
assert(modified != allFiles)
|
||||||
|
|
@ -21,7 +21,7 @@ checkModified := {
|
||||||
|
|
||||||
val checkRemoved = taskKey[Unit]("check that removed files are returned")
|
val checkRemoved = taskKey[Unit]("check that removed files are returned")
|
||||||
checkRemoved := Def.taskDyn {
|
checkRemoved := Def.taskDyn {
|
||||||
val files = (foo / allInputFiles).value
|
val files = foo.inputFiles
|
||||||
val removed = foo.changedInputFiles.map(_.deleted).getOrElse(Nil)
|
val removed = foo.changedInputFiles.map(_.deleted).getOrElse(Nil)
|
||||||
if (removed.isEmpty) Def.task(assert(true))
|
if (removed.isEmpty) Def.task(assert(true))
|
||||||
else Def.task {
|
else Def.task {
|
||||||
|
|
@ -32,7 +32,7 @@ checkRemoved := Def.taskDyn {
|
||||||
|
|
||||||
val checkAdded = taskKey[Unit]("check that modified files are returned")
|
val checkAdded = taskKey[Unit]("check that modified files are returned")
|
||||||
checkAdded := Def.taskDyn {
|
checkAdded := Def.taskDyn {
|
||||||
val files = (foo / allInputFiles).value
|
val files = foo.inputFiles
|
||||||
val added = foo.changedInputFiles.map(_.created).getOrElse(Nil)
|
val added = foo.changedInputFiles.map(_.created).getOrElse(Nil)
|
||||||
if (added.isEmpty || (files.toSet == added.toSet)) Def.task(assert(true))
|
if (added.isEmpty || (files.toSet == added.toSet)) Def.task(assert(true))
|
||||||
else Def.task {
|
else Def.task {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ val foo = taskKey[Seq[File]]("Retrieve Foo.txt")
|
||||||
|
|
||||||
foo / fileInputs += baseDirectory.value.toGlob / ** / "*.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")
|
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 / 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")
|
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 := {
|
checkAll := {
|
||||||
import sbt.dsl.LinterLevel.Ignore
|
import sbt.dsl.LinterLevel.Ignore
|
||||||
val expected = Set("Foo.txt", "Bar.md").map(baseDirectory.value / "base" / "subdir" / "nested-subdir" / _)
|
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)
|
assert(actual == expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,6 +55,6 @@ depth / fileInputs ++= {
|
||||||
|
|
||||||
checkDepth := {
|
checkDepth := {
|
||||||
val expected = Seq("Bar.md").map(baseDirectory.value / "base/subdir/nested-subdir" / _)
|
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)
|
assert(actual == expected)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ compileLib := {
|
||||||
val name = path.getFileName.toString
|
val name = path.getFileName.toString
|
||||||
objectDir.resolve(name.substring(0, name.lastIndexOf('.')) + ".o")
|
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 {
|
val changedFiles: Option[Seq[Path]] = compileLib.changedInputFiles match {
|
||||||
case Some(ChangedFiles(c, d, u)) =>
|
case Some(ChangedFiles(c, d, u)) =>
|
||||||
d.foreach(p => Files.deleteIfExists(objectPath(p)))
|
d.foreach(p => Files.deleteIfExists(objectPath(p)))
|
||||||
|
|
@ -52,7 +52,7 @@ linkLib / target := baseDirectory.value / "out" / "lib"
|
||||||
linkLib := {
|
linkLib := {
|
||||||
val changedObjects = compileLib.changedOutputFiles
|
val changedObjects = compileLib.changedOutputFiles
|
||||||
val outPath = (linkLib / target).value.toPath
|
val outPath = (linkLib / target).value.toPath
|
||||||
val allObjects = (compileLib / allOutputFiles).value.map(_.toString)
|
val allObjects = compileLib.outputFiles.map(_.toString)
|
||||||
val logger = streams.value.log
|
val logger = streams.value.log
|
||||||
linkLib.previous match {
|
linkLib.previous match {
|
||||||
case Some(p: Path) if changedObjects.isEmpty =>
|
case Some(p: Path) if changedObjects.isEmpty =>
|
||||||
|
|
@ -90,7 +90,7 @@ compileMain := {
|
||||||
logger.info(s"Not building $outPath: no dependencies have changed")
|
logger.info(s"Not building $outPath: no dependencies have changed")
|
||||||
p
|
p
|
||||||
case _ =>
|
case _ =>
|
||||||
(compileMain / allInputFiles).value match {
|
compileMain.inputFiles match {
|
||||||
case Seq(main) =>
|
case Seq(main) =>
|
||||||
Files.createDirectories(outDir)
|
Files.createDirectories(outDir)
|
||||||
logger.info(s"Building executable $outPath")
|
logger.info(s"Building executable $outPath")
|
||||||
|
|
@ -112,7 +112,7 @@ compileMain := {
|
||||||
val executeMain = inputKey[Unit]("run the main method")
|
val executeMain = inputKey[Unit]("run the main method")
|
||||||
executeMain := {
|
executeMain := {
|
||||||
val args = Def.spaceDelimited("<arguments>").parsed
|
val args = Def.spaceDelimited("<arguments>").parsed
|
||||||
val binary: Seq[Path] = (compileMain / allOutputFiles).value
|
val binary: Seq[Path] = compileMain.outputFiles
|
||||||
val logger = streams.value.log
|
val logger = streams.value.log
|
||||||
binary match {
|
binary match {
|
||||||
case Seq(b) =>
|
case Seq(b) =>
|
||||||
|
|
@ -131,7 +131,7 @@ executeMain := {
|
||||||
val checkOutput = inputKey[Unit]("check the output value")
|
val checkOutput = inputKey[Unit]("check the output value")
|
||||||
checkOutput := {
|
checkOutput := {
|
||||||
val args @ Seq(arg, res) = Def.spaceDelimited("").parsed
|
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)
|
val output = RunBinary(binary, args, linkLib.value)
|
||||||
assert(output.contains(s"f($arg) = $res"))
|
assert(output.contains(s"f($arg) = $res"))
|
||||||
()
|
()
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import scala.collection.JavaConverters._
|
||||||
val foo = taskKey[Unit]("foo")
|
val foo = taskKey[Unit]("foo")
|
||||||
foo := {
|
foo := {
|
||||||
val fooTxt = baseDirectory.value / "foo.txt"
|
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")
|
IO.write(fooTxt, "foo")
|
||||||
println(s"foo wrote to $foo")
|
println(s"foo wrote to $foo")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ object Build {
|
||||||
lazy val root = (project in file(".")).settings(
|
lazy val root = (project in file(".")).settings(
|
||||||
reloadFile := baseDirectory.value / "reload",
|
reloadFile := baseDirectory.value / "reload",
|
||||||
foo / fileInputs += baseDirectory.value.toGlob / "foo.txt",
|
foo / fileInputs += baseDirectory.value.toGlob / "foo.txt",
|
||||||
foo := (foo / allInputFiles).value,
|
foo := foo.inputFiles,
|
||||||
setStringValue := Def.taskDyn {
|
setStringValue := Def.taskDyn {
|
||||||
// This hides foo / fileInputs from the input graph
|
// This hides foo / fileInputs from the input graph
|
||||||
Def.taskDyn {
|
Def.taskDyn {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ foo / watchForceTriggerOnAnyChange := true
|
||||||
foo / fileInputs := baseDirectory.value.toGlob / "files" / "foo.txt" :: Nil
|
foo / fileInputs := baseDirectory.value.toGlob / "files" / "foo.txt" :: Nil
|
||||||
foo / watchTriggers := baseDirectory.value.toGlob / ** / "foo.txt" :: Nil
|
foo / watchTriggers := baseDirectory.value.toGlob / ** / "foo.txt" :: Nil
|
||||||
foo := {
|
foo := {
|
||||||
(foo / allInputFiles).value.foreach { p =>
|
foo.inputFiles.foreach { p =>
|
||||||
Files.setLastModifiedTime(p, FileTime.fromMillis(Files.getLastModifiedTime(p).toMillis + 3000))
|
Files.setLastModifiedTime(p, FileTime.fromMillis(Files.getLastModifiedTime(p).toMillis + 3000))
|
||||||
}
|
}
|
||||||
sbt.nio.Stamps.check(foo).value
|
sbt.nio.Stamps.check(foo).value
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue