Custom Plugin: provide

In the context of writing a custom plugin.
In the apply function of the plugin, I register a task.
This is a copy task.
The task copies a project resource (‘src/main/proto/foo.proto’) into a target directory.

Based on Working With Files it seems like the following should work.

tasks.register<Copy>("retrieveSchema") {
    group = "Retrieve"
    into(project.extensions.schemaDir)
    from('src/main/proto') {
            include("*.proto")
        }
    }
}

It appears that it does not work because it searches the consuming project for the source file rather than the plugin resources.

This question has been previously asked a few times with answers.

This lead me to the following, which does work.

tasks.register<Copy>("retrieveSchema") {
    group = "retrieve"
    val loader = javaClass.classLoader
    val url= loader.getResource("foo.proto")
  
    if (url == null) {
        logger.quiet("resource not available")
    }
    else if  (url.toURI().scheme.equals("jar")) {
        val fs = FileSystems.newFileSystem(url.toURI(), emptyMap<String, Any>())
        into(project.extensions.schemaDir)
        from(project.zipTree(fs.toString())) {
            include("foo.proto")
        }
    }
    else {
        logger.quiet("resource not found in a jar")
    } 
}

While this works it seems wrong.

  • The project.zipTree(fs.toString())
  • Will it always be a jar?

Any advice?

Of course it is searching in the consuming project, that is the context in which your plugin code is executed. :slight_smile:

You were on the right track with the resource, just neither using FileSystem, or doing anything schema-specific, or even using a Copy task is the proper tool here. (Btw. in most cases you do not want Copy, but Sync anyway).

What you want is more like this:

tasks.register("retrieveSchema") {
    group = "retrieve"
    val outputFile = project.extensions.schemaDir.file("foo.proto")
    outputs.file(outputFile).withPropertyName("outputFile")
    doLast {
        val loader = javaClass.classLoader
        val url = loader.getResource("foo.proto")

        if (url == null) {
            logger.quiet("resource not available")
        } else {
            url.openStream().use { input ->
                outputFile.asFile.outputStream().use { output ->
                    input.copyTo(output)
                }
            }
        }
    }
}