Is there a way to achieve lazy evaluation for a CopySpec’s filter method’s properties?
The value I’m using there is the runtime configuration’s resolved files, which are missing the transitive dependencies of a project dependency, if it is resolved during configuration phase.
So I’d be thankful for any hint that tackles this problem by the lazy evaluation of the properties, or by making early resolving of the configuration possible.
That’s a general technique for delaying configuration until execution time. It has some caveats though, the most significant of which is that it defeats task dependency inference.
Luke, thanks for that technique, that works fine. If there’s a more elegant method, I’d still be interested though. Here’s my original code, it is the classpath()-Method that resolves the configuration.
well actually I didn’t get it to work yet, I still don’t know to delay reading FilterReader properties (or add the filter later, this is actually a more complex archive task, with several nested CopySpecs.
The best thing to do would be to subclass ‘ReplaceTokens’ and allow it to take a type of factory for the tokens, so the generation can be delayed until execution time.
Thanks, sounds like the way to do this properly. I did succeed with the configuration task by now (adding the whole child spec, not just the filter), but it is quite hacky and blows up the build script.
I came up with a DeferredReplaceTokens class to solve this issue:
import org.apache.tools.ant.filters.ReplaceTokens
/**
* Like ReplaceTokens but with a deferred evaluation of the tokens Hashset to allow
* for generation after dynamic properties like project version have been evaluated.
* Use it like this:
* filter(DeferredReplaceTokens, tokenGenerator: { return createHashSetFromProperties() })
* The tokenGenerator closure will be invoked as late as possible (when the filter runs)
*/
class DeferredReplaceTokens extends FilterReader {
/**
* This is the closure that is expected to return something that can be converted to a Hashset
*/
def tokenGenerator
FilterReader actualReader
public DeferredReplaceTokens(Reader reader) {
super(reader)
}
/**
* On-demand creation of the actual ReplaceToken instance
* @return The reader we delegate to
*/
FilterReader reader() {
if (actualReader == null) {
actualReader = new ReplaceTokens(this.in)
Hashtable tokens = tokenGenerator()
// setTokens is really private, but all gradle example code
// use it like it's public so I will as well
actualReader.tokens = tokens
}
return actualReader
}
@Override
int read(char[] cbuf, int off, int len) throws IOException {
return reader().read(cbuf, off, len)
}
@Override
int read() throws IOException {
return reader().read()
}
@Override
void close() throws IOException {
reader().close()
}
}