I need to script an ant build which reads in the existing version from a META-INF/manifest.mf file and appends to it.
The updating should be possible using the ANT manifest task, however I've had trouble reading the existing version.
As the manifest entries are use key: value rather than key= value I cant read them in using ANT's loadproperties task.
Has anyone done this/ have any ideas?
Thanks
The <manifest>
task should do exactly what you want. It will append new Manifest key=value pairs to an existing Manifest. Any idea why you can't use it?
You can use the <concat>
task with the various filter readers, and then load the result with the <loadproperties>
task. It takes a bit of elbow grease, but it might be a way to read in your damaged Manifest file this way, get the values, and then rewrite a new Manifest file with those old values.
I'd have to see a sample of your existing Manifest and what you want to add to it in order to figure out exactly what you need.
You need to be careful using <loadproperties>
on a manifest: though it appears to work with short values, it fails when the line-length exceeds 70 characters because of the odd way manifest entries wrap. The resulting values are truncated.
I wrote a <scriptdef>
that does what you ask, though it's not fully tested yet.
<!--
Loads entries from a manifest file.
@jar The jar from where to read
@file A manifest file to read
@prefix A prefix to prepend
@section The name of the manifest section to load
-->
<scriptdef name="loadmf" language="javascript" loaderRef="sharedbuild-loaderRef">
<attribute name="jar" />
<attribute name="file" />
<attribute name="prefix" />
<attribute name="section" />
<![CDATA[
var jarname = attributes.get("jar");
var filename = attributes.get("file");
if (jarname != null && filename != null) {
self.fail("Only one of jar or file is required");
}
var prefix = attributes.get("prefix");
if (prefix == null) {
prefix = "";
}
var section = attributes.get("section");
var manifest;
if (jarname != null) {
var jarfile = new java.util.jar.JarFile(new java.io.File(jarname));
manifest = jarfile.getManifest();
} else if (filename != null) {
manifest = new java.util.jar.Manifest(new java.io.FileInputStream(new java.io.File(filename)));
} else {
self.fail("One of jar or file is required");
}
if (manifest == null) {
self.log("No manifest in " + jar);
} else {
var attributes = (section == null) ? manifest.getMainAttributes() : manifest.getAttributes(section);
if (attributes != null) {
var iter = attributes.entrySet().iterator();
while (iter.hasNext()) {
var entry = iter.next();
project.setProperty(prefix + entry.getKey(), entry.getValue());
}
}
}
]]>
</scriptdef>
I'm sure the JavaScript can be improved--I'm no expert--but it seems to work well-enough for me (running AntUnit tests to make sure my OSGi manifests are created correctly.) As an added bonus it loads from either a jar (or ear or war) file or a stand-alone manifest file.
To grep the value of a key from a Manifest use loadproperties, here's a macrodef to get you going =
<macrodef name="mfgrep">
<attribute name="jar"/>
<attribute name="key"/>
<attribute name="update"/>
<sequential>
<loadproperties>
<zipentry zipfile="@{jar}" name="META-INF/MANIFEST.MF"/>
</loadproperties>
<echo>@{key} => ${@{key}}</echo>
<jar jarfile="@{jar}">
<manifest>
<attribute name="@{key}" value="@{update}"/>
</manifest>
</jar>
</sequential>
</macrodef>
<!-- Grep a key from Manifest and update its value -->
<mfgrep
jar="/home/gilreb/temp/test.jar"
key="Manifest-Version"
update="2.0"
/>
optionally you may use nested filterchains within loadproperties
Thanks All,
FYI this is my final code, tested working
This appends a revision number (4th element) to a version without a revision or replaces the revision for a version that already has one.
<available file="META-INF/MANIFEST.MF" property="has.manifest" />
<target name="loadBundleVersion" if="has.manifest">
<!-- load version, if no current build number -->
<loadproperties srcfile="META-INF/MANIFEST.MF">
<filterchain>
<linecontainsregexp>
<regexp pattern="^Bundle-Version: \d*.\d*.\d*\s*$" />
</linecontainsregexp>
</filterchain>
</loadproperties>
</target>
<target name="loadBundleVersionRemoveBuild" unless="Bundle-Version" depends="loadBundleVersion">
<!-- if version not set here we have a current build number so needs to be stripped -->
<loadproperties srcfile="META-INF/MANIFEST.MF">
<filterchain>
<linecontains>
<contains value="Bundle-Version" />
</linecontains>
<tokenfilter>
<replaceregex pattern=".\d*$" replace="" />
</tokenfilter>
</filterchain>
</loadproperties>
</target>
<target name="loadBundleDetails" depends="loadBundleVersionRemoveBuild">
<loadproperties srcfile="META-INF/MANIFEST.MF">
<filterchain>
<linecontains>
<contains value="Bundle-SymbolicName" />
</linecontains>
</filterchain>
</loadproperties>
</target>
<target name="updateManifestVersion" if="has.manifest" depends="loadBundleDetails">
<manifest file="META-INF/MANIFEST.MF" mode="update">
<attribute name="Bundle-Version" value="${Bundle-Version}.${build.number}" />
</manifest>
</target>