Passing variables to arg in Ant Script - ant

I've the following Ant command. I need to pass a variable {merged.folder} to the arg line. This value comes from a property file. But it is not resolving that variable. Is there any way to do this. Can you please help me?
<java fork="true" dir="${shrinksafe.util.path}/buildscripts" classname="org.mozilla.javascript.tools.shell.Main">
<arg line="releaseDir=${merged.folder}" />
<classpath>
<pathelement location="${shrinksafe.util.path}/shrinksafe/js.jar" />
<pathelement location="${shrinksafe.util.path}/shrinksafe/shrinksafe.jar" />
<pathelement path="${java.class.path}" />
</classpath>
</java>

I've checked this ant script based on your post:
<?xml version="1.0" encoding="UTF-8"?>
<project default="test_arg_path" basedir=".">
<property file="props.properties"/>
<target name="test_arg_path">
<java dir=".\build\classes" classname="Test">
<!-- <arg value="${argValue}"/>--> <!-- First variant -->
<arg line="releaseDir=${argValue} arg2Value" /> <!-- Second variant -->
</java>
</target>
</project>
Property file props.properties:
argValue=argVal
Test class source:
public class Test {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("args is empty");
}
System.out.println(Test.class + ", arg0: " + args[0]);
if (args.length > 1) {
System.out.println(Test.class + ", arg1: " + args[1]);
}
}
}
The output for first variant (using arg value):
class Test, arg0: argVal
The output for second variant (using arg line):
class Test, arg0: releaseDir=argVal
class Test, arg1: arg2Value
As you can see, the everything is OK with your script and it is correct. The problem, I think, in value setting of your variable merged.folder

Related

How can I generate Ant targets?

I want to be able to generate a number of Ant targets something like this:
<property name="grunt_tasks" value="jsp,css,js,img" />
<foreach list="${grunt_tasks}" param="task">
<target name="${task}">
<exec executable="grunt" failonerror="true">
<arg line="${task}" />
</exec>
</target>
</foreach>
allowing me to run ant jsp or ant js.
However, this code fails because a target tag cannot be placed in a foreach tag.
How can I accomplish this?
There's a number of ways you might add targets on the fly. Here's one suggestion:
<property name="mybuild" value="mybuild.xml" />
<property name="grunt_tasks" value="jsp,css,js,img" />
<echo message="<project>" file="${mybuild}" />
<for list="${grunt_tasks}" param="task">
<sequential>
<echo file="${mybuild}" append="yes"><![CDATA[
<target name="#{task}">
<exec executable="grunt" failonerror="true">
<arg line="#{task}" />
</exec>
</target>
]]></echo>
</sequential>
</for>
<echo message="</project>" file="${mybuild}" append="yes"/>
<import file="${mybuild}" />
Explanation:
Use the antcontrib <for> task in preference to <foreach>, else you have to have a separate target for the body of the loop.
Create a second buildfile, here called mybuild.xml, to contain your targets.
The buildfile content has to be within a <project> element.
Import the buildfile.
You can then invoke the on-the-fly targets in the way you wish.
You might alternatively use a <script> task to create the targets if you prefer, which would remove the need for the separate buildfile and import, something like this:
<for list="${grunt_tasks}" param="task">
<sequential>
<script language="javascript"><![CDATA[
importClass(org.apache.tools.ant.Target);
var exec = project.createTask( "exec" );
exec.setExecutable( "grunt" );
exec.setFailonerror( true );
var arg = exec.createArg( );
arg.setValue( "#{task}" );
var target = new Target();
target.addTask( exec );
target.setName( "#{task}" );
project.addOrReplaceTarget( target );
]]></script>
</sequential>
</for>

Ant script + parsing csv file

Hi I am having a csv file with 2 lines :
mf1,eg1,eg2,br1,br2
mf2,eg2,eg3,br2,br3
I want to store each comma separated value in separate variables using ant.
I am able to parse lines, but not individual values since list is not supporting nesting.
Below is my script :
<?xml version="1.0" encoding="UTF-8"?>
<project name="ForTest" default="getLine" basedir="."
xmlns:ac="antlib:net.sf.antcontrib">
<taskdef uri="antlib:net.sf.antcontrib" resource="net/sf/antcontrib/antlib.xml"
classpath="C:\Manju\apache-ant-1.8.4\ant-contrib-1.0b3-bin\ant-contrib\ant-contrib-1.0b3.jar" />
<loadfile property="message" srcFile="build_params.csv" />
<target name="getLine">
<ac:for list="${message}" delimiter="${line.separator}" param="val">
<sequential>
<echo>#{val}</echo>
<property name="var1" value=#{val}/>
</sequential>
</ac:for>
</target>
<target name="parseLine" depends="getLine">
<for list=#{val} delimiter="," param="letter">
<sequential>
<echo>#{letter}</echo>
</sequential>
</for>
</target>
</project>
Target parseline is giving error saying for list is expecting open quotes. Help is appreciated.
Have you considered embedding a scripting language like groovy instead? Far simpler compared to fighting ant-contrib.
<project name="demo" default="run">
<target name="run">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<groovy>
new File("build_params.csv").splitEachLine(",") { fields ->
println "===================="
println "field1: ${fields[0]}"
println "field2: ${fields[1]}"
println "field3: ${fields[2]}"
println "field4: ${fields[3]}"
println "field5: ${fields[4]}"
println "===================="
}
</groovy>
</target>
</project>
You can add a special bootstrap target to install the groovy jar automatically:
<target name="bootstrap">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/groovy-all.jar" src="http://search.maven.org/remotecontent?filepath=org/code
haus/groovy/groovy-all/2.2.1/groovy-all-2.2.1.jar"/>
</target>
For one thing, your parseLine target should start like this:
<for list="#{val}" delimiter="," param="letter">
Note the quotes around #{val}.

