Oh how I love the Groovy!
I just needed to check version numbers of jar files in multiple folders and collate a table like:
While most jar files have the version number in either the Bundle-Version or Implementation-Version attributes of the MANIFEST.MF file, some do not follow this convention, and we need to either look for a file ending in _VERSION, or parse a pom.xml within a META-INF subfolder to get the version number.
Groovy makes it so easy to do this stuff. On top of this, creating the HTML table is a breeze. The icing on the cake is to save the file and open in Firefox in a couple of lines.
import groovy.xml.MarkupBuilder; | |
/* | |
* Given a number of folders, finds all jar files in each folder and retrieves the first version number found using: | |
* 1. the jar manifest (either Bundle-Version or Implementation-Version) | |
* 2. a file name ending in _VERSION, stripping the _VERSION suffix | |
* 3. by parsing a pom.xml file in a subfolder of META-INF and using the text of the version element | |
* Creates an HTML file containing a table showing the version of each jar file name for each folder. | |
* Opens the HTML file in Firefox. | |
*/ | |
def versionFromManifest = { zipFile -> | |
def versionLines = zipFile.getInputStream('META-INF/MANIFEST.MF').filterLine { | |
it.startsWith('Bundle-Version') || it.contains('Implementation-Version') | |
} | |
def versionLine = versionLines.toString().split('\n')[0] | |
versionLine ? (versionLine.split(': ')[1]) : '' | |
} | |
def versionFromVersionFile = { zipFile -> | |
def entry = zipFile.entries().find { it.name.endsWith('_VERSION') } | |
entry ? entry.name - '_VERSION' : '' | |
} | |
def versionFromPom = { zipFile -> | |
def entry = zipFile.entries().find { it.name.matches('META-INF/.*/pom.xml') } | |
if (entry) { | |
def pom = zipFile.getInputStream(entry.name).text | |
def project = new XmlSlurper().parseText(pom) | |
return project.version | |
} | |
} | |
def jarVersions = [:].withDefault { [:] } // Map of maps [jarFileName: [folderDescription: version]] | |
def folderDescriptions = [] | |
def addJarVersions = { folderDescription, folder-> | |
folderDescriptions += folderDescription | |
new File(folder).eachFileMatch(~/.*\.jar/) { f -> | |
def zip = new java.util.zip.ZipFile(f) | |
def version = versionFromManifest(zip) ?: versionFromVersionFile(zip) ?: versionFromPom(zip) ?: 'unknown' | |
jarVersions[f.name][folderDescription] = version | |
} | |
} | |
addJarVersions('ivy', '/local/work/jibx/core/build/ivy/lib') | |
addJarVersions('lib', '/local/work/jibx/core/lib') | |
addJarVersions('zip', '/local/java/tools/jibx/jibx-1.2.3/lib') | |
def writer = new StringWriter() | |
def doc = new MarkupBuilder(writer) | |
doc.html() { | |
head { | |
style(type:'text/css', new File('table.css').text) | |
} | |
body { | |
table() { | |
tr { | |
th() | |
folderDescriptions.each { folderDescription -> | |
th(align:'left', folderDescription) | |
} | |
} | |
(jarVersions.sort() *.key).each { jarName -> | |
tr { | |
td(style:'font-style:italic', jarName) | |
folderDescriptions.each { folderDescription -> | |
td(jarVersions[jarName][folderDescription] ?: 'n/a') | |
} | |
} | |
} | |
} | |
p(style:'font-style:italic;font-size:small;float:right', "Results obtained at ${new Date().dateTimeString}") | |
} | |
} | |
def filename = '/tmp/versions.html' | |
new File(filename).write(writer.toString()) | |
"firefox $filename".execute() |
This would have taken hundreds of lines in Java. Groovy makes it concise, while allowing access to all Java libraries, resulting in code that is readable (if a little alien at first) to a Java developer.