How Ant script execute command for each file - ant

I would like to use ant script set readonly for each file in the directory
but exec doesn't allow filelist:
<target name="readonly">
<exec executable="attrib +r">
<fileset dir="${reset.root.dir}">
<include name="**/*" />
</fileset>
</exec>
</target>
The type doesn't support the
nested "fileset" element.

Try using the apply task instead of exec, it supports <fileset>.

Related

How to specify lib directory for ant task?

I'm currently running an exec task in my build like this:
<target name="bar">
<exec executable="ant">
<arg value="-f"/>
<arg value="/path/to/my/build.xml"/>
<arg value="-lib"/>
<arg value="/path/to/my/libs"/>
</exec>
</target>
I don't really like it and want to replace the exec task with an ant task:
<target name="bar">
<ant antfile="/path/to/my/build.xml"/>
</target>
However, I don't know how to specify the lib directory in this case. Is this possible somehow?
What are you trying to achieve, by launching ANT from within ANT in this manner?
For example if you need custom ANT extensions, the path to these jars can be specified at runtime within the code as follows:
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="${lib.dir}/ant-contrib-0.3.jar"/>
</classpath>
</taskdef>
Better again, you could integrate a dependency management system like Apache ivy to manage 3rd party jar dependencies.
You can call ant script inside an ant script like below.
If you use the attribute inheritrefs="true" any Ids that are set in the parent build script will be passed to child build script as well.
Eg:
<ant antfile="subbuild.xml" inheritrefs="true"/>

How to locally echo Apply task?

Is it possible to execute an apply on a file set and have ant print the command it is executing?
For example:
<target name="test">
<apply executable="ls" failonerror="true" verbose="true" ignoremissing="false">
<fileset dir=".">
<include name="*.xml" />
</fileset>
<arg line="-la" />
</apply>
</target>
I would like the output to be something close to the following, with the key line being:
[apply] ls -la ./build.xml"
E.g.
Buildfile: /home/abarker/NetBeansProjects/TestProject/build.xml
test:
[apply] ls -la ./build.xml
[apply] -rw-r--r-- 1 abarker abarker 29231 Feb 13 11:29 /home/abarker/NetBeansProjects/TestProject/build.xml
[apply] Applied ls to 1 file and 0 directories.
There are several ideas I have:
You can use the outputproperty parameter. This will give you the output of the command in the <apply> task.
You can use fileset reference instead of an actual fileset.
Like this:
<property name="apply.files.prop" refid='apply.files'/>
<echo>The files you're operating on are "${apply.files.prop}"</echo>
<apply executable="ls" failonerror="true" verbose="true" ignoremissing="false">
<fileset refid="apply.files"/>
<arg line="-la" />
</apply>
You can then look at the fileset reference apply.files to see what files the <apply> task is operating on.
You can always add the -debug and -verbose flag when you run ant. This will print exactly what you want and then some -- then some a whole lot. I wish there was a way to turn verbose mode on and off on a particular task, but I don't know how to do that -- at least an easy way to do that.
For debug purposes - Just replace your own executable with echo. Here is an example of how I do it on Windows machines:
<target name="test">
<apply executable="cmd" failonerror="true" verbose="true" ignoremissing="false">
<fileset dir=".">
<include name="*.xml" />
</fileset>
<arg line="/c" />
<arg line="echo" />
<arg line="ls" />
<arg line="-la" />
</apply>
</target>
Normally when you run ant with -v/-verbose flag, it will print each execution of the command (this also includes exec and apply).

modify ant classpath on the fly

I want to use resolvers (ssh) which are dependant on ant classpath.
Something like
<resolvers>
...
<ssh ...
...
</resolvers>
To use it I need jsch in ant classpath. Ant script should depends only on common lib (which also includes resolved jsch dependencies) - to use it on any client PC. Scenario is:
task to download lib.
Extract libs (jsch and etc.)
ivy:configure
But ivy:configure does not have any classpathref param, so it is unclear for me how to load jars I extracted.
Is it possible?
Or, probably, somehow run ant again internally with extended classpath?
Ok,
so my comment to question looked good for me but at the end it did not work.
The only way I found (working way I mean) is to to run ant script with
Download common-lib (with ) which includes all jar-libs required for optional ivy processing
Construct new classpath and run exec on same build file with required target:
<target name="call.task" if="wrapped.task.name">
<path id="ant.class.path">
<fileset dir="${tools.lib.dir}" >
<include name="*.jar" />
</fileset>
<pathelement location="${java.class.path}" />
</path>
<condition property="append.dest.dir" value="-Ddest.dir=${dest.dir}" else="">
<isset property="dest.dir"/>
</condition>
<exec executable="ant" failonerror="true">
<arg line="-f ivy-build.xml" />
<arg line='-lib "${toString:ant.class.path}"' />
<arg value="${wrapped.task.name}" />
<arg value="${append.dest.dir}" />
</exec>
</target>

How to add all files in a fileset as an argument to the exec task?

