Generating multiple source files from a template


(Schalk Cronjé) #1

Normally when a applying a filter in a Copy task one would just have like a template file and then copy it whilst substituting using filter or expand. I would want to do something slighlty different.

In a specific code generation use case I have N source files and one template file. The source files actually contain data that becomes one property in the expansion of the template file. Let’s say my template file contains

${prop1}
${prop2}
${prop3}

The source files will contain the content that goes into prop1.

What I got so far in my Copy task is

task generator( type : Copy ) {
  from 'examples', {
   include '*.txt'
 }

 into "${buildDir}/fooDir"

 rename /\.txt$/, '.foo'

 eachFile { fcd ->
 }
}

I am stuck in the eachFile closure because somehow I need to figure out to open the source file and the template file and then substitute the content of the source file as a property for the template file.


Is it possible to edit a file while it is in-flight as part of a copy?
(Schalk Cronjé) #2

To answer my one question, one can do the following:

eachFile { fcd ->
  String sourceName = fcd.sourceName.replaceAll( /\.txt$/, '')
  String content = fcd.file.text
  fcd.filter {null}
  fcd.filter ConcatFilter, append : project.file('src/templates/my.template')
  fcd.filter ReplaceTokens, tokens : [
    token1 : content,
    token2 : sourceName
 ]
}

It is very importtant that no filters must have been added before String content = fcd.file.text is executed. This is due to Combining eachFile & filter results in failure. The only way of adding filters are within the eachFile and only after extracting the content of the data file.


(Lance Java) #3

I think it’d be easier to invoke project.copy() in a custom task rather than using the Copy task. Eg:

task generator() {
   def inFiles = fileTree('examples').matching {
      include "*.txt"
   } 
   def template = file("src/templates/my.template") 
   inputs.files inFiles
   inputs.file template
   outputs.dir "$buildDir/fooDir" 
   doLast {
      inFiles.files.each { inFile ->
         copy { 
            from template 
            filter ... 
            into "$buildDir/fooDir/$inFile.name"
         } 
      } 
   } 
} 

(Schalk Cronjé) #4

That would work too.