Copying the contents of several directories in ant - ant

The following attempts to make copies of a list of directories. It doesn't copy anything. Are filelists not permitted to reference directories?
<macrodef name="collect-services-from-build-tree">
<attribute name="src" default="NOT SET"/>
<attribute name="target" default="NOT SET"/>
<sequential>
<property name="src" value="#{src}"/>
<property name="target" value="#{target}"/>
<filelist id="packages" dir="${src}">
<!-- more like this -->
<file name="interface/ui/ui-server/target/ui-install"/>
</filelist>
<delete dir="${target}" quiet="true"/>
<mkdir dir="${target}"/>
<copy todir="${target}">
<filelist id="packages"/>
</copy>
</sequential>
</macrodef>

Try changing :
<copy todir="${target}">
<filelist id="packages"/>
</copy>
Into :
<copy todir="${target}">
<filelist refid="packages"/>
</copy>

Related

How to develope a method to substitute repetitive code block

I am new in ant, so I wasn't able to find an approach to make my buld file a bit more elegant. I believe there is an approach to substitute repetitive block of code into my build. So here is build file:
<project basedir="../../../" name="do-report" default="zip-all">
<xmlproperty keeproot="false" file="implementation/xml/ant/properties.xml"/>
<!-- -->
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="${infrastructure-base-dir}/apache-ant-1.9.6/lib/ant-contrib-0.3.jar"/>
</classpath>
</taskdef>
<!-- -->
<target name="clean">
<delete dir="${dita-odt.path.odt-unzipped-base-dir}" includeemptydirs="true" failonerror="no"/>
<delete dir="examples/intermediate/odt-files" includeemptydirs="true" failonerror="no"/>
</target>
<!-- -->
<target name="unzip-writing-odt-file" depends="clean">
<unzip src="${dita-odt.path.writing-odt}" dest="${dita-odt.path.writing-odt-unzipped}"/>
</target>
<!-- -->
<target name="extract-common-paths" depends="unzip-writing-odt-file">
<foreach target="copy-text-path" param="file">
<path>
<fileset dir="${dita-odt.path.text-xml-base-dir}">
<include name="**/content.xml"/>
</fileset>
</path>
</foreach>
</target>
<!-- -->
<target name="copy-text-path" description="copy text-xml path relative to text-xml-base-dir">
<dirname property="text-absolute-dir-path" file="${file}"/>
<property name="absolute-path-text-base-dir" location="${dita-odt.path.text-xml-base-dir}"/>
<pathconvert property="common-path" dirsep="/">
<path location="${text-absolute-dir-path}"/>
<map from="${absolute-path-text-base-dir}/" to=""/>
</pathconvert>
<antcall target="copy-writing-unzipped">
<param name="common-path" value="${common-path}"/>
</antcall>
</target>
<!-- -->
<target name="copy-writing-unzipped">
<echo>${common-path}</echo>
<copy todir="${dita-odt.path.odt-unzipped-base-dir}/${common-path}">
<fileset dir="${dita-odt.path.writing-odt-unzipped}">
<include name="**/*"/>
</fileset>
</copy>
</target>
<!-- -->
<target name="transform-all" depends="extract-common-paths">
<foreach target="transform" param="file">
<path>
<fileset dir="${dita-odt.path.text-xml-base-dir}">
<include name="**/content.xml"/>
</fileset>
</path>
</foreach>
</target>
<!-- -->
<target name="transform">
<basename property="file-base-name" file="${file}"/>
<dirname property="file-dir-absolute-path" file="${file}"/>
<property name="text-xml-base-dir-absolute-path" location="${dita-odt.path.text-xml-base-dir}"/>
<pathconvert property="common-path" dirsep="/">
<path location="${file-dir-absolute-path}"/>
<map from="${text-xml-base-dir-absolute-path}/" to=""/>
</pathconvert>
<!--Substitutes backslashes with forword slashes. Basedir is a reserved property that returns absolute path with separator symbols of the current OS.-->
<pathconvert dirsep="/" property="base-dir-unix">
<path location="${basedir}"/>
</pathconvert>
<echo>TRANSFORM TO: ${dita-odt.path.odt-unzipped-base-dir}/${common-path}/${file-base-name}</echo>
<xslt in="${file}" out="${dita-odt.path.odt-unzipped-base-dir}/${common-path}/${file-base-name}" style="${dita-odt.path.text-odt-xsl}" extension=".xml" force="true">
<param name="dir-path-styles-xml" expression="${dita-odt.path.odt-unzipped-base-dir}/${common-path}"/>
<param name="project-base-dir-absolute-path" expression="${base-dir-unix}"/>
<classpath location="${infrastructure-base-dir}/${dita-odt.text-odt-xsl.processor}"/>
</xslt>
</target>
<!-- -->
<target name="zip-all" depends="transform-all" description="Turns all unzipped text folders into ODT files">
<foreach target="zip-odt" param="file">
<path>
<fileset dir="${dita-odt.path.odt-unzipped-base-dir}" includes="**/content.xml" excludes="writing/**"/>
</path>
</foreach>
</target>
<!-- -->
<target name="zip-odt">
<basename property="file-base-name" file="${file}"/>
<dirname property="file-dir-absolute-path" file="${file}"/>
<!--This property will be used to provided name for the produced ODT file. The document will have the same name as the folder that contains it.-->
<basename property="odt-doc-name" file="${file-dir-absolute-path}.odt"/>
<property name="odt-unzipped-base-dir-absolute-path" location="${dita-odt.path.odt-unzipped-base-dir}"/>
<pathconvert property="common-path" dirsep="/">
<path location="${file-dir-absolute-path}"/>
<map from="${odt-unzipped-base-dir-absolute-path}/" to=""/>
</pathconvert>
<echo>COMMON PATH: ${common-path}</echo>
<zip destfile="examples/intermediate/odt-files/${common-path}/${odt-doc-name}" basedir="${dita-odt.path.odt-unzipped-base-dir}/${common-path}" update="true"/>
</target>
<!-- -->
</project>
So this part of the script does pretty much the same, but shared among almost all the target in the project:
<dirname property="file-dir-absolute-path" file="${file}"/>
<property name="text-xml-base-dir-absolute-path" location="${dita-odt.path.text-xml-base-dir}"/>
<pathconvert property="common-path" dirsep="/">
<path location="${file-dir-absolute-path}"/>
<map from="${text-xml-base-dir-absolute-path}/" to=""/>
</pathconvert>
This part does nothing but to obtain part of a path. For example if ${file} stands for /folder/subfolder1/subfolder2 then take the path after /folder namely subfolder1/subfolder2 and assign it to a property. I this case that property is named common-path that holds same path for all the target. I examined MacroDef Task, but as far as I understand it doesn't return, only accepts some parameters in form of attributes. Anyway, any help would be much appreciated.
You are on the right track in considering <macrodef> to reduce repetitive code.
While it's true that <macrodef> doesn't return anything, <macrodef> can be given the name of a property to set. For example...
<macrodef name="my-hello">
<attribute name="person"/>
<attribute name="output-property"/>
<sequential>
<property name="#{output-property}" value="Hello, #{person}!"/>
</sequential>
</macrodef>
<my-hello person="Riko" output-property="say-hi-to-riko"/>
<echo>my-hello said: ${say-hi-to-riko}</echo>
...outputs...
[echo] my-hello said: Hello, Riko!
In this example, the caller of <my-hello> tells the macrodef to "return" its results in the say-hi-to-riko property.
Knowing this, several of the <target>s in your script can be converted to <macrodef>s that set properties...
<project name="ant-macrodef-pathconvert" default="extract-common-paths">
<taskdef resource="net/sf/antcontrib/antlib.xml" />
<property name="dita-odt.path.text-xml-base-dir" value="C:\temp\dita-odt"/>
<macrodef name="my-pathconvert">
<attribute name="file"/>
<attribute name="common-path-property"/>
<sequential>
<!-- <local> allows multiple calls to a macrodef. -->
<local name="file-dir-absolute-path"/>
<echo>In my-pathconvert for #{file}</echo>
<dirname property="file-dir-absolute-path" file="#{file}"/>
<property name="text-xml-base-dir-absolute-path"
location="${dita-odt.path.text-xml-base-dir}"/>
<pathconvert property="#{common-path-property}" dirsep="/">
<path location="${file-dir-absolute-path}"/>
<map from="${file-dir-absolute-path}/" to=""/>
</pathconvert>
</sequential>
</macrodef>
<macrodef name="copy-text-path"
description="copy text-xml path relative to text-xml-base-dir">
<attribute name="file"/>
<sequential>
<local name="common-path"/>
<echo>In copy-text-path for #{file}</echo>
<my-pathconvert file="#{file}" common-path-property="common-path"/>
<copy-writing-unzipped common-path="${common-path}"/>
</sequential>
</macrodef>
<macrodef name="copy-writing-unzipped">
<attribute name="common-path"/>
<sequential>
<echo>In copy-writing-unzipped for #{common-path}</echo>
<echo>copy task goes here.</echo>
</sequential>
</macrodef>
<target name="extract-common-paths">
<for param="file">
<path>
<fileset dir="${dita-odt.path.text-xml-base-dir}">
<include name="**/content.xml"/>
</fileset>
</path>
<sequential>
<copy-text-path file="#{file}"/>
</sequential>
</for>
</target>
</project>
In general, it's better to prefer calling <macrodef>s over calling <target>s directly. In the above example, <foreach> is replaced with <for> because <for> lets us call <macrodef>s.
Output
[echo] In copy-text-path for C:\temp\dita-odt\dir1\content.xml
[echo] In my-pathconvert for C:\temp\dita-odt\dir1\content.xml
[echo] In copy-writing-unzipped for C:/temp/dita-odt/dir1
[echo] copy task goes here.
[echo] In copy-text-path for C:\temp\dita-odt\dir2\content.xml
[echo] In my-pathconvert for C:\temp\dita-odt\dir2\content.xml
[echo] In copy-writing-unzipped for C:/temp/dita-odt/dir2
[echo] copy task goes here.

