How can I concat files with Ant if source files is changed? - ant

How can I concat files with Ant if source files is changed?
I create such code but it is very complex to do such simple thing - want to do in more simple way - can I do it?
<target name="check.src/web_site/seo/frontend/base/crud/yaml/keyword/list/static/list.js">
<uptodate property="dirty.src/web_site/seo/frontend/base/crud/yaml/keyword/list/static/list.js"
targetfile="src/web_site/seo/frontend/base/crud/yaml/keyword/list/static/list.js">
<srcfiles file="src/web_site/seo/frontend/base/crud/yaml/base/list/static/list.js"></srcfiles>
<srcfiles file="src/web_site/seo/frontend/base/crud/yaml/keyword/list/js/list.js"></srcfiles>
</uptodate>
<echo message="result: ${dirty.src/web_site/seo/frontend/base/crud/yaml/keyword/list/static/list.js}"/>
</target>
<target name="src/web_site/seo/frontend/base/crud/yaml/keyword/list/static/list.js"
depends="check.src/web_site/seo/frontend/base/crud/yaml/keyword/list/static/list.js"
unless="dirty.src/web_site/seo/frontend/base/crud/yaml/keyword/list/static/list.js">
<echo message="concat"></echo>
<concat destfile="src/web_site/seo/frontend/base/crud/yaml/keyword/list/static/list.js"
fixlastline="true" >
<fileset file="src/web_site/seo/frontend/base/crud/yaml/base/list/static/list.js"></fileset>
<fileset file="src/web_site/seo/frontend/base/crud/yaml/keyword/list/js/list.js"></fileset>
</concat>
</target>

Since ant 1.8.2, you can use overwrite property of the concat task for that purpose.
Before version 1.8.2, you may use the force property instead.

Related

Ant conditional if within a macrodef

Within ant, I have a macrodef.
Assuming I have to use this macrodef, and there is a item inside said macrodef that I want to run if the property special.property exists and is true, what do I do?
I currently have
<macrodef name="someName">
<sequential>
<someMacroDefThatSetsTheProerty />
<some:thingHereThatDependsOn if="special.property" />
<sequential>
</macrodef>
Which doesn't work - the some:thingHereThatDependsOn doesnt have an "if" attribute, and I cannot add one to it.
antcontrib is not available.
With a target I can give the target an "if", what can I do with a macrodef?
In Ant 1.9.1 and higher, there is now a new implementation of if and unless attributes. This might be what you're thinking of.
First, you need to put them into your namespace. Add them to your <project> header:
<project name="myproject" basedir="." default="package"
xmlns:if="ant:if"
xmlns:unless="ant:unless">
Now, you can add them to almost any Ant task or sub entity:
<!-- Copy over files from special directory, but only if it exists -->
<available property="special.dir.available"
file="${special.dir} type="dir"/>
<copy todir="${target.dir}>
<fileset dir="${special.dir}" if:true="special.dir.available"/>
<fileset dir="${other.dir}"/>
</copy>
<!-- FTP files over to host, but only if it's on line-->
<condition property="ftp.available">
<isreachable host="${ftp.host}"/>
</condition>
<ftp server="${ftp.host}"
userid="${userid}"
passowrd="${password}"
if:true="ftp.available">
<fileset dir=".../>
</ftp>
This is only possible if the ANT "thingHereThatDependsOn" task supports an "if" attribute.
As stated above, conditional execution in ANT, normally, only applies to targets.
<target name="doSomething" if="allowed.to.do.something">
..
..
</target>
<target name="doSomethingElse" unless="allowed.to.do.something">
..
..
</target>
<target name="go" depends="doSomething,doSomethingElse"/>

Loop through directory structure in ant

