phreed
phreed

Reputation: 1859

How to: pass a closure (or Gradle Action) as an input to a custom Gradle task?

I want to pass a Gradle closure to a custom task.


@CacheableTask
abstract class FooTask : DefaultTask() {

    @get:Input
    abstract val input: RegularFileProperty

    @get:Input
    abstract val renamer: Property<Action<Path>>

    @TaskAction
    fun generate() {
        val path = input.get().asFile.toPath()
        val result = renamer.get().execute(path)
        logger.quiet("original: $path, final: $result")
    }
}

The usage in a 'build.gradle.kts' would be something like...


tasks {

   register<FooTask>("foo") {
      group = "foo"
      input.set(fooFile)
      renamer.set { filename: String ->
         filename.replace(Regex("(.*)\\bar"), "$1.baz")
      }
    }
}

I am, however, having difficulty getting it to work. For example, it appears that the Action is not serializable which it apparently needs to be.

I have been looking at how the Copy task does this.

https://github.com/gradle/gradle/blob/7ecdf635cb4e94cf6721b9247a983ea1d967a403/subprojects/core/src/main/java/org/gradle/api/internal/file/copy/DefaultCopySpec.java#L447-L455

Upvotes: 2

Views: 794

Answers (1)

phreed
phreed

Reputation: 1859

Starting with the rename method in Copy task After digging around in the source I found how the Transformer class is used. The following appears to work in the fashion I wanted.

import org.gradle.api.Transformer
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.SourceTask
import org.gradle.api.tasks.TaskAction
import java.io.File
import java.util.*

@CacheableTask
abstract class FooTask : SourceTask() {

    private val copyActions = LinkedList<Transformer<File, File>>()

    fun rename(renamer: Transformer<File, File>): FooTask {
        copyActions.add(renamer)
        return this
    }

    @TaskAction
    fun generate() {
        val sourceFileTree = this.source
        sourceFileTree.visit {
            val fileCopyDetails = this@visit
            copyActions.forEach { action ->
                val result = action.transform(fileCopyDetails.file)
                logger.quiet(" ${fileCopyDetails.path} -> $result")
            }
        }
    }
}

The usage in ‘build.gradle.kts’.

tasks {

    register<FooTask>("foo") {
        group = "foo"
        source(layout.projectDirectory.dir("foo").asFileTree.matching {
            include("**/*.foo")
        })
        rename { file ->
            file.parentFile.resolve( file.name.replace(Regex("(.*)\\.foo"), "$1.json")  )
        }
    }
}

Enjoy!

Upvotes: 0

Related Questions