Ant read files in a directory and regex - ant

I am trying to read the names of a set of files in a directory and apply regex to those names and obtain a list with comma seperated values. The names of the files are in the format of build_level1_D1.properties, build_level1.D2.properties, build_level2.D1.properties etc...
I need to read all the file names and apply regex and parse the names to get level1_D1, level1_D2, level2_D1 etc.. I need it in the format of property name="build.levels" value="level1_D1,level1_D2,level2_D1" This is what i tried. Need some pointers and help.
<target name="build-levels-all">
<for param="program">
<path><fileset dir="${root.build.path}/build" includes="*"/>
</path>
<sequential>
<propertyregex override="yes" property="file" input="#{program}" regexp="build\_([^\.]*)" select="\1" />
<echo>${file}</echo>
</sequential>
</for>
<echo>${program}</echo>
<-- This prints the files regexed Level1_D1, level2_D2 etc....But i need to capture it in the format of <property name="build.levels" value="level1_D1,level1_D2,level2_D1" /> -->
</target>

Try using an embedded scripting language, like groovy, to do this kind of complex logic.
<target name="process-files">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<groovy>
def list = []
new File('build').eachFile() {
def matcher = it.name =~ /(build_level\d_D\d).properties/
list.add matcher[0][1]
}
properties."build.levels" = list.join(",")
</groovy>
</target>
<target name="doSomething" depends="process-files">
<echo>${build.levels}</echo>
</target>
Just like ant-contrib, groovy needs an additional jar. I normally include a "bootstrap" target to install this:
<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/codehaus/groovy/groovy-all/2.1.6/groovy-all-2.1.6.jar"/>
</target>

Related

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 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"/>

How to compile a .drl file through an ant build script

I am new to Drools. I want to know if it is possible to compile a .drl file using some kind of a command that can be entered in the windows command line (shell/cmd). I looked through the binaries that come with the drools distribution but I am unable to figure out a way to compile a .drl file.
The reason I am interested in such a command is that I want to write an ant build file which will compile my java classes and rules and create a jar. This jar should be self sufficient, i.e running the jar from the command line should run the main program, which passes facts in the session causing the rules that operate on these facts to automatically be executed.
The DroolsCompilerAntTask used to be the way to do this. It would take all your various rule files and compile them into a serialized file. It appears to have some bugs in 5.3 though which I am currently trying to work out. In the meantime, here is an illustrative build file that can be used for creating an executable JAR based on Drools. The build will fail if the rules cannot be compiled.
<project name="DroolsProto" default="dist" basedir=".">
<property name="build.src" location="src"/>
<property name="build.target" location="target"/>
<property name="build.dist" location="dist"/>
<property name="build.artifact" value="droolsproto"/>
<property name="one-jar.dist.dir" value="~/Work/Data/Misc/OneJar"/>
<property name="one-jar.version" value="0.97"/>
<property name="one-jar.ant.jar" value="${one-jar.dist.dir}/one-jar-ant-task-${one-jar.version}.jar"/>
<path id="build.lib.path">
<fileset dir="${build.src}/lib">
<include name="**/*.jar"/>
</fileset>
</path>
<taskdef name="one-jar" classname="com.simontuffs.onejar.ant.OneJarTask"
classpath="${one-jar.ant.jar}" onerror="report"/>
<taskdef name="droolscompiler" classname="org.drools.contrib.DroolsCompilerAntTask">
<classpath refid="build.lib.path"/>
</taskdef>
<target name="clean">
<delete dir="${build.target}"/>
<delete dir="${build.dist}"/>
</target>
<target name="init">
<tstamp/>
<mkdir dir="${build.target}"/>
<mkdir dir="${build.dist}"/>
</target>
<target name="compile" depends="init">
<mkdir dir="${build.target}/classes"/>
<javac srcdir="${build.src}/main/java" destdir="${build.target}/classes">
<classpath refid="build.lib.path"/>
<include name="**/*.java"/>
<exclude name="**/*Test.java"/>
</javac>
</target>
<target name="verify-rules">
<droolscompiler srcDir="${build.src}/main/resources" toFile="${build.target}/classes/foo.foo">
<classpath refid="build.lib.path"/>
</droolscompiler>
</target>
<target name="verify-resources" depends="verify-rules"/>
<target name="bundle-resources" depends="verify-resources">
<copy todir="${build.target}/classes">
<fileset dir="${build.src}/main/resources"/>
</copy>
</target>
<target name="dist" depends="compile, bundle-resources">
<one-jar destfile="${build.dist}/${build.artifact}.jar">
<manifest>
<attribute name="One-Jar-Main-Class" value="org.drools.examples.HelloWorldExample"/>
</manifest>
<main>
<fileset dir="${build.target}/classes"/>
</main>
<lib>
<fileset dir="${build.src}/lib">
<include name="**/*.jar"/>
</fileset>
</lib>
</one-jar>
</target>
</project>
Note that the build uses One-Jar in order to create the self-contained executable, you may wish to substitute this with your 'Super Jar™' tool of choice. There is also a DroolsVerifierAntTask which allegedly can check logical errors in your rules (as opposed to syntactical ones), but I have no hands on experience with it.
You can use something like this:
private static void compile(final String srcFile, final String destFile) throws IOException {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
URL src = FormChecker.class.getResource(srcFile);
Resource r = ResourceFactory.newInputStreamResource(src.openStream());
kbuilder.add(r, ResourceType.DRL);
if (kbuilder.hasErrors()) {
throw new IllegalStateException("Can not initialize Drools: " + kbuilder.getErrors().toString());
}
Collection<KnowledgePackage> kpackages = kbuilder.getKnowledgePackages();
File dest = new File(destFile);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(dest));
out.writeObject(kpackages);
out.close();
}
There's a drools-ant jar in the droolsjbpm-tools zip.

