Does (ant-contrib) propertyregex support multiple uses from the same property? - ant

I'm attempting to use a property as a template for multiple other properties, but it only works the first time. It's probably easiest to show by example, so I've cut down my code to a minimal case that exhibits this behaviour:
<target name="test">
<property name="individual.template" value="x#ID#"/>
<propertyregex property="individual.1" input="${individual.template}" regexp="\#ID\#" replace="1" global="true" override="true"/>
<echo>====== ${individual.1} ::: ${individual.template}</echo>
<propertyregex property="individual.2" input="${individial.template}" regexp="\#ID\#" replace="2" global="true" override="true"/>
<echo>====== ${individual.2} ::: ${individual.template}</echo>
<propertyregex property="individual.3" input="${individial.template}" regexp="\#ID\#" replace="3" global="true" override="true"/>
<echo>====== ${individual.3} ::: ${individual.template}</echo>
<propertyregex property="individual.4" input="${individial.template}" regexp="\#ID\#" replace="4" global="true" override="true"/>
<echo>====== ${individual.4} ::: ${individual.template}</echo>
<propertyregex property="individual.5" input="${individial.template}" regexp="\#ID\#" replace="5" global="true" override="true"/>
<echo>====== ${individual.5} ::: ${individual.template}</echo>
</target>
I would expect this to output x1, x2, etc., but it outputs the following:
[echo] ====== x1 ::: x#ID#
[echo] ====== ${individual.2} ::: x#ID#
[echo] ====== ${individual.3} ::: x#ID#
[echo] ====== ${individual.4} ::: x#ID#
[echo] ====== ${individual.5} ::: x#ID#
As you can see it's ok for the first one, but the next properties are simply not set. I thought at first that the template property was modified, but as you can see from the output, that's not the case. Am I just doing something silly here? Is this not supported? Or is it a bug? Any ideas would be greatly appreciated.
(Ant version 1.8.2, ant-contrib version 1.0b2).

It's just a typo: (individ i al) vs. (individ u al)

#thor84no, I see a copy/paste error in the test case: Shouldn't you be printing the value of individual.1/individual.2/individual.3/individual.4/individual.5 instead of individual.template? I made these changes locally and the output is what you had expected:
test:
[echo] ====== x1 ::: x1
[echo] ====== x2 ::: x2
[echo] ====== x3 ::: x3
[echo] ====== x4 ::: x4
[echo] ====== x5 ::: x5

Related

Propertyregex to read a CSV line and assign fields to variables

I have a csv/txt file with below entries
abc,123
xyz,678
ijk,921
I'm trying to read the file through for loop and assign first element to var1, and second to var2
var1=abc
var2=123
I need to use these variables to perform some task and return back to the loop to read the next line of the file and assign new values.
Below is what I have, and I'm not able to assign the variable
<loadfile property="message" srcFile="test.txt" />
<target name="compile">
<for param="line" list="${message}" delimiter="${line.separator}">
<sequential>
<echo>#{line}</echo>
<propertyregex property="var1"
input="#line"
regexp="/^(.+?),(.+)/"
select="\1" />
<echo message="${var1}" />
</sequential>
</for>
</target>
Below is the output I get, showing no assignment of value to var1.
[echo] abc,123
[echo] ${var1}
[echo] xyz,678
[echo] ${var1}
[echo] ijk,921
[echo] ${var1}
You have a couple of errors, the below loop body works for me, see output at the end.
The first problem is that the #{line} parameter substitution syntax in the for loop uses an antcontrib macrodef, and the {} brakets are not optional - you had missed them out of the input="" attribute, whereas in the echo task you had included them.
The second problem is that you need not specify enclosing slashes /../ in the rexexp= attribute.
<echo>#{line}</echo>
<propertyregex property="var1"
override="yes"
input="#{line}"
regexp="^(.+?),(.+)"
select="\1"/>
<propertyregex property="var2"
override="yes"
input="#{line}"
regexp="^(.+?),(.+)"
select="\2"/>
<echo message="${var1},${var2}" />
Output:
[echo] abc,123
[echo] abc,123
[echo] xyz,678
[echo] xyz,678
[echo] ijk,921
[echo] ijk,921

