2

I'm working on a custom TaskKey that makes a clean that keeps a folder in target directory - it's a database that I don't want to fill everytime.

So I tried something like that:

lazy val cleanOutput = taskKey[Unit]("Prints 'Hello World'")

cleanOutput := clean.value

cleanKeepFiles in cleanOutput <+= target { target => target / "database" }

It seems that the statement in cleanOutput is not taken in consideration.
Even when I do just the following it doesn't work:

cleanKeepFiles in clean <+= target { target => target / "database" }

But the following works:

cleanKeepFiles <+= target { target => target / "database" }

Why is the difference?

Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
Joan
  • 4,079
  • 2
  • 28
  • 37

1 Answers1

3

There are keys, which may have defined values in different scopes (project, configuration or task).

A key can be defined, even if it's not used in any scope, as well as a key can be given a value in any scope. The later doesn't mean that the value will be used by a specific task. It means you can reuse keys declared by sbt for your purposes.

What you do you declare a new taskKey. You define your task to call clean. You then define cleanKeepFiles in the scope of your new task to equal to whatever the value was before, plus your database directory in the target.

The value is set correctly, but the clean task will not look for it in the scope of your task.

You can verify it:

> show cleanOutput::cleanKeepFiles  
[info] List(/home/lpiepiora/Desktop/sbt/stack-overflow/q-24020437/target/.history, /home/lpiepiora/Desktop/sbt/stack-overflow/q-24020437/target/database)

Additionally you can check:

> inspect *:cleanKeepFiles
[info] Setting: scala.collection.Seq[java.io.File] = List(/home/lpiepiora/Desktop/sbt/stack-overflow/q-24020437/target/.history)
[info] Description:
[info]  Files to keep during a clean.
[info] Provided by:
[info]  {file:/home/lpiepiora/Desktop/sbt/stack-overflow/q-24020437/}q-24020437/*:cleanKeepFiles
[info] Defined at:
[info]  (sbt.Defaults) Defaults.scala:278
[info] Dependencies:
[info]  *:history
[info] Reverse dependencies:
[info]  *:clean
[info] Delegates:
[info]  *:cleanKeepFiles
[info]  {.}/*:cleanKeepFiles
[info]  */*:cleanKeepFiles
[info] Related:
[info]  *:cleanOutput::cleanKeepFiles

You can also see that sbt knows, that you have set it in the scope *:cleanOutput::cleanKeepFiles, it is just not using it.

Where it will look for it?. You can check it by inspecting the clean task.

> inspect clean
[info] Task: Unit
[info] Description:
[info]  Deletes files produced by the build, such as generated sources, compiled classes, and task caches.
// next lines are important
[info] Dependencies:
[info]  *:cleanKeepFiles
[info]  *:cleanFiles

You can see that one of the dependencies is *:cleanKeepFiles, the * means Global configuration. This means that the clean task will look for the setting in that scope. You can change your setting to:

cleanKeepFiles += target.value / "database"

This will set it in the correct scope used by the clean task.

Edit

There is a doClean function which you can reuse. Given that, you can define your clean task like this:

val cleanKeepDb = taskKey[Unit]("Cleans folders keeping database")

cleanKeepDb := Defaults.doClean(cleanFiles.value, (cleanKeepFiles in cleanKeepDb).value)

cleanKeepFiles in cleanKeepDb += target.value / "database"
lpiepiora
  • 13,659
  • 1
  • 35
  • 47
  • Good explanation but if I do that I modify the behaviour of `clean` and I wanted to have a custom clean that ignore `database` folder and keep the current `clean` task as it is. – Joan Jun 04 '14 at 09:55
  • 1
    I've updated my answer with the way how you can do it. – lpiepiora Jun 04 '14 at 19:35
  • 1
    This is dramatically better than what I did. Cheers @lpiepiora! – Joan Jun 05 '14 at 10:22