Ant Build issue : Additonal folder getting created

need your help at the earliest and I have been breaking my head over this for a while.
Below is my Ant Script.
<property name="build.dir" value="${basedir}/build"/>
<property name="lib.dir" value="${basedir}/lib"/>
<property name="src.dir" value="${basedir}/allocator"/>
<property name="classes.dir" value="${basedir}/classes"/>
<property name="jar.dir" value="${basedir}/jar"/>
<property name="main-class" value="allocator.Allocator"/>
<path id="classpath_ref">
<pathelement path="${basedir}/"/>
<fileset dir="${lib.dir}" includes="*.jar"/>
</path>
<target name="clean">
<delete dir="${classes.dir}" />
<delete dir="${build.dir}" />
<delete dir="${jar.dir}" />
</target>
<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath_ref" includeantruntime="false">
<src path="${basedir}/supportlibraries"/>
<src path="${basedir}/com/xyz/framework"/>
</javac>
<copy todir="${build.dir}"><fileset dir="${src.dir}" excludes="**/*.java"/>
</copy>
</target>
<target name="jar" depends="compile">
<mkdir dir="${jar.dir}"/>
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${build.dir}">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
</manifest>
</jar>
</target>
<target name="run" depends="jar">
<java classname="${main-class}" fork="true" >
<arg line="username"/>
<arg line="password"/>
<classpath>
<path refid="classpath_ref"/>
<pathelement location="${jar.dir}/${ant.project.name}.jar"/>
</classpath>
</java>
</target>
<target name="main" depends="clean,run"/>
</project>
when i try to run the ant build from eclipse it is creating an additional folder allocator, supportlibraries and com/xyz/framework inside the class folder. why is it creating additional folder? because of the additional folders when the run target executes its not able to locate the allocator class. Please let me know if i am missing anything
Remove the <copy> from the "compile" <target>.
The <jar> in the "jar" target should be:
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
</manifest>
</jar>
In the above snippet, basedir is ${classes.dir} instead of ${build.dir}.
I don't see a need for build.dir in your script. All references to it can likely be removed.