Ant: don't print build.xml indentation with echo or fail

Say I have the following in my build.xml file:
<target name="FOO">
<echo>a
b
c
d</echo>
</target>
The result is:
[echo] a
[echo] b
[echo] c
[echo] d
I want the output to be:
[echo] a
[echo] b
[echo] c
[echo] d
To get that, I could change build.xml to:
<target name="FOO">
<echo>a
b
c
d</echo>
</target>
But is there anything else I can do to get the same output? Anything that keeps the build.xml indentation the same as the original, that is.
One of the solution is to use line.separator property
<property name="nl" value="${line.separator}"/>
<target name="FOO">
<echo>a${nl}b${nl}c${nl}d</echo>
</target>
Output:
FOO:
[echo] a
[echo] b
[echo] c
[echo] d
Second solution is to create custom ANT task, that will provide output as you need (your custom java code will modify ant output massage). See http://www.developer.com/java/article.php/3630721/Introduction-to-Custom-Ant-Tasks.htm

Excluding a directory and all subdirectories of it?

I have a Java application that I am packaging into a JAR. I created an Ant script to do that as I need to also add resources to the JAR (icons etc).
Now, I have libraries that I use in my project (Apache HttpClient and a JSON library). I also copy their contents into the JAR, as it is the simplest way.
My build file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project default="create_run_jar"
name="Create Runnable Jar">
<target name="create_run_jar">
<jar destfile="C:/Users/Pietu1998/Documents/Java/Whatever.jar"
filesetmanifest="mergewithoutmain">
<manifest>
<attribute name="Main-Class"
value="net.pietu1998.whatever" />
<attribute name="Class-Path" value="." />
</manifest>
<fileset dir="C:/Users/Pietu1998/Documents/Java/Whatever/bin"
includes="*.class" />
<fileset dir="C:/Users/Pietu1998/Documents/Java/Whatever/res" />
<zipfileset excludes="META-INF/**"
src="C:/Users/Pietu1998/Documents/Java/Whatever/lib/commons-codec-1.6.jar" />
<zipfileset excludes="META-INF/**"
src="C:/Users/Pietu1998/Documents/Java/Whatever/lib/commons-logging-1.1.3.jar" />
<!-- More (like 5) JARs -->
</jar>
</target>
</project>
However, the libraries (JARs) have their own META-INF folders, and they have a lot of stuff in them; files like LICENSE, CONDITIONS and also a folder for Maven called maven.
The project is for personal use, so I just want to get rid of the unnecessary stuff. I have tried some ways to exclude all of the META-INF stuff, but something is always left behind.
excludes="META-INF" leaves everything.
excludes="META-INF/**" leaves the maven folder.
**/excludes="META-INF/**", see above.
I believe I could use a lot of include-excludes or patternsets, but it would lead to a lot of repeating.
Is there a way (not for this specific case) to exclude a folder (META-INF here) and all its contents including subdirectories, and preferably with not too much repeating (for a lot of libraries)?
Using excludes="META-INF/**"" works for me (Ant 1.9.3, Windows 7, JDK 1.7.0_51)
Some test after downloading original commons-logging-1.1.3.jar from here :
<project>
<zipfileset excludes="META-INF/**" src="c:/area51/commons-logging-1.1.3.jar" id="foobar"/>
<!-- for output line by line -->
<pathconvert property="foo" refid="foobar">
<map from="c:/area51/commons-logging-1.1.3.jar:" to="${line.separator}"/>
</pathconvert>
<echo>${foo}</echo>
</project>
output contains only classfiles under org/apache/commons/logging/.. :
[echo] commons-logging-1.1.3.jar
[echo] org/apache/commons/logging/Log.class;
[echo] org/apache/commons/logging/LogConfigurationException.class;
[echo] org/apache/commons/logging/LogFactory$1.class;
[echo] org/apache/commons/logging/LogFactory$2.class;
[echo] org/apache/commons/logging/LogFactory$3.class;
[echo] org/apache/commons/logging/LogFactory$4.class;
[echo] org/apache/commons/logging/LogFactory$5.class;
[echo] org/apache/commons/logging/LogFactory$6.class;
[echo] org/apache/commons/logging/LogFactory.class;
[echo] org/apache/commons/logging/LogSource.class;
[echo] org/apache/commons/logging/impl/AvalonLogger.class;
[echo] org/apache/commons/logging/impl/Jdk13LumberjackLogger.class;
[echo] org/apache/commons/logging/impl/Jdk14Logger.class;
[echo] org/apache/commons/logging/impl/Log4JLogger.class;
[echo] org/apache/commons/logging/impl/LogFactoryImpl$1.class;
[echo] org/apache/commons/logging/impl/LogFactoryImpl$2.class;
[echo] org/apache/commons/logging/impl/LogFactoryImpl$3.class;
[echo] org/apache/commons/logging/impl/LogFactoryImpl.class;
[echo] org/apache/commons/logging/impl/LogKitLogger.class;
[echo] org/apache/commons/logging/impl/NoOpLog.class;
[echo] org/apache/commons/logging/impl/ServletContextCleaner.class;
[echo] org/apache/commons/logging/impl/SimpleLog$1.class;
[echo] org/apache/commons/logging/impl/SimpleLog.class;
[echo] org/apache/commons/logging/impl/WeakHashtable$1.class;
[echo] org/apache/commons/logging/impl/WeakHashtable$Entry.class;
[echo] org/apache/commons/logging/impl/WeakHashtable$Referenced.class;
[echo] org/apache/commons/logging/impl/WeakHashtable$WeakKey.class;
[echo] org/apache/commons/logging/impl/WeakHashtable.class
Maybe you forgot to set the update attribute from your jar task to true :
<jar destfile=".." update="true" ..>
to overwrite some already existing jarfile with the same name !?
I found a way to do it with the stars.
<zipfileset excludes="META-INF/**/*" src="C:\library.jar" />
This excludes the META-INF folder and all its contents.
* means it excludes all files inside a folder, and
foo/**/bar means it excludes bar in any level inside foo.
So, foo/**/* excludes every file on every level inside foo.

