I'm running ant 1.8.0 in verbose mode. I have created a manifest containing Implementation-Title, -Version and -Vendor and the resulting JAR contains a manifest with those in it. The JAR's class runs fine. However, output from ant says
[jar] No Implementation-Title set.No Implementation-Version set.No Implementation-Vendor set.
Is this just a bug in ant or am I missing something here?
Thanks
Here's my ant code:
<?xml version="1.0" encoding="UTF-8"?>
<project name="helloworld.makejar" default="makejar" basedir=".">
<target name ="makejar" description="Create a JAR for the HelloWorld project">
<delete file="helloworld.jar" />
<delete file="MANIFEST.MF" />
<manifest file="MANIFEST.MF">
<attribute name="Built-By" value="${user.name}" />
<attribute name="Main-Class" value="project.builder.example.HelloWorld" />
<section name="common">
<attribute name="Specification-Title" value="Example" />
<attribute name="Specification-Version" value="1.0.0" />
<attribute name="Specification-Vendor" value="Example Organization" />
<attribute name="Implementation-Title" value="common" />
<attribute name="Implementation-Version" value="1.0.0 today" />
<attribute name="Implementation-Vendor" value="Acme Corp." />
</section>
</manifest>
<jar jarfile="helloworld.jar"
includes="**/*.class"
basedir="bin"
manifest="MANIFEST.MF"
/>
</target>
<javac srcdir="src" destdir="bin" />
</project>
I think the problem is that the attributes must be defined as children of the manifest element, as opposed to being children of the nested section.
Update
Maybe using an inline manifest element would make a difference. The following snippet is from the Ant docs:
<jar destfile="test.jar" basedir=".">
<include name="build"/>
<manifest>
<!-- Who is building this jar? -->
<attribute name="Built-By" value="${user.name}"/>
<!-- Information about the program itself -->
<attribute name="Implementation-Vendor" value="ACME inc."/>
<attribute name="Implementation-Title" value="GreatProduct"/>
<attribute name="Implementation-Version" value="1.0.0beta2"/>
<!-- details -->
<section name="common/MyClass.class">
<attribute name="Sealed" value="false"/>
</section>
</manifest>
</jar>
Related
I would like to call a macro from inside an element of another macro.
Let's suppose I have the following macro:
<macrodef name="jc">
<attribute name="name" />
<attribute name="destdir" />
<element name="fileset-list" optional="false" />
<sequential>
<jar destfile="#{destdir}${file.separator}#{name}.jar" update="false">
<fileset-list />
<manifest>
<attribute name="Manifest-Version" value="1.0" />
</manifest>
</jar>
</sequential>
</macrodef>
and another macro
<macrodef name="defaultfs" description="Defines the default fileset">
<attribute name="path" />
<sequential>
<fileset dir="${dir.build.classes}">
<include name="#{path}/**/*.class" />
</fileset>
<fileset dir="${src.ehs}">
<include name="#{path}/**/icons/**" />
<include name="#{path}/**/sounds/**" />
<include name="#{path}/**/*.gif" />
<include name="#{path}/**/*.png" />
<include name="#{path}/**/*.wav" />
<include name="#{path}/**/*.jpg" />
<include name="#{path}/**/*.properties" />
<include name="#{path}/**/*.xml" />
<include name="#{path}/**/jaxb.index" />
</fileset>
</sequential>
</macrodef>
I use these macros as follow:
<jc destdir="${dir.build.jar}" name="thejar">
<fileset-list>
<defaultfs path="org/path/inner" />
</fileset-list>
</jc>
What I get is the following error message:
jar doesn't support the nested "defaultfs" element.
What is wrong?
You could try making macro call within your main macro 'jc' and pass fileset path to consider as an additional attribute
<macrodef name="jc">
<attribute name="name" />
<attribute name="destdir" />
<attribute name="fileset.path.to.consider" />
<sequential>
<jar destfile="#{destdir}${file.separator}#{name}.jar" update="false">
<defaultfs path="#{fileset.path.to.consider}"/>
<manifest>
<attribute name="Manifest-Version" value="1.0" />
</manifest>
</jar>
</sequential>
</macrodef>
And then your main macro call could look like :
<jc destdir="${dir.build.jar}" name="thejar" fileset.path.to.consider="org/path/inner"/>
(not tested, you could give it a try )
I'd like to "map" a bunch of ant properties, based on a prefix (sounds simple enough).
I have a solution, but it's not elegant (having to write out to a properties file, then read it back in!)
Question: Is there a quicker/more generic/simpler/out-of-the-box/straight-forward way of doing the below "load-propertyset" within ANT? (... than the example I've provided below)
(Roughly analogous to the Groovy > ConfigSlurper > Special Environment Configuration behaviour.)
For example:
<?xml version="1.0" encoding="UTF-8"?>
<project name="Config">
<!-- Section 1. (These will be loaded from a property file...) -->
<property name="a.yyy" value="foo" />
<property name="a.zzz" value="cat" />
<property name="b.xxx" value="bar" />
<property name="b.zzz" value="dog" />
<macrodef name="load-propertyset">
<attribute name="prefix" />
<attribute name="outfile" default="123" />
<attribute name="propset" default="123" />
<sequential>
<propertyset id="#{propset}">
<propertyref prefix="#{prefix}" />
<globmapper from="#{prefix}.*" to="*" />
</propertyset>
<echo level="debug">Created propertyset - '#{propset}' from prefix='#{prefix}'</echo>
<tempfile property="#{outfile}" suffix=".properties" deleteonexit="true" />
<echo level="debug">Writing propset to temp file - '${#{outfile}}'</echo>
<echoproperties destfile="${#{outfile}}">
<propertyset refid="#{propset}"/>
</echoproperties>
<echo level="debug">Reading props from temp file - '${#{outfile}}'</echo>
<property file="${#{outfile}}" />
<delete file="${#{outfile}}" />
</sequential>
</macrodef>
<load-propertyset prefix="a" />
<load-propertyset prefix="b" />
<echo>>>> Using variables xxx=${xxx} yyy=${yyy} zzz=${zzz}</echo>
</project>
I'm sure I'm missing something simple, for instance:
Can I reference properties within a propertyset? (e.g. ${myprops.yyy} ?)
I'd like to avoid something like ${${filter}.hostname}.
The third-party Ant-Contrib has an <antcallback> task that takes the <antcall> task and adds the ability to return properties to the caller:
<?xml version="1.0" encoding="UTF-8"?>
<project name="Config" default="run">
<taskdef resource="net/sf/antcontrib/antlib.xml" />
<!-- Section 1. (These will be loaded from a property file...) -->
<property name="a.yyy" value="foo" />
<property name="a.zzz" value="cat" />
<property name="b.xxx" value="bar" />
<property name="b.zzz" value="dog" />
<macrodef name="load-propertyset">
<attribute name="prefix" />
<attribute name="return" />
<sequential>
<antcallback target="-empty-target" return="#{return}">
<propertyset>
<propertyref prefix="#{prefix}" />
<globmapper from="#{prefix}.*" to="*" />
</propertyset>
</antcallback>
</sequential>
</macrodef>
<target name="-empty-target"/>
<target name="run">
<property name="properties-to-return" value="xxx,yyy,zzz"/>
<load-propertyset prefix="a" return="${properties-to-return}"/>
<load-propertyset prefix="b" return="${properties-to-return}"/>
<echo>>>> Using variables xxx=${xxx} yyy=${yyy} zzz=${zzz}</echo>
</target>
</project>
The properties-to-return concept is a bit of a maintenance burden. Luckily, <antcallback> doesn't fail when asked to return a property that wasn't set. Only the properties-to-return property needs to be modified when you want a new mapped property.
I would like to use the fileset in below macrodef.
I wish to change attribute jar to dir so that all jar files in dir can be processed.
<macrodef name="unjartemp">
<attribute name="jar" />
<sequential>
<!-- Remove any existing signatures from a JAR file. -->
<tempfile prefix="unjar-"
destdir="${java.io.tmpdir}" property="temp.file" />
<echo message="Removing signatures from JAR: #{jar}" />
<mkdir dir="${temp.file}" />
<unjar src="#{jar}" dest="${temp.file}" />
<delete file="#{jar}" failonerror="true" />
</sequential>
</macrodef>
To keep it flexible you may use macrodef with nested element attribute for 1-n filesets, f.e.
a macrodef that creates a dirlisting in xmlformat for nested filesets :
<macrodef name="dir2xml">
<attribute name="file"
description="xmlfile for filelisting"/>
<attribute name="roottag"
description="xml root tag"/>
<attribute name="entrytag"
description="xml tag for entry"/>
<element name="fs"
description="nested filesets for listing"/>
<sequential>
<pathconvert
property="files.xml"
dirsep="/"
pathsep="</#{entrytag}>${line.separator} <#{entrytag}>"
>
<!-- 1-n nested fileset(s) -->
<fs/>
</pathconvert>
<!-- create xmlfile -->
<echo message="<#{roottag}>${line.separator} <#{entrytag}>${files.xml}</#{entrytag}>${line.separator}</#{roottag}>" file="#{file}"/>
</sequential>
</macrodef>
Usage :
<dir2xml file="filelistant.xml" entrytag="antfile" roottag="antfilelist">
<fs>
<fileset dir="." includes="**/*.xml"/>
<fileset dir="../ant_xml" includes="**/*.xml"/>
</fs>
</dir2xml>
Add your fileset:
<fileset dir="${jars.dir}" id="jars_to_unjar">
<include name="**/*.jar"/>
</fileset>
call you macros:
<unjartemp filesetref="jars_to_unjar"/>
And you can try this modified macros:
<macrodef name="unjartemp">
<attribute name="filesetref" />
<sequential>
<for param="file">
<fileset refid="#{filesetref}"/>
<sequential>
<!-- Remove any existing signatures from a JAR file. -->
<tempfile prefix="unjar-"
destdir="${java.io.tmpdir}" property="temp.file" />
<echo message="Removing signatures from JAR: #{file}" />
<mkdir dir="${temp.file}" />
<unjar src="#{file}" dest="${temp.file}" />
<delete file="#{file}" failonerror="true" />
</sequential>
</for>
</sequential>
</macrodef>
I want to build my project using ant but I have a small problem. My problem is that I need the output jar have all my .class and all my jar dependencies extracted not zipped.
<project name="ivy example" default="compress" xmlns:ivy="antlib:org.apache.ivy.ant">
<target name="resolve" description="Resolve and retrieve with ivy">
<ivy:resolve />
<ivy:cachepath pathid="compile.path" />
</target>
<target name="compile" depends="resolve" description="compilation">
<mkdir dir="build/classes" />
<javac srcdir="src" destdir="build/classes">
<classpath refid="compile.path" />
</javac>
</target>
<target name="compress" depends="compile">
<jar destfile="output/engine.jar" filesonly="true" update="true">
<fileset dir="build/classes" />
<fileset dir="lib"/>
<manifest>
<attribute name="Created-By" value="vireton"/>
<attribute name="Main-Class" value="HelloIvy"/>
</manifest>
</jar>
<echo>Building .jar file completed successfully!</echo>
</target>
</project>
That code generates my engine.jar with the output classes + dependencies.jar.
I want it to generate my classes and the dependencies extracted.
Can anyone help?
i did it by extracting the dependencies to a tmp directory then make a jar of both directories (src & tmp)
<target name="compress" depends="compile">
<delete file="output/engine.jar" />
<mkdir dir="tmp" />
<unzip dest="tmp">
<fileset dir="lib">
<include name="*.jar" />
</fileset>
</unzip>
<delete dir="tmp/META-INF" />
<jar destfile="output/engine.jar" update="true">
<fileset dir="build/classes" />
<fileset dir="tmp"/>
<manifest>
<attribute name="Created-By" value="vireton"/>
<attribute name="Main-Class" value="HelloIvy"/>
</manifest>
</jar>
</target>
and i found an even better way to do it using
<target name="compress" depends="compile">
<delete file="output/engine.jar" />
<jar destfile="output/engine.jar" update="true">
<zipgroupfileset dir="lib" includes="*.jar"/>
<zipfileset dir="build/classes" />
</jar>
</target>
Extract all the jars of the lib folder to some temporary folder (using the unjar task), then create the engine.jar by adding this temporary folder as a fileset.
Just like you would do it by hand.
You have your dependency jar files available as a path thanks to
<ivy:cachepath pathid="compile.path" />
so the simplest way to bundle them all into your final jar would be (assuming Ant 1.8 or later)
<jar destfile="output/engine.jar" filesonly="true" update="true">
<fileset dir="build/classes" />
<archives>
<zips>
<path refid="compile.path"/>
</zips>
</archives>
<manifest>
<attribute name="Created-By" value="vireton"/>
<attribute name="Main-Class" value="HelloIvy"/>
</manifest>
</jar>
This will read the jars directly from your ivy cache, you don't need to retrieve them into a local lib directory first.
Please, find below a few targets from my ant file:
<fileset id="test-dep-jars" dir="o:/java">
<include name="junit-4.10.jar"/>
<include name="easymock-3.1\easymock-3.1.jar"/>
<include name="easymockclassextension-3.1\easymockclassextension-3.1.jar"/>
</fileset>
<target name="copy-test-deps">
<mkdir dir="${deploy.dir}"/>
<copy todir="${deploy.dir}">
<fileset refid="test-dep-jars"/>
<flattenmapper/>
</copy>
</target>
<target name="jar" depends="copy-test-deps">
<jar destfile="${deploy.dir}/test-${ant.project.name}.jar" basedir="${test.classes.dir}"
includes="**/*.class" filesetmanifest="skip">
<manifest>
<attribute name="Class-Path"
value="${ant.project.name}.jar junit-4.10.jar easymock-3.1.jar easymockclassextension-3.1.jar"/>
</manifest>
</jar>
</target>
My problem is that I have to state the test dependency jars twice - once when defining the test-dep-jars fileset and the second time when specifying the Class-Path manifest attribute of the produced jar.
If I only could get hold on the flattenmapper result, then I would be able to use it in the Class-Path as is.
How can I get hold on the flattenmapper result?
Thanks.
If you want to use flattenmapper you can use following...
<pathconvert property="mf.classpath" pathsep=" ">
<path refid="build.class.path" />
<flattenmapper />
</pathconvert>
<manifest>
<attribute name="Class-Path"
value="${ant.project.name}.jar ${mf.classpath}"/>
</manifest>
I would recommend using the manifestclasspath task instead:
<manifestclasspath property="jar.classpath" jarfile="${jar.file}">
<classpath>
<fileset dir="${deploy.dir}" includes="*.jar"/>
</classpath>
</manifestclasspath>
<jar destfile="${jar.file}" basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="${jar.main.class}" />
<attribute name="Class-Path" value="${jar.classpath}" />
</manifest>
</jar>
It will generate the correct classpath property definition and even works with relative paths (for example if you were to place the dependent jars in sub-directory).