I am using processResources to “filter” build information (timestamp, id, etc.) into a properties file that is then packaged into a jar or war archive and thereby made accessible to a Java-based application. This is a familiar use case and the gradle implementation works well for it.
But I would like to extend this mechanism to non-java-based builds as well. It might be useful to include such a properties file in other packages, which could somehow be read by the code in these packages, parsed, etc.
Would I have to manually invoke processResources for such cases? Or is there a more generic functionality I could use in such cases?
It occurs to me that what I want might better be achieved by a custom task that simply read things like project.version, buildTimestamp and buildNumber properties from memory (perhaps specified on command line) and wrote them out to a file in properties format somewhere. For java-based builds this could be build/resources/main as it is with processResources, but for other types it could be in some other location. An advantage of this scheme would be that it would eliminate the need to create a template file in src/main/resources with the specified properties.
It seems to me that the most reasonable method of implementing such a task would be to define a template file inside the plugin collection where this task would reside. This template could be read in as a resource, filtered with the info, and then written out to the destination file location. But I know of nothing in Gradle that allows a copy to be made from a stream-based as opposed to a file-based source.
The processResources task isn’t special, it’s just a Copy task. You can get the same functionality by creating your own Copy task and using things like filter() or expand().
As for copying from sources that aren’t necessarily files, it’s true only files can be an input to the Copy task but you can easily bridge between steam/archives sources using a TextResource.
Hmm. But these are interfaces and all the concrete implementations I find in Gradle source are internal, not public apis and even these require as constructor parameters other objects from the internal api.
Is there a concrete example that shows how all this might be set up?
but I’d like to specify as the first parameter, the archive to which this code (which will be in a plugin) will belong (‘my archive’, i.o.w, what you’d get from getResourceAsStream() ) but I don’t see how to do that.
OK getting around to doing this, but I can’t actually get the task to execute. --info level output tells me that this is because there are no source files. This is indeed the case but I thought this is what TextResource was supposed to provide.
Your problem is you should not be extending Copy and specifically, you should not be overriding the copy() method. The issue here is that copy() is the task action. What you are doing is overriding this method with what is configuration logic and therefore the copy operation actually never happens.
What I would instead suggest is that you create a task of type Copy and simply configure it as such. Extending task types should only be done when you want to change their behavior. In this case that isn’t what you want. You want a copy task, you just want it configured a certain way.
One thing I’ve never fully understood is the difference between extending a task class and declaring a task with the type of a task class. Probably this is because most of the gradle user guide documentation is geared toward writers of build scripts as opposed to writers of plugins. There is a distinct lack of examples of doing what you suggest in a groovy class inside a plugin jar. I’ve been bitten over and over by this.
In any case, I have now tried still keeping my classes (which do add some important default behavior) but following your suggestion of not trying to do the configuration in a copy() override method. This succeeds, but I had to explicitly define the task’s destinationDir and then not use an into{} closure (which isn’t necessary once destinationDir is defined) in my configuration.
The pattern is pretty simple, put this inside a plugin.
public class MyPlugin implements Plugin<Project> {
public void apply(Project project) {
project.tasks.create("myCopyTask", Copy) {
// put custom task configuration here
}
}
}
Thanks, that’s simple enough. I was trying to avoid creating a separate plugin to do this task and creating the task in another preexisting plugin, but I’m having another buildshiip-only issue doing it my way, and I will now try to do this as you suggest. I will need two plugins to capture the two different flavors of this functionality, but that’s probably the best way to go.
So let me try to cast this remark of yours into a rule-of-thumb:
If you want to to create a version of an existing task for a plugin, don’t extend it via subclassing. Instead create it in a new plugin and apply that plugin. Inside the apply() method, do any configuration necessary.
That about right?
One minor quibble: this doesn’t work outside of build scripts: project.tasks.create("myCopyTask", Copy)
Instead, I had to import the Copy class, and then do project.tasks.create("myCopyTask", Copy.class)