How to use ant to extract all substring in a file without using regex

I have a file has many lines such as:
aaa bbb ccc ddd eeee
a111 b111 c111 d111
A222 B222 X222 Y222 Z222
FFF GGG HHH
etc
I hope to use ant to extract all substring in this file
aaa bbb ccc ddd eeee
a111 b111 c111 d111
A222 B222 X222 Y222 Z222
FFF GGG HHH
in each line, ie
all aaa bbb ccc ddd eee in 1st line,
all FFF GGG HHH in last line etc
Pls help how to do it but not using regex???
My code is:
<for list="#{line}" delimiter=" " param = "val">
<sequential>
<echo>in sequential : #{line}</echo>
<var name="first.part" value="1"/>
<var name="second.part" value="2"/>
<var name="third.part" value="3"/>
<propertyregex
property="first.part"
input="#{line}"
select="\0"/>
<propertyregex
property="second.part"
input="#{line}"
select="\1"/>
<propertyregex
property="third.part"
input="#{line}"
select="\2"/>
<echo> after assign: 1st.part = ${first.part}</echo>
<echo> after assign: 2nd.part = ${second.part}</echo>
<echo> after assign: 3rd.part = ${third.part}</echo>
</sequential>
</for>
But ant 1.6 did not support regex,
I got error:
The type doesn't support the "regex" attribute.
how to fix it???
Thanks
ANT is not a programming language. You are best advised to embed one.
The following example uses groovy:
<project name="demo" default="scan">
<target name="bootstrap">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/groovy.jar" src="http://search.maven.org/remotecontent?filepath=org/codehaus/groovy/groovy-all/2.1.3/groovy-all-2.1.3.jar"/>
</target>
<target name="scan">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<groovy>
new File("File1.txt").eachLine {
def values = it.split()
ant.echo "Extracted values: ${values}"
values.each {
ant.echo "Need to so something with ${it}"
}
}
</groovy>
</target>
</project>
Produces the following output
scan:
[echo] Extracted values: [aaa, bbb, ccc, ddd, eeee]
[echo] Need to so something with aaa
[echo] Need to so something with bbb
[echo] Need to so something with ccc
[echo] Need to so something with ddd
[echo] Need to so something with eeee
[echo] Extracted values: [a111, b111, c111, d111]
[echo] Need to so something with a111
[echo] Need to so something with b111
[echo] Need to so something with c111
[echo] Need to so something with d111
[echo] Extracted values: [A222, B222, X222, Y222, Z222]
[echo] Need to so something with A222
[echo] Need to so something with B222
[echo] Need to so something with X222
[echo] Need to so something with Y222
[echo] Need to so something with Z222
[echo] Extracted values: [FFF, GGG, HHH]
[echo] Need to so something with FFF
[echo] Need to so something with GGG
[echo] Need to so something with HHH
Update
An alternative way to enable the groovy task is to use a classpath reference as follows:
<path id="build.path">
<pathelement location="/path/to/groovy-all/jar/groovy-all-2.1.3.jar"/>
</path>
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>