How to pass multiple parameters to a target in Ant?

I have this dummy target:
<mkdir dir="${project.stage}/release
<war destfile="${project.stage}/release/sigma.war">
...
...
</war>
What I want to do is provide two parameters say "abc" & "xyz" which will replace the word release with the values of abc and xyz parameters respectively.
For the first parameter say abc="test", the code above will create a test directory and put the war inside it.Similarly for xyz="production" it will create a folder production and put the war file inside it.
I tried this by using
<antcall target="create.war">
<param name="test" value="${test.param.name}"/>
<param name="production" value="${prod.param.name}"/>
</antcall>
in the target which depends on the dummy target provided above.
Is this the right way to do this.I guess there must be some way to pass multiple parameters and then loop through the parameters one at a time.
unfortunately ant doesn't support iteration like for or foreach loops unless you are refering to files. There is however the ant contrib tasks which solve most if not all of your iteration problems.
You will have to install the .jar first by following the instructions here : http://ant-contrib.sourceforge.net/#install
This should take about 10 seconds. After you can simply use the foreach task to iterate through you custom list. As an example you can follow the below build.xml file :
<project name="test" default="build">
<!--Needed for antcontrib-->
<taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
<target name="build">
<property name="test" value="value_1"/>
<property name="production" value="value_2"/>
<!--Iterate through every token and call target with parameter dir-->
<foreach list="${test},${production}" param="dir" target="create.war"/>
</target>
<target name="create.war">
<echo message="My path is : ${dir}"/>
</target>
</project>
Output :
build:
create.war:
[echo] My path is : value_1
create.war:
[echo] My path is : value_2
BUILD SUCCESSFUL
Total time: 0 seconds
I hope it helps :)
Second solution without using ant contrib. You could encapsulate all your logic into a macrodef and simply call it twice. In any case you would need to write the two parameters at some point in your build file. I don't think there is any way to iterate through properties without using external .jars or BSF languages.
<project name="test" default="build">
<!--Needed for antcontrib-->
<macrodef name="build.war">
<attribute name="dir"/>
<attribute name="target"/>
<sequential>
<antcall target="#{target}">
<param name="path" value="#{dir}"/>
</antcall>
</sequential>
</macrodef>
<target name="build">
<property name="test" value="value_1"/>
<property name="production" value="value_2"/>
<build.war dir="${test}" target="create.war"/>
<build.war dir="${production}" target="create.war"/>
</target>
<target name="create.war">
<echo message="My path is : ${path}"/>
</target>
</project>
I admit that I don't understand the question in detail. Is ${project.stage} the same as the xyz and abc parameters? And why are there two parameters xyz and abc mentioned, when only the word "release" should be replaced?
What I know is, that macrodef (docu) is something very versatile and that it might be of good use here:
<project name="Foo" default="create.wars">
<macrodef name="createwar">
<attribute name="stage" />
<sequential>
<echo message="mkdir dir=#{stage}/release " />
<echo message="war destfile=#{stage}/release/sigma.war" />
</sequential>
</macrodef>
<target name="create.wars">
<createwar stage="test" />
<createwar stage="production" />
</target>
</project>
The output will be:
create.wars:
[echo] mkdir dir=test/release
[echo] war destfile=test/release/sigma.war
[echo] mkdir dir=production/release
[echo] war destfile=production/release/sigma.war
Perhaps we can start from here and adapt this example as required.

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