We want to loop through directory structure in ant without using foreach .
Is there any elegant way to do the same ?
The apply task can iterate over a set of directories or files
<target name="run-apply">
<apply executable="echo">
<dirset dir="src"/>
</apply>
</target>
I personally like the groovy ANT task
<target name="run-groovy">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<dirset id="dirs" dir="src"/>
<groovy>
project.references.dirs.each {
ant.echo it
}
</groovy>
</target>
The installation of the task jar is easily automated:
<target name="install-groovy">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/groovy-all.jar" src="http://search.maven.org/remotecontent?filepath=org/codehaus/groovy/groovy-all/2.1.1/groovy-all-2.1.1.jar"/>
</target>
Finally if you're iterating thru other build files, the subant task is very useful:
<target name="run-subant">
<subant>
<fileset dir="src" includes="**/build.xml"/>
</subant>
</target>
Short answer: Not really. There are ways around this, but I prefer the ant-contrib <for/> task for clarity and simplicity. With the <local/> task, you can now localize values of variables. Before, you sometimes had to use ant-contrib's <var/> task to reset the values, so you could loop through them over and over.
<for param="directory">
<fileset dir="${some.dir}"/>
<sequential>
<local name="foo"/>
<local name="bar"/> <!-- Properties that may change with each iteration -->
<!-- Here be dragons -->
</sequential>
</for>
It's clean, simple, and easy to understand. The big issue many people have with Ant Contrib is that not everyone may have it installed in their $ANT_HOME/lib directory. Far enough. So, if you use ant-contrib, put it as part of your project.
I'll put the ant-contrib jar in ${basedir}/antlib/antcontrib and then put this in my program:
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<fileset dir="${basedir}/antlib/antcontrib"/>
</classpath>
</taskdef>
Now, when someone checks out my project, they have ant-contrib already installed (since it's inside my project) and accessible (since I point my <taskdef> task at the location of ant-contrib.jar in my project).

Running an ant task only when a file has changed

In Ant, I am trying to achieve a simple task: If couple of files are modified a compiler should run. I have seen many solutions using OutOfDate, UpToDate and Modified. I dont want to use OutOfDate and UpToDate because I wont be able to use the task if the files have been modified on the same day. I can use modified but there is no way to call another task - my compiler task, from the modifier task. Is there any other solution apart from these?
Using <uptodate> with a following <antcall> to a conditional <target> will give you what you're looking for:
<project name="ant-uptodate" default="run-tests">
<tstamp>
<format property="ten.seconds.ago" offset="-10" unit="second"
pattern="MM/dd/yyyy hh:mm aa"/>
</tstamp>
<target name="uptodate-test">
<uptodate property="build.notRequired" targetfile="target-file.txt">
<srcfiles dir= "." includes="source-file.txt"/>
</uptodate>
<antcall target="do-compiler-conditionally"/>
</target>
<target name="do-compiler-conditionally" unless="build.notRequired">
<echo>Call compiler here.</echo>
</target>
<target name="source-older-than-target-test">
<touch file="source-file.txt" datetime="${ten.seconds.ago}"/>
<touch file="target-file.txt" datetime="now"/>
<antcall target="uptodate-test"/>
</target>
<target name="source-newer-than-target-test">
<touch file="target-file.txt" datetime="${ten.seconds.ago}"/>
<touch file="source-file.txt" datetime="now"/>
<antcall target="uptodate-test"/>
</target>
<target name="run-tests"
depends="source-older-than-target-test,source-newer-than-target-test"/>
</project>

Using Ant to delete a file based on existence of another file

I need to write an ant task to selectively delete files.
In a directory, I have the following jars:
acme.jar
acme-201105251330.jar
I want to delete acme.jar because acme-*.jar exists.
Here's what I've tried:
<target name="-check-use-file">
<available property="file.exists">
<filepath> <fileset dir=".">
<include name="./test-*.jar"/> </fileset>
</filepath>
</available>
</target>
<target name="use-file" depends="-check-use-file" if="file.exists">
<!-- do something requiring that file... -->
</target>
Thanks
Have a look at If/Unless Attributes, examples given there seem to be exactly what you are looking for.

How do I pass an argument to an Ant task?

I'm not very good with Ant, but we're using it as a build tool. Right now, we can run "ant test" and it'll run through all the unit tests.
However, I'd love to be able to do something like ant test some_module and have it accept some_module as a parameter, and only test that.
I haven't been able to find how to pass command line args to Ant - any ideas?
One solution might be as follows. (I have a project that does this.)
Have a separate target similar to test with a fileset that restricts the test to one class only. Then pass the name of that class using -D at the ant command line:
ant -Dtest.module=MyClassUnderTest single_test
In the build.xml (highly reduced):
<target name="single_test" depends="compile" description="Run one unit test">
<junit>
<batchtest>
<fileset dir="${test.dir}" includes="**/${test.module}.class" />
</batchtest>
</junit>
</target>
You can also define a property with an optional default value that can be replaced via command line, e.g.
<target name="test">
<property name="moduleName" value="default-module" />
<echo message="Testing Module: ${moduleName}"/>
....
</target>
and run it as:
ant test -DmoduleName=ModuleX
What about using some conditional in your test target and the specifying -Dcondition=true?
<target name="test" depends="_test, _test_if_true>
...
</target>
<target name="_test_if_true" if="condition">
...
</target>
<target name="_test" unless="condition">
...
</target>
Adapted a bit from the ant faq.
You can define a property on commandline when invoking ant:
ant -Dtest.module=mymodulename
Then you can use it as any other ant property:
...
<fileset dir="${test.dir}" includes="**/${test.module}.class" />
...
Have a look at Ant's manual.
I tried the solutions posted here for the very same original question. Yes just use ant -D<arg_name>. THe -D is a "keyword" I guess. I'm no ant expert and have not read the manuals in detail. Then inside the ant XML files can be accessed like: ${arg_name}
For instance you can have an argument name like: arg.myarg, so in XML ${arg.myarg}.
Ant really doesn't have parameters_ for the build file. I can think of a few ways to do this:
Use a special target to specify the tests. You can use the <for/> task from AntContrib to allow you to specify multiple tests. You'll need to download the Ant-Contrib jar file. I recommend placing it inside your project under the `${basedir}/antlib/antcontrib" directory. That way, when others checkout your project, they get the needed Ant-Contrib jar file.
<property name="antlib.dir" value="${basedir}/antlib"/>
<property name="antcontrib.dir" value="${antlib}/antcontrib"/>
<!-- Set up the ant contrib tasks for your use -->
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<fileset dir="${antcontrib.dir}"/>
</classpath>
</taskdef>
<target name="select-test"
description="Select the tests to run"
depends="test-compile"
if="junit-tests">
<for parameter="module"
list="${junit-tests}"
delimiter=" ">
<sequential>
<junit
fork="true"
...>
<batchtest todir="$target/unit-tests">
<fileset dir="${test.destdir}">
<include name="**/#{module}.class"/>
</fileset>
</junit>
</sequential>
</for>
</target>
You cab now run multiple tests like this:
$ ant -D"test-one test-two test-three" select-test
You could try this to access one target at a time. Add these lines to your build.xml file :
<project name="whatever" default="default">
<input message="Please select module:" addproperty="mod" />
<target name="default" depends="${mod}/>
...
</project>
This allows you to enter the module you want to execute and execute that itself instead of running the whole build.xml
You might need to make a few more changes to your build.xml for this to work perfectly.
For the arguments , there is Facility called property. You need to set the property. As in ANT plain arguments is taken as target name.
Lest say you have two modules in your project ModuleX and ModuleY where ModuleX has 2 testcases to run and ModuleY with 10 testcases.
You could do something like this :
ant runTestsOnModule -Dtestmodule="ModuleX"
OR to test all modules by calling
ant tests
<target name="runTestsOnModule">
<antCall target="testcase${testmodule}"/>
</target>'
<! -- run single module -->
<target name="runTestsOnModule">
<antCall target="testcase${testmodule}"/>
</target>
<!--run all tests-->
<target name="tests">
<antcall target="testcaseModuleX">
<antcall target="testCaseModuleY">
</target>
<target name="testcaseModuleX">
..run junit task to call 2 testcase
</target>
<target name="testcaseModuleY">
....run junit task to call 10 testcase
</target>

Resources