What is the proper way to copy resoursces out of a plugin's classpath


(Doug Lethin) #1

I’m developing an external gradle plugin that can be imported and used by other gradle projects.

One of the things I want my plugin to do is define a “Copy”-type task which copies a collection of files into the buildDirectory. Something like this:

task generateFile(type: Copy) {
   from "myfile.src"
  into "${buildDir}"
  rename '(.*).src', '$1'
  expand([
           project: project,
  ])
}

However, what I really want to do is pack myfile.src on the classpath of my plugin and pull it from there. My plugin build would have a src dir like this:

src/main/resources/myfile.src

And my plugin source would look something like this:

public class MyPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.task([type: Copy], 'generateFile') {
         from classpath('myfile.src') // This is pseudo-code expressing my desired havior
        into "${project.buildDir}"
        rename '(.*).src', '$1'
        expand([
           project: project,
        ])
}

Is there a way to directly use a copy task in this way? I couldn’t figure out how to do it, so I resorted to something ugly where I have an initial task which get’s a handle to a classloader and call getResourceAsStream(“myfile.src”) and copies that to the target directory, like this:

public class MyPlugin implements Plugin<Project> {
      void apply(Project project) {
        project.task('copyTemplateFiles') << {
           ['myfile'].each {
file ->
            def is = this.class.classLoader.getResourceAsStream("${file}.src")
            File target = new File("${project.buildDir}/${file}.src")
            target.withOutputStream {
os ->
            os << is
          }
            if (is) {
            is.close()
          }
        }
      }
}

The above code is ugly and I can only get it to work if I pass the --no-daemon flag to gradle. When running with the daemon, is turns out to be null. Is there a better way to get the InputStream?

Any help would be greatly appreciated.

Thanks.

Doug


(Peter Niederwieser) #2

One solution is to package the files as a separate artifact, and have the plugin use a configuration and dependency to resolve them from the same repository as the plugin.

Alternatively, you could perhaps use something along the lines of a ‘Copy’ task with ‘from { zipTree(project.buildscript.configurations.classpath.find { it.name == “my-plugin-1.0.jar” } ) }; include “myfile.src”’, but this won’t work for multi-project builds where the plugin dependency is only defined on the root project.

The class loader based solution is another valid approach, but it won’t get much nicer/different. Not sure what the daemon related problem is about.