If I have an Ant task like this:
<target name="default">
<mkdir dir="${installer.config.installation.db.path}"/>
</target>
And the property referenced is NOT set, I end up with a directory (in this 'mkdir' example) being created with the literal name of (as a subdir of the 'basedir'):
${installer.config.installation.db.path}
Is there any way to enforce a failure if ANT is asked to resolve properties but fails?
There is no way to do this for all properties but you can check individual ones:
<fail unless="installer.config.installation.db.path" />
The above will abort the script when the property isn't defined. It will succeed when the property is empty, though!
the following works only with ant project-level properties. (groovy lib required)
<?xml version="1.0" encoding="UTF-8"?>
<project name="strict me" default="default" basedir=".">
<target name="init-strict">
<script language="groovy">
import org.apache.tools.ant.PropertyHelper;
def antProject = project;
if( "#MyPropertyHelper"!=PropertyHelper.getPropertyHelper(antProject).toString() ) {
def myPropertyHelper = new PropertyHelper(){
#Delegate PropertyHelper delegate = PropertyHelper.getPropertyHelper(antProject);
public Object getProperty(String name){
Object v = delegate.getProperty(name);
if(v==null)throw new org.apache.tools.ant.BuildException("The property `$name` not defined");
return v;
}
public String toString() {return "#MyPropertyHelper"}
}
antProject.addReference("ant.PropertyHelper", myPropertyHelper);
}
</script>
</target>
<target name="default" depends="init-strict">
<mkdir dir="${installer.config.installation.db.path}"/>
</target>
</project>
Related
I have the following code:
new AntBuilder().zip( destFile: "${file}.zip" ) {
fileset( dir: srcDir ) {
include( name:pattern )
}
}
In this example I'd like ant to create a zip with the same name as the original file, but with a .zip added to the end. Is there a way to do this without knowing the original file's name ahead of time in ant? I'd like to be able to do the same thing with other ant tasks as well.
To put it another way, I'd like the filename to become whatever "pattern" resolves to for each file.
Something like this?
<target name="zip-files">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>
<dirset id="dirsToZip" dir="src">
<include name="dir*"/>
</dirset>
<groovy>
project.references.dirsToZip.each {
ant.zip(destfile: "${it}.zip", basedir: it)
}
</groovy>
</target>
If find the groovy task's ability to iterate thru a fileset or dirset a very useful feature.
I need to retrieve some values from an HTML file. I need to use Ant so I can use these values in other parts of my script.
Can this even be achieved in Ant?
As stated in the other answers you can't do this in "pure" XML. You need to embed a programming language. My personal favourite is Groovy, it's integration with ANT is excellent.
Here's a sample which retrieves the logo URL, from the groovy homepage:
parse:
print:
[echo]
[echo] Logo URL: http://groovy.codehaus.org/images/groovy-logo-medium.png
[echo]
build.xml
Build uses the ivy plug-in to retrieve all 3rd party dependencies.
<project name="demo" default="print" xmlns:ivy="antlib:org.apache.ivy.ant">
<target name="resolve">
<ivy:resolve/>
<ivy:cachepath pathid="build.path" conf="build"/>
</target>
<target name="parse" depends="resolve">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>
<groovy>
import org.htmlcleaner.*
def address = 'http://groovy.codehaus.org/'
// Clean any messy HTML
def cleaner = new HtmlCleaner()
def node = cleaner.clean(address.toURL())
// Convert from HTML to XML
def props = cleaner.getProperties()
def serializer = new SimpleXmlSerializer(props)
def xml = serializer.getXmlAsString(node)
// Parse the XML into a document we can work with
def page = new XmlSlurper(false,false).parseText(xml)
// Retrieve the logo URL
properties["logo"] = page.body.div[0].div[1].div[0].div[0].div[0].img.#src
</groovy>
</target>
<target name="print" depends="parse">
<echo>
Logo URL: ${logo}
</echo>
</target>
</project>
The parsing logic is pure groovy programming. I love the way you can easily walk the page's DOM tree:
// Retrieve the logo URL
properties["logo"] = page.body.div[0].div[1].div[0].div[0].div[0].img.#src
ivy.xml
Ivy is similar to Maven. It manages your dependencies on 3rd party software. Here it's being used to pull down groovy and the HTMLCleaner library the groovy logic is using:
<ivy-module version="2.0">
<info organisation="org.myspotontheweb" module="demo"/>
<configurations defaultconfmapping="build->default">
<conf name="build" description="ANT tasks"/>
</configurations>
<dependencies>
<dependency org="org.codehaus.groovy" name="groovy-all" rev="1.8.2"/>
<dependency org="net.sourceforge.htmlcleaner" name="htmlcleaner" rev="2.2"/>
</dependencies>
</ivy-module>
How to install ivy
Ivy is a standard ANT plugin. Download it's jar and place it in one of the following directories:
$HOME/.ant/lib
$ANT_HOME/lib
I don't know why the ANT project doesn't ship with ivy.
Yes this is very possible.
Note that in order to use this solution you will need to set your JAVA_HOME variable to JRE 1.6 or later.
<project name="extractElement" default="test">
<!--Extract element from html file-->
<scriptdef name="findelement" language="javascript">
<attribute name="tag" />
<attribute name="file" />
<attribute name="property" />
<![CDATA[
var tag = attributes.get("tag");
var file = attributes.get("file");
var regex = "<" + tag + "[^>]*>(.*?)</" + tag + ">";
var patt = new RegExp(regex,"g");
project.setProperty(attributes.get("property"), patt.exec(file));
]]>
</scriptdef>
<!--Only available target...-->
<target name="test">
<!--Load html file into property-->
<loadfile srcFile="D:\Tools\CruiseControl\Build\artifacts\RECO\20110831100942\RECO_merged_report.html" property="html.file"/>
<!--Find element with specific tag and save it to property element-->
<findelement tag="title" file="${html.file}" property="element"/>
<echo message="File : ${html.file}"/>
<echo message="Title : ${element}"/>
</target>
</project>
Output : [echo] Title : <title>Test Report</title>,Test Report
As I don't know what exactly variables you were looking for this particular solution will find all elements that you specify in the tag attribute. Of course you could modify the regex to suit your own specific needs.
Also this is pure build.xml ant with no external dependencies whatsoever.
Sure, but you have to write your own task for it. Visit http://ant.apache.org/manual/develop.html#writingowntask for more information about writing own tasks for Ant. In your Ant task you may parse your HTML file as needed.
I claim, that it is not directly possible with "pure" XML (build.xml) to achieve what you want.
Take a look at the (http://ant.apache.org/manual/Tasks/xmlproperty.html) task and see if it'll work for you. It's pretty straight forward:
<xmlProperty file="${html.file}"
prefix="html."/>
After all, HTML is just a subset of XML. I've used it before to do this very task. No need to write your own task or script.
I want to use manifestclasspath Ant task. I have a very large build.xml file with a couple of imported other build files and when I run it I get this:
build.xml:1289: The following error occurred while executing this line:
build.xml:165: Property 'some.property' already set!
I am sure that this property is defined only in manifestclasspath task. Here is my code:
<manifestclasspath property="some.property" jarfile="some.jar">
<classpath refid="some.classpath"/>
</manifestclasspath>
This code is located inside of <project>.
What am I doing wrong? Is there a way to add something like condition to set property only if it is not already set? I don't want to use custom Ant tasks such as Ant Contrib's if if there is other way around.
Antcall opens a new project scope, but by default, all of the properties of the current project will be available in the new project. Also if you used something like =
<antcall target="whatever">
<param name="some.property" value="somevalue"/>
</antcall>
in the calling project then ${some.property} is also already set and won't be overwritten, as properties once set are immutable in ant by design.
Alternatively, you may set the inheritAll attribute to false and only "user" properties (those passed on the command-line with -Dproperty=value) will be passed to the new project.
So, when ${some.property} ain't no user property, then use inheritAll="false" and you're done.
btw. it's better to use a dependency between targets via depends="..." attribute than to use antcall, because it opens a new project scope and properties set in the new project won't get back to the calling target because it lives in another project scope..
Following a snippet, note the difference, first without inheritAll attribute
<project default="foo">
<target name="foo">
<property name="name" value="value1" />
<antcall target="bar"/>
</target>
<target name="bar">
<property name="name" value="value2" />
<echo>$${name} = ${name}</echo>
</target>
</project>
output :
[echo] ${name} = value1
second with inheritAll=false
<project default="foo">
<target name="foo">
<property name="name" value="value1" />
<antcall target="bar" inheritAll="false" />
</target>
<target name="bar">
<property name="name" value="value2" />
<echo>$${name} = ${name}</echo>
</target>
</project>
output :
[echo] ${name} = value2
some rules of thumb for antcall, it's rarely used for good reasons :
1. it opens a new project scope (starting a new 'ant -buildfile yourfile.xml yourtarget') so it uses more memory, slowing down your build
2. depending targets of the called target will be called also !
3. properties don't get passed back to the calling target
In some cases it might be ok when calling the same 'standalone' target (a target that has no target it depends on) with different params for reuse. Normally macrodef or scriptdef are used for that purpose. So, think twice before using antcall which also puts superfluous complexity to your scripts, because it works against the normal flow.
Answer to your question in the comment, using a dependency graph instead of antcall
you have some target that holds all conditions and sets the appropriate properties which may be evaluated by targets via if and unless attributes to control the further flow
<project default="main">
<target name="some.target">
<echo>starting..</echo>
</target>
<!-- checking requirements.. -->
<target name="this.target">
<condition property="windowsbuild">
<os family="windows"/>
</condition>
<condition property="windowsbuild">
<os family="unix"/>
</condition>
<!-- ... -->
</target>
<!-- alternatively
<target name="yet.another.target" depends="this.target" if="unixbuild">
-->
<target name="another.target" depends="this.target" unless="windowsbuild">
<!-- your unixspecific stuff goes here .. -->
</target>
<!-- alternatively
<target name="yet.another.target" depends="this.target" if="windowsbuild">
-->
<target name="yet.another.target" depends="this.target" unless="unixbuild">
<!-- your windowspecific stuff goes here .. -->
</target>
I'm rather new to Ant but I have experienced it's quite good pattern to create generic ant targets which are to be called with antcall task with varying parameters.
My example is compile target, which compiles multiple systems using complex build command which is a bit different for each system. By using pattern described above it's possible not to create copy paste code for that compile command.
My problem here is, that I'm not aware of any way to pass return value (for example the return value of compiler) back to target which called the antcall task. So is my approach pathological and it's simply not possible to return value from antcall task or do you know any workaround?
Thanks,
Use antcallback from the ant-contrib jar instead of antcall
<target name="testCallback">
<antcallback target="capitalize2" return="myKey">
</antcallback>
<echo>a = ${myKey}</echo>
</target>
<target name="capitalize2">
<property name="myKey" value="it works"/>
</target>
Output:
testCallback:
capitalize2:
[echo] a = it works
BUILD SUCCESSFUL
One approach is to write out a property to a temp file using "echo file= ...." or PropertyFile task. Then read the property back in where required. Kludge but works.
Ant tasks are all about stuff goes in, side effect happens. So trying to program in terms of functions (stuff goes in, stuff comes out) is going to be messy.
That said what you can do is generate a property name per invocation and store the result value in that property. You would need to pass in a indentifier so you do not end up trying to create copies of the same property. Something like this:
<target name="default">
<property name="key" value="world"/>
<antcall target="doSomethingElse">
<param name="param1" value="${key}"/>
</antcall>
<echo>${result-${key}}</echo>
</target>
<target name="doSomethingElse">
<property name="hello-${param1}" value="it works?"/>
</target>
But I believe the more typical approach -instead of antcalls- is to use macros. http://ant.apache.org/manual/Tasks/macrodef.html
Antcall can be used from the ant-contrib jar task.
You can get a similar behaviour with the keyword "depends".
<?xml version="1.0" encoding="UTF-8"?>
<project name="test" default="main">
<target name="main">
<antcall target="build-system-with-depends" />
<!-- wait for different results -->
<waitfor checkevery="1000" checkeveryunit="millisecond" maxwaitunit="millisecond" maxwait="2000">
<available file="dummy.not.present.file" classname="" property=""></available>
</waitfor>
<antcall target="build-system-with-depends" />
</target>
<target name="build-system-with-depends" depends="do-compiler-stuff">
<echo>$${compiler.result}=${compiler.result}</echo>
</target>
<target name="do-compiler-stuff">
<!-- simulate different return states -->
<tstamp>
<format pattern="yyyyMMddHHmmss" property="compiler.result" />
</tstamp>
</target>
</project>
I have a set of nested Ant build files, and I need to control which properties are inherited by each "sub" task. I'm trying to define these as propertysets (to keep the code manageable) but these are not inherited by subtasks, unlike properties.
The example below demonstrates the problem, foo.* get copied into the middle project but not to the bottom project. If I define each property to be inherited explicitly, like bar.*, they get inherited by the bottom project too.
Is there any way to get a group of properties to inherit all the way down, in the same way individual properties do? Without rewriting the sub-processes, is there something else I could try?
[top.xml]
<?xml version="1.0"?>
<project name="test-top">
<property name="foo.1" value="1"/>
<property name="foo.2" value="2"/>
<property name="bar.1" value="1"/>
<property name="bar.2" value="2"/>
<ant antfile="middle.xml" inheritall="false">
<propertyset>
<propertyref prefix="foo."/>
</propertyset>
<property name="bar.1" value="${bar.1}"/>
<property name="bar.2" value="${bar.2}"/>
</ant>
</project>
[middle.xml]
<?xml version="1.0"?>
<project name="test-middle">
<echo>foo ${foo.1} ${foo.2}</echo>
<echo>bar ${bar.1} ${bar.2}</echo>
<ant antfile="bottom.xml" inheritall="false"/>
</project>
[bottom.xml]
<?xml version="1.0"?>
<project name="test-bottom">
<echo>foo ${foo.1} ${foo.2}</echo>
<echo>bar ${bar.1} ${bar.2}</echo>
</project>
[OUTPUT OF ant -f top.xml]
[echo] foo 1 2
[echo] bar 1 2
[echo] foo ${foo.1} ${foo.2}
[echo] bar 1 2
I think Alexander's solution is close. How about this though, doesn't need any change in middle.xml or bottom.xml.
The idea is to use the echoproperties task to 'unroll' the propertyset to individual properties, then to use that in the ant task call.
Before calling middle.xml, write the property set out using something like this:
<echoproperties destfile="myproperties.txt">
<propertyset>
<propertyref prefix="foo."/>
<propertyref prefix="bar."/>
</propertyset>
</echoproperties>
Then make the call to middle.xml:
<ant antfile="middle.xml" inheritall="false">
<property file="myproperties.txt" />
</ant>
Properties supplied to the ant task inherit all the way down as you say, so you only need to change top.xml:
These properties become equivalent to
properties you define on the command
line. These are special properties and
they will always get passed down, even
through additional <ant> tasks with
inheritall set to false (see above).
In top.xml you can create a file with inheritable properties using <propertyfile> task.
Then you can load this file with <property file="..."/>in each of your submodules.