trouble using replaceregexp when replacing string DIR location

I am having trouble in doing this.
there is 1 batch file with this line:
set TEST_DIR=C:\temp\dir1
I just want to set some new value to TEST_DIR
But, when I use in my ant script, it escapes forward slashes and gives this result:
set TEST_DIR=C:homedir2
Instead, I want to give it:
set TEST_DIR=C:\home\dir2
I am using this command:
<replaceregexp file="${MT_BATCH_FILE_LOCATION}\myfile.bat" match="TEST_DIR=C:\\temp\\dir1" replace="TEST_DIR=C:\home\dir2" byline="true" />
You can get the result you want by using this replace pattern:
replace="TEST_DIR=C:\\\\home\\\\dir2"
The reason is that you must escape the backslash once for the regex and once for Java - backslash is an escape character in both those contexts.
In answer to your subsequent questions in comments...
I expect the answer will be the same. You will need to double-escape the backslash in the value of ${new_loc}, i.e. use C:\\\\my_projcode not C:\my_projcode.
If new_loc is coming in as an environment variable, you could use the propertyregex task from ant-contrib to escape backslashes in the value:
<project default="test">
<!-- import ant-contrib -->
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="C:/lib/ant-contrib/ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
<target name="test">
<!-- load environment variables -->
<property environment="env"/>
<!-- escape backslashes in new_loc -->
<propertyregex property="loc" input="${env.new_loc}" regexp="\\" replace="\\\\\\\\\\\\\\\\" />
<echo message="env.new_loc: ${env.new_loc}"/>
<echo message="loc: ${loc}"/>
<!-- do the replace -->
<replaceregexp file="test.bat" match="TEST_DIR=C:\\temp\\dir1" replace="TEST_DIR=${loc}\\\\home\\\\dir2" byline="true" />
</target>
Output:
c:\tmp\ant>set new_loc=c:\foo\bar
c:\tmp\ant>ant
Buildfile: c:\tmp\ant\build.xml
test:
[echo] new_loc: c:\foo\bar
[echo] env.new_loc: c:\foo\bar
[echo] loc: c:\\\\foo\\\\bar
BUILD SUCCESSFUL
Total time: 0 seconds
c:\tmp\ant>type test.bat
set TEST_DIR=c:\foo\bar\home\dir2
I have found another simple solution use replace instead of replaceregexp.
<replace file="${MT_BATCH_FILE_LOCATION}\myfile.bat"
token='TEST_DIR=C:\temp\dir1'
value='TEST_DIR=${new_loc}\home\dir2' />

Resources