Dynamically write to a file inside a WAR during the archive creation


(Ryan Nelson) #1

In my WAR, I would like to write a file that contains the names of all the files contained within the WAR. In my experimentation, my best solution ended like so:

war {
   ...
 def myFileList = ""
 eachFile { file ->
  myFileList += file.relativePath.toString() + "\n"
 }
 def myFile = file("myFileList.txt")
 myFile << "pre info" + myFileList + "post info"
 from(myFile)
}

This doesn’t work because despite the order of invocation specified in the code, eachFile() gets invoked after the file has already been written to disk, so the string myFileList is empty. I suspect I have a chicken-and-egg problem here with source file creation, but despite trying a few different approaches, nothing seems to quite give me what I need. My requirements are:

  1. The text file must contain the contents of all files written to the WAR 2. I must have the ability to prepend or append strings to the list after the list has been generated 3. The file must be included in the root of the WAR

Any suggestions on how to do this?

EDIT: I did try using war.doLast{}, but couldn’t figure out how to get my file into the final WAR.


(Ryan Nelson) #2

I’ve made a few more cracks at this, but can’t quite seem to get it.

My first alternative idea was to create a shell of a file and use Ant to tokenize the string I want. Something like this:

/warHomeDir/myFileList.txt:

pre info
@TOKEN
post info

build.gradle:

war {
 eachFile { file ->
  myFileList += file.relativePath.toString() + "\n"
 }
     filter(ReplaceTokens, tokens: 'TOKEN': myFileList ])
}

Unfortunately that doesn’t work because eachFile() gets called AS the files are being copied. So the call to filter() comes too late.

Then I tried iterating over the source directly:

war {
 source.each {
  myFileList += file.path
  ...
 }
}

That was a pain, however, because I have to manage the paths myself. Using eachFile() is nice because the relative path is provided by Gradle. So I made one last ditch effort to do it in a second task:

def myFileList = ""
war {
 eachFile { file ->
  myFileList += file.relativePath.toString() + "\n"
 }
}
  task addCache(type: Copy) {
 def myFile = file("myFileList.txt")
 cacheFile << "pre info" + myFileList + "post info"
 from war.rootSpec
 from my File
 into ???
}

I think I might be on the right track here … just add the file to the war after the fact. However, I’m not sure how to use rootSpec to access the path to do this. Any ideas?

Thanks!


(Ryan Nelson) #3

Not sure anyone else is reading, but just in case, I solved the issue by taking some advice from this question, modifying my 3rd try above, and using Ant.

def myFileList = ""
def destArchivePath
war {
    destArchivePath = archivePath
    eachFile { file ->
        myFileList += file.relativePath.toString() + "\n"
    }
}
war.doLast {
 def myFile = file("myFileList.txt")
 cacheFile << "pre info" + myFileList + "post info"
 ant.war(warfile: destArchivePath, update: "true") {
  fileset(file: "myFileList.txt")
 }
    delete(myFile)
}