how to use fileset in ant macrodef

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>

can't make jar with dependencies extracted in it via ant

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.

Generate manifest class-path from <classpath> in Ant

In the build file below, the jar target refers to the jar.class.path property for the manifest class-path. The compile target refers to project.class.path
There is redundancy here, because jar.class.path and project.class.path are very similar. They must be both updated when libraries are added, which can be a pain if the list of libraries gets very long. Is there a better way? Any solution must be cross-platform and always use relative paths.
Edit:
It should generate the JAR classpath from a fileset and not the other way around, so I can use wildcards to e.g. include all JAR files in a directory.
<?xml version="1.0"?>
<project name="Higgins" default="jar" basedir=".">
<property name="jar.class.path" value="lib/forms-1.2.0.jar lib/BrowserLauncher.jar"/>
<path id="project.class.path">
<pathelement location="build"/>
<fileset dir="lib">
<include name="forms-1.2.0.jar"/>
<include name="BrowserLauncher.jar"/>
</fileset>
</path>
<target name="prepare">
<mkdir dir="build"/>
</target>
<target name="compile" depends="prepare" description="Compile core sources">
<javac srcdir="src"
includes="**"
destdir="build"
debug="true"
source="1.5">
<classpath refid="project.class.path"/>
</javac>
</target>
<target name="jar" depends="compile" description="Generates executable jar file">
<jar jarfile="higgins.jar">
<manifest>
<attribute name="Main-Class" value="nl.helixsoft.higgins.Main"/>
<attribute name="Class-Path" value="${jar.class.path}"/>
</manifest>
<fileset dir="build" includes="**/*.class"/>
<fileset dir="src" includes="**/*.properties"/>
</jar>
</target>
</project>
<path id="build.classpath">
<fileset dir="${basedir}">
<include name="lib/*.jar"/>
</fileset>
</path>
<pathconvert property="manifest.classpath" pathsep=" ">
<path refid="build.classpath"/>
<mapper>
<chainedmapper>
<flattenmapper/>
<globmapper from="*.jar" to="lib/*.jar"/>
</chainedmapper>
</mapper>
</pathconvert>
<target depends="compile" name="buildjar">
<jar jarfile="${basedir}/${test.jar}">
<fileset dir="${build}" />
<manifest>
<attribute name="Main-Class" value="com.mycompany.TestMain"/>
<attribute name="Class-Path" value="${manifest.classpath}"/>
</manifest>
</jar>
</target>
For further information check out this article.
Assuming Ant 1.7 or above, you can use the manifestclasspath task.
<path id="dep.runtime">
<fileset dir="./lib">
<include name="**/*.jar" />
</fileset>
</path>
<property name="dep_cp" value="${toString:dep.runtime}" />
<target name="default">
<manifestclasspath property="manifest_cp" jarfile="myjar.jar">
<classpath refid="dep.runtime" />
</manifestclasspath>
<echo message="Build Classpath: ${dep_cp}" />
<echo message="Manifest Classpath: ${manifest_cp}" />
</target>
If you just want a common subpath shared between two (or more) paths, that is easy to do:
<path id="lib.path>
<fileset dir="lib">
<include name="forms-1.2.0.jar"/>
<include name="BrowserLauncher.jar"/>
</fileset>
</path>
<path id="project.class.path">
<pathelement location="build"/>
<path refid="lib.path"/>
</path>
<property name="jar.class.path" refid="lib.path"/>
EDIT Sorry, I misunderstood the question. Try this:
<property name="jar.class.path" value="lib/forms-1.2.0.jar lib/BrowserLauncher.jar"/>
<path id="project.class.path">
<pathelement location="build"/>
<fileset dir="." includes="${jar.class.path}"/>
</path>
You can use <pathconvert> to convert a path (which can contain a fileset) into a plain string. You'll likely need to <echo> that string to a file, use either <replace> or <replaceregexp> to chop the leading path bits, then finally use <loadfile> to load the manipulated string into the final property.
Implementation left as an exercise to the reader.

Resources