I'm trying to provide all *.cpp files in a folder to the c++ compiler through ant. But I get no further than ant giving gpp a giant string containing all the files. I tried to prove it by using a small test application:
int main( int argc, char**args ){
for( --argc; argc != 0; --argc ) printf("arg[%d]: %s\n",argc,args[argc]);
}
With the ant script like this:
<target name="cmdline">
<fileset id="fileset" dir=".">
<include name="*"/>
</fileset>
<pathconvert refid="fileset" property="converted"/>
<exec executable="a.exe">
<arg value="${converted}"/>
</exec>
</target>
My a.exe's output is this:
[exec] arg[1]: .a.cpp.swp .build.xml.swp a.cpp a.exe build.xml
Now here's the question: how do I provide all files in the fileset individually as an argument to the executable?
This is what the apply task in ANT was designed to support.
For example:
<target name="cmdline">
<apply executable="a.exe" parallel="true">
<srcfile/>
<fileset dir="." includes="*.cpp"/>
</apply>
</target>
The parallel argument runs the program once using all the files as arguments.
Found it: the difference seems to lie in arg value vs. arg line.
<arg line="${converted}"/>
resulted in the expected output:
[exec] arg[5]: C:\cygwin\home\xtofl_2\antes\build.xml
[exec] arg[4]: C:\cygwin\home\xtofl_2\antes\a.exe
[exec] arg[3]: C:\cygwin\home\xtofl_2\antes\a.cpp
[exec] arg[2]: C:\cygwin\home\xtofl_2\antes\.build.xml.swp
[exec] arg[1]: C:\cygwin\home\xtofl_2\antes\.a.cpp.swp
Based on this article, here is the complete code illustrating the use of the pathconvert task:
<target name="atask">
<fileset dir="dir" id="myTxts">
<include name="*.txt" />
</fileset>
<pathconvert property="cmdTxts" refid="myTxts" pathsep=" " />
<apply executable="${cmd}" parallel="false" verbose="true">
<arg value="-in" />
<srcfile />
<arg line="${cmdTxts}" />
<fileset dir="${list.dir}" includes="*.list" />
</apply>
</target>
Above code assumes there are no spaces in the paths.
To support spaces in paths, change above pathconvert line to:
<pathconvert property="cmdTxts" refid="myTxts" pathsep="' '" />
and arg line to:
<arg line="'${cmdTxts}'"/>
Source: Converting an Ant fileset to multiple apply args.
Have you looked at the ant cpptasks? This would allow you to integrate C++ compilation into your Ant build in a more Ant-centric fashion. For example, specifying files to be compiled using a fileset.
Here is the example (compatible with Ant 1.6 or later)::
<project name="hello" default="compile" xmlns:cpptasks="antlib:net.sf.antcontrib.cpptasks">
<target name="compile">
<mkdir dir="target/main/obj"/>
<cpptasks:cc outtype="executable" subsystem="console" outfile="target/hello" objdir="target/main/obj">
<fileset dir="src/main/c" includes="*.c"/>
</cpptasks:cc>
</target>
</project>

How do I execute an ant task for each line in a given file?

I need to execute an ant task for each line from a given file. Any ideas appreciated.
I have a properties file that defines processes that need to be run. This is all on a single line and comma separated, not multiple lines as you have specified. This answer shows how to iterate over a file.
env.start=webserver:localhost, dataserver:localhost
then in my ant file that handles application execution I have the following
<target name="start-all" description="Start all processes specified in target-info.properties:env.start">
<foreach list="${env.start}" trim="yes" param="process.and.host" target="-start-process"/>
</target>
<target name="-start-process">
<property name="colon.separated.pattern" value="([^:]*):([^:]*)"/>
<propertyregex property="process" input="${process.and.host}" regexp="${colon.separated.pattern}" select="\1"/>
<propertyregex property="host" input="${process.and.host}" regexp="${colon.separated.pattern}" select="\2"/>
<condition property="start.target" value="start-${process}" else="-start-process-ssh">
<equals arg1="${host}" arg2="localhost" trim="yes" casesensitive="no"/>
</condition>
<antcall target="${start.target}"/>
</target>
${start.target} then is executed for the processes defined in the env.start property for example
<target name="start-webserver" description="Start the webserver on this machine">
<echo>** Starting webserver **</echo>
<run-script dir="${project.base.dir}/apache-tomcat" script="${project.base.dir}/apache-tomcat/bin/startup" spawn="yes">
<args>
<env key="CATALINA_HOME" value="${project.base.dir}/apache-tomcat"/>
<env key="CATALINA_PID" value="${project.base.dir}/apache-tomcat/logs/pid_catalina"/>
</args>
</run-script>
</target>
<target name="start-dataserver" depends="decipher_caldb_password,check-event-seed,run-prestart-sql" description="Start the dataserver on this machine">
<run-calypso process="dataserver" class="calypsox.apps.startup.StartNOGUI" failonerror="yes"
args="-class com.calypso.apps.startup.StartDataServer"/>
</target>
I can start all the processes defined in env.start by running
ant -f run.xml start-all

Resources