ant and command line arguments and absolute path

All
I am passing a -D build.dir = ~/myhome/build to my ant script and when I echo build.dir it is coming out relative to where the build.xml is such as ./~/myhome/build.
I am using command line argument since I have to override a property defined in a properties file.
Thoughts on this?
Try this code:
<?xml version="1.0" encoding="UTF-8" ?>
<project default="all" basedir=".">
<taskdef resource="net/sf/antcontrib/antcontrib.properties" />
<target name="all">
<echo message="${user.home}" />
<propertyregex property="build.dir"
input="${build.dir}"
regexp="~"
replace="${user.home}"
override="true" />
<echo message="${build.dir}" />
</target>
</project>

Can ant generate a unified script including all imports similar to maven's effective pom?

I have an ant script that imports other scripts which import additional scripts leading to web of places where definitions can happen.
Can ant pull in all the definitions and output a file much like maven's help:effective-pom?
I'd like to add this as an output file with my build to make debugging somewhat easier.
You can create another target which will create that kind of file. For example it can look like this:
main build.xml which do some work and also can generate effective build:
<project name="testxml" default="build">
<import file="build1.xml" />
<import file="build2.xml" />
<target name="build">
<echo>build project</echo>
</target>
<target name="effective.build">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpath="C:\Program Files (x86)\groovy-2.1.4\embeddable\groovy-all-2.1.4.jar" />
<groovy>
def regex = ~/import file="(.*)"/
def buildXmlContent = new File('build.xml').text
new File('build.xml').eachLine {
line -> regex.matcher(line).find() {
def file = new File(it[1])
if (file.exists()) {
def replacement = file.getText().replaceAll(/<project.*/, '').replaceAll(/<\/project.*/, '')
buildXmlContent = buildXmlContent.replaceFirst(/<import.*/, replacement)
}
}
}
new File('build.effective.xml') << buildXmlContent
</groovy>
</target>
</project>
Two build.xml's created for tests:
<project name="testxml2" default="build">
<target name="clean">
<echo>clean project</echo>
</target>
</project>
<project name="testxml1" default="build">
<target name="test">
<echo>test project</echo>
</target>
</project>
If you will run ant effective.build you will get new build.effective.xml file with this content:
<project name="testxml" default="build">
<target name="test">
<echo>test project</echo>
</target>
<target name="clean">
<echo>clean project</echo>
</target>
<target name="build">
<echo>build project</echo>
</target>
<target name="effective.build">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpath="C:\Program Files (x86)\groovy-2.1.4\embeddable\groovy-all-2.1.4.jar" />
<groovy>
import java.util.regex.Pattern
def regex = ~/import file="(.*)"/
def buildXmlContent = new File('build.xml').text
new File('build.xml').eachLine {
line -> regex.matcher(line).find() {
def file = new File(it[1])
if (file.exists()) {
def replacement = file.getText().replaceAll(/<project.*/, '').replaceAll(/<\/project.*/, '')
buildXmlContent = buildXmlContent.replaceFirst(/<import.*/, replacement)
}
}
}
new File('build.effective.xml') << buildXmlContent
</groovy>
</target>
</project>
I chose groovy (because I learn it actually) for this purpose but you can create it in another langage. You can also compile this groovy code to ant task and use it as new task, for example <effectiveant outfile="build.effective.xml">. My example isn't perfect but it shows one of the solutions.

Ant path convert

Good afternoon
I am running ant to process some code now I have path "com/source/project" in properties but I need to pass "com.source.project" to my java code is there anyway I can convert "/" to "." using ant command
thanks
PropertyRegex task works for you, but you need to install ant-contrib.
<project>
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="./ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
<property name="path" value="com/source/project"/>
<echo message="Path=${path}"/>
<propertyregex property="java.package.name"
input="${path}"
regexp="/"
replace="."
global="true"
defaultValue="${path}" />
<echo message="package=${java.package.name}"/>
</project>
Here's some complete project that uses the Ant Plugin Flaka. I also had to replace the ${path.separator} with '.' to start some java classes. See the comments starting with ';'
<project xmlns:fl="antlib:it.haefelinger.flaka">
<fl:install-property-handler/>
<property name="srcroot" value="path/to/srcrootdir"/>
<property name="classroot" value="path/to/classrootdir"/>
<!-- determine all main classes -->
<fileset dir="${srcroot}" includes="**/*.java" id="mainclasses">
<contains text="public static void main"/>
</fileset>
<!-- iterate over those main classes and
call the corresponding classfile -->
<fl:for var="file" in="split('${toString:mainclasses}', ';')">
<fl:let>
; strip the .java Extension
file = replace(file, '', '.java')
; replace fileseparator with '.'
; on Windows you have to use the following line
; replace(file, '\.', '${file.separator}${file.separator}')
file = replace(file, '\.', '${file.separator}')
</fl:let>
<fl:echo>
starting => #{file} in ${classroot}
</fl:echo>
<java classname="#{file}">
<classpath>
<!--
when using a fileset you'll get a
java.util.zip.ZipException because you're
referencing classfiles and no jars
therefore you have to use
pathelement and location
-->
<pathelement location="${classroot}"/>
</classpath>
</java>
</fl:for>
</project>

Resources