import org.tmatesoft.svn.core.wc.* //includeTargets << grailsScript("Init") /** * Check and update the app.vcsRevision property in application.properties file and metadata. * May be run directly by `grails update-rev` and normally run by _Events.groovy and eventCompileStart. * The revision in the properties file is checked against the version control system (VCS) revision * and updated if required. * The VCS revision is written to the properties file so that it is available in the compiled war. * The compile is intentionally allowed to go ahead if a handled exception occurs. * VCS currently supported: subversion. */ target(updateVcsRevision: "Check and update the app.vcsRevision property in application.properties file and metadata.") { def result = [:] // Properties file. def url = basedir + "/application.properties" def propertiesFile = new File(url) def fail = { Map m -> updateInMemoryMetadata('Unknown') def writeResult = writePropertiesFileRevision(propertiesFile, 'Unknown') if(writeResult.error) { m.code= writeResult.error.code m.args= writeResult.error.args } result.error = [ code: m.code, args: m.args ] println "Error: UpdateRev script: " + result.error return result } // Get propertiesFile revision. def properitesFileResult = getPropertiesFileRevision(propertiesFile) if(properitesFileResult.error) return fail(code: properitesFileResult.error.code, args: properitesFileResult.error.args) // Get VCS revision. def vcsResult = getVcsRevision() if(vcsResult.error) return fail(code: vcsResult.error.code, args: vcsResult.error.args) // Compare and update. if(properitesFileResult.revision != vcsResult.revision) { println "app.vcsRevision = "+properitesFileResult.revision +', VCS Revision = '+vcsResult.revision updateInMemoryMetadata(vcsResult.revision) // Update application.properties file. def writeResult = writePropertiesFileRevision(propertiesFile, vcsResult.revision) if(writeResult.error) return fail(code: writeResult.error.code, args: writeResult.error.args) } // if(rev != rev) else { println "VCS Revisions match: app.vcsRevision = ${properitesFileResult.revision}, VCS Revision = ${vcsResult.revision}." } // Success. return result } // updateVcsRevision() /** * Get the app.vcsRevision property from properties file. * @retuns A map containing revision and lineNumber otherwise an error map. */ def getPropertiesFileRevision(propertiesFile) { def result = [:] def fail = { Map m -> result.error = [ code: m.code, args: m.args ] return result } if(!propertiesFile.isFile()) return fail(code:"application.properties.file.not.found", args:[propertiesFile.getAbsoluteFile()]) propertiesFile.eachLine { line, lineNumber -> // app.vcsRevision=$Rev: NUM $ if ( line =~ '^app.vcsRevision.' ) { if(line.size() > 23) { result.revision = line[22..-3] result.lineNumber = lineNumber } } } if(!result.revision || !result.lineNumber) return fail(code:"app.vcsRevision.not.found") // Success. return result } // getAppRevision() /** * Get the working copy's base revision from SVN. * @retuns A map containing revision otherwise an error map. */ def getVcsRevision() { def result = [:] def fail = { Map m -> result.error = [ code: m.code, args: m.args ] return result } def wc = new File(basedir) if(!wc.isDirectory()) return fail(code:"vcs.working.copy.not.found", args:[basedir]) // Use svnkit to get the last committed revision. def clientManager = SVNClientManager.newInstance() def wcClient = clientManager.getWCClient() try { result.revision = wcClient.doInfo(wc, SVNRevision.BASE).getCommittedRevision().toString() } catch(org.tmatesoft.svn.core.SVNException e) { fail(code:"vcs.exception", args:[e]) } // Success. return result } // getVcsRevision() /** * Update the in memory metadata if already loaded. * Available vars: binding.variables.each { println it.key } */ def updateInMemoryMetadata(revision) { if(binding.variables.containsKey('metadata')) { def metadata = binding.variables['metadata'] metadata['app.vcsRevision'] = '$Rev: '+revision+' $' } } // updateInMemoryMetadata() /** * Write revision to properties file. * @retuns An error map if any errors. */ def writePropertiesFileRevision(propertiesFile, revision) { def result = [:] def fail = { Map m -> result.error = [ code: m.code, args: m.args ] return result } if(!propertiesFile.isFile()) return fail(code:"application.properties.file.not.found", args:[propertiesFile.getAbsoluteFile()]) def revisionString = 'app.vcsRevision=\\$Rev: '+revision+' \\$' println "Updating application.properties file with: ${revisionString}" def processFileInplace = { file, Closure processText -> def text = file.text file.write(processText(text)) } processFileInplace(propertiesFile) { text -> text.replaceAll('app.vcsRevision.*', revisionString) } // Success. return result } // writePropertiesFileRevision()