I've got a situation where we're generating an Ant <path> which may contain some directories which don't actually exist. Unfortunately this is being fed into bnd, which blows up if anything in the path is missing.
So what I want is a way to filter a <path> to keep only those path elements which actually exist.
Is there a simple way to say this in Ant, or do I have to write a task?
I believe I have found an answer:
<path id="bnd.cp.existing">
<restrict>
<path refid="bnd.cp"/>
<exists/>
</restrict>
</path>
<!-- To see when it happens, add the following: -->
<echo message="bnd classpath is: ${toString:bnd.cp.existing}"/>
<iff>
<not>
<equals arg1="${toString:bnd.cp.existing}"
arg2="${toString:bnd.cp}"/>
</not>
<then>
<echo message=" trimmed from: ${toString:bnd.cp}"/>
</then>
</iff>
The restrict operation can take a path-like structure as input and return a version of it with the requested filtering applied -- in this case keep only the path elements which actually exist. This is then re-bound to a new ID for use by the <bnd> operation.
Related
I am banging my head on the walls with ant...
My target is the following:
<target name="js.minify">
<apply executable="java">
<arg line="-jar"></arg>
<arg path="path_to_file/yuicompressor-2.4.7.jar"></arg>
<arg line="-v"></arg>
<srcfile></srcfile>
<arg line="-o"></arg>
<targetfile></targetfile>
<globmapper from="*.js" to="*.min.js" casesensitive="no"/>
<fileset id="jsFiles" dir="${artifactsdir}/js">
</fileset>
</apply>
</target>
Here's the funny thing, with the mapper in the code nothing gets processed. I can even change the name of the executable to some non existing application and it won't complain, ie it skips the apply. If I remove the mapper and the target file, at least I get some error message. If I try another process with just the source file, it runs. I really narrowed it down to mapper which seems to select the files only if they have changed (?!), ie if I edit them and save them, it works... any idea how to force mapper to take any files, even non modified (whatever that means) files?
It sounds like you want to ignore the timestamp checking you get when you use <targetfile>.
You can do that using the force="true" parameter of the <apply> task. (It's at the bottom of the list of parameters, note that this option was new at Ant version 1.6.3.)
<apply executable="java" force="true">
...
I am trying to compare the value of a properties variable with a string as following
<if>
<equals "${mat.projectName}"="seal">
<then>
When done so, I'm getting following message.
Element type "equals" must be followed by either attribute specifications,">" or
"/>"
I'm using eclipse framework to do this.
Read the manual first:
http://ant.apache.org/manual/Tasks/conditions.html
clearly, from the manual we know for equals:
arg1 First value to test
arg2 Second value to test
So it should be
<if>
<equals arg1="${mat.projectName}" arg2="seal" />
<then>
...
I recommend you to read guides about XML first, and then, Ant's manual.
Update:
<if> task is not provided by Ant; it is provided by Ant-Contrib. So you need <taskdef>.
For example, I have ant-contrib.jar put in my project's lib directory (${basedir}/lib), so I can write the following:
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="lib/ant-contrib.jar"/>
</classpath>
</taskdef>
For more, you can check taskdef's manual page, as well as Ant-contrib's webpage:
http://ant.apache.org/manual/Tasks/taskdef.html
http://ant-contrib.sourceforge.net/
Exactly what you're error message says...
Element type "equals" must be followed by either attribute specifications,">" or "/>"
You want this:
<if>
<equals arg1="${mat.projectName}" arg2="seal"/>
<then>
<yadda, yadda, yadda/>
</then>
</if>
This is XML, so you need parameters with values. Take a look at the equals condition on this page. It takes two parameters.
Notice the format of the <if>. The condition ends with a />. The <then> is a sub-entity of the <if>, and the if clause is a sub-entity of the <then> clause. Notice that you basically indent twice.
If you're doing a not equals condition, it would look like this:
<if>
<not>
<equals arg1="${mat.projectName}" arg2="seal"/>
</not>
<then>
<yadda, yadda, yadda/>
</then>
</if>
I'm using ant condition task to check a file existence and directory existence and below is my code
<project name="makeitmutable" basedir="." default="main">
<target name="main">
<condition property="folderexists?" value="Yeah" else="Nope">
<and>
<available file="folderexistance" type="dir"/>
<available file="a.zip" type="file"/>
</and>
</condition>
<echo>before deleting "folderexistance" folder property folderexists?=${folderexists?}</echo>
<delete dir="folderexistance"/>
<!--after delete-->
<condition property="folderexists?" value="Yeah" else="Nope">
<and>
<available file="folderexistance" type="dir"/>
<available file="a.zip" type="file"/>
</and>
</condition>
<!--how to make below line to print Nope ?-->
<echo>After deleting "folderexistance" folder property folderexists?=${folderexists?}</echo>
</target>
</project>
My output value of the property folderexists? remains same even after deleting the directory,i.e.., Nope two times
I knew that ant properties are immutable once set cannot be changed,and also an alternative to this solution is we can use
<antcall>
task and call the main target.
Is there a way to make the property mutable within that target as in the above scenario,I'm looking for other possibilities to resolve this, what's the better programming practice for this type of problem.
As you said, properties are immutable. The only other option is to use the var task from ant-contrib.
Quote from the docs: In general, use of this task is DISCOURAGED, and the standard Ant Property should be used if possible. Having said that, in real life I use this a lot.
which says a lot, too ;-)
It sounds a little far fetched to me, but is there an ANT task for watching a directory for changes and then running a particular ANT class when the directory changes?
If files can only be added to or changed in the watched directory, then you can use this simple OutOfDate task from antcontrib.
<property name="watched-dir.flagfile"
location="MUST be not in watched dir"/>
<outofdate>
<sourcefiles>
<fileset dir="watched-dir"/>
</sourcefiles>
<targetfiles>
<pathelement location="${watched-dir.flagfile}"/>
</targetfiles>
<sequential>
<!--Tasks when something changes go here-->
<touch file="${watched-dir.flagfile}"/>
</sequential>
</outofdate>
If files can disappear from the watched-dir, then you have more complicated problem, that you can solve by creating shadow directory structure of the watched dir and checking if its consistent with the watched-dir. This task is more complex, but I'll give you a script to create a shadow directory, as it is not straight forward:
<property name="TALK" value="true"/>
<property name="shadow-dir"
location="MUST be not in watched dir"/>
<touch
mkdirs="true"
verbose="${TALK}"
>
<fileset dir="watched-dir">
<patterns/>
<type type="file"/>
</fileset>
<!-- That's the tricky globmapper to make touch task work -->
<globmapper from="*" to="${shadow-dir}/*"/>
</touch>
<!--
Due to how touch task with mapped fileset is implemented, it
truncates file access times down to a milliseconds, so if you
would have used outofdate task on shadow dir it would always
show that something is out of date.
Because of that, touching all files in ${shadow-dir} again fixes
that chicken and egg problem.
-->
<touch verbose="${TALK}">
<fileset dir="${shadow-dir}"/>
</touch>
With shadow directory created, I'll leave the task of checking directory consistency as an exercise for the reader.
Yes there is an Ant Task that will do this:
https://github.com/chubbard/WatchTask
It requires 1.7+. It can watch any number of filesets, and invoke any target depending on which fileset it came from.
You might be able to use the Waitfor task to achieve what you want. It blocks until one or more conditions (such as the presence of a particular file) become true.
You can combine the apply task with a fileset selector
<apply executable="somecommand" parallel="false">
<srcfile/>
<fileset dir="${watch.dir}">
<modified/>
</fileset>
</apply>
The fileset will check the files against a stored MD5 checksum for changes. You'll need to put ANT into a loop in order to repeatedly run this check. this is easy to do in Unix:
while true
> do
> ant
> sleep 300
> done
I have the following clean function in my build script and I'd like to know how I can improve it.
<target name="clean" description="Clean output directories.">
<!-- Must not fail on error because it fails if directories don't exist.
Is there really no better way to do this? -->
<delete includeEmptyDirs="true" failonerror="false">
<fileset dir="${main.build.directory}" />
<fileset dir="dist" />
<fileset dir="${documentation.build.directory}" />
<fileset dir="/build-testing" />
</delete>
</target>
Specifically regarding my comment, I'm unhappy with the fact that I can't run this on a fresh box because the directory structure hasn't been set up yet by the other targets. We run the build in such a way that it entirely recreates the structures necessary for testing and deployment every time to avoid stale class files and such. With the way that delete currently is set up, a failure to delete a file does not fail the build and I'd like it to. I don't want it to fail the build if the file doesn't exist though. If it doesn't exist then what I'm asking it to do has already happened.
Thoughts?
via Michael's answer, which was 90% of what I needed but not quite all the way there.
The actual solution that I ended up with because of your answers is the following:
<target name="clean" description="Clean output directories.">
<!-- Must not fail on error because it fails if directories don't exist.
Is there really no better way to do this? -->
<delete includeEmptyDirs="true" failonerror="false">
<fileset dir="${main.build.directory}" />
...
</delete>
<available
file="${main.build.directory}"
type="dir"
property="delete-main-failure" /> ...
<condition property="delete-failure">
<and>
<isset property="delete-main-failure" /> ...
</and>
</condition>
<fail
if="delete-failure"
message="Unable to delete previous build's directories." />
</target>
This meets my criteria that the code attempts to delete it and then fails if it still exists. It's super ugly though. The default behavior of the delete task strikes me as very odd. I suppose the rationale is that if you try to delete something and it isn't there then something must be wrong but it seems to me that the normal case would be that if it's not there you don't care because it's gone already while the odd case is that you needed it to be there but now it shouldn't be anymore at this specific stage in the build.
I came here to ask the same question... it doesn't look like there is an elegant way to solve this. When I want to keep the code clean, I do it this way:
<mkdir dir="${main.build.directory}" />
<delete dir="${main.build.directory}" failonerror="true" />
I didn't think the delete task had an "if" property. Will have to check that out.