Ant equivalent of cut | sort | uniq - ant

In an Ant task I set a property which is a list of files. e.g.
web/src/main/test/com/whatever/Ralph
business/src/main/test/com/whatever/Alice
web/src/main/test/com/whatever/Bob
I would like to extract the set of subdirectories from this list. In bash I'd:
$ cat filename | cut -d'/' -f1 | sort | uniq
business
web
Is there a way I can do something similar in an Ant macro? It needs to run on Windows too, so <exec> is not an option.

You can do this using a loadresource task with a filterchain. Something like this perhaps:
<property name="list.of.files">
web/src/main/test/com/whatever/Ralph
business/src/main/test/com/whatever/Alice
web/src/main/test/com/whatever/Bob
</property>
<loadresource property="dirs">
<string value="${list.of.files}" />
<filterchain>
<replaceregex pattern="/.*" replace="" />
<sortfilter />
<uniqfilter />
</filterchain>
</loadresource>
<echo message="${dirs}" />
Result:
[echo] business
[echo] web
BUILD SUCCESSFUL
In older versions of Ant (<1.7) you could do the same by writing the property out to a file, then using a loadfile task with filterchain.

Related

How can I extract version from a file name in Ant without using ant contrib?

I am trying to scan a folder in ant script and extract the version out of it, suppose file name is abc-1.0.0.exe/dmg. I want to get the 1.0.0 in Ant. Is there any way I can do without using ant contrib? I only found help with ant contrib which I don't want to use.
You might be able to use something like this, based on the <pathconvert> task with a regexmapper.
Here's the directory structure in this example:
$ find folder
folder
folder/abc-1.0.0.exe
folder/abc-1.0.0.exe/dmg
Here's the Ant buildfile:
<fileset dir="folder" id="folder"/>
<echo message="file is: ${toString:folder}" />
<pathconvert property="version">
<path path="${toString:folder}" />
<regexpmapper from=".*-(.*).exe.*" to="\1" />
</pathconvert>
<echo message="version is: ${version}" />
Output:
[echo] file is: abc-1.0.0.exe/dmg
[echo] version is: 1.0.0

How to read the Class-Path from a JAR in Ant?

The Class-Path of a JAR is written in the Manifest file in the JAR. The following Bash code reads the Class-Path from a JAR, if it does not exceed the 72 char limit:
unzip -c "$1" META-INF/MANIFEST.MF |
sed -n 's/^Class-Path: \(.\+\)$/\1/p' |
tr -d '\r'
Right now I am calling the code with exec in Ant but I would like to remove all execs.
How to do the same in Ant without using unzip, sed and tr?
You may want to try adding the following (in the beginning of your build.xml file where properties are defined) which puts the short Class-Path in property classpath:
<loadresource property="classpath">
<zipentry zipfile="demo.jar" name="META-INF/MANIFEST.MF"/>
<filterchain>
<tokenfilter>
<containsregex pattern="^Class-Path: (.+)$" flags="i"/>
<replaceregex pattern="^Class-Path: (.+)$" replace="\1" flags="i"/>
</tokenfilter>
<tokenfilter><!-- get rid of trailing line separator -->
<filetokenizer/>
<replaceregex pattern="(\r?\n)+" replace="" flags="m"/>
</tokenfilter>
</filterchain>
</loadresource>
Edit: If you put the following before the tokenfilter above, then it should also work for longer values of Class-Path (by first joining split lines):
<tokenfilter>
<filetokenizer/>
<replaceregex pattern="\r?\n (.+)$" replace="\1" flags="m"/>
</tokenfilter>

Want to remove [echo], [script] like keywords from file

I am using filter in a filterchain, in a task which supports the filterchain element, i.e. the built-in Concat, Copy, LoadFile, LoadProperties, Move tasks.
So, for example, copy or move the file using a filterchain containing your linecontains filter.
Use the negate parameter on your linecontains filter to exclude lines containing that string.
Example: Consider the following code
<project default="test">
<target name="test">
<copy tofile="file.txt.edit" file="file.txt">
<filterchain>
<linecontains negate="true">
<contains value="[echo]"/>
</linecontains>
</filterchain>
</copy>
</target>
</project>
outputs:
$ cat file.txt
[echo] Your project1 location is: D:/Project/Project1
[echo] Your project2 location is: D:/Project/Project2
[script] my script running
[echo] Your project3 location is: D:/Project/Project3
[echo] Your project4 location is: D:/Project/Project4
$ cat file.txt.edit
[script] my script running
Expected:
$ cat file.txt.edit
Your project1 location is: D:/Project/Project1
Your project2 location is: D:/Project/Project2
[script] my script running
Your project3 location is: D:/Project/Project3
Your project4 location is: D:/Project/Project4
Here if i am using filterchain then complete line gets deleted. I want only the word like
[echo], [script]...etc. should be removed.
Replace your linecontains element with replaceregex:
<tokenfilter>
<replaceregex pattern="\[echo\]" replace="" />
</tokenfilter>
For multiple token replacements, modify pattern="\[(echo|script)\]"

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

Filtering Files In-Place with Ant?

I have a directory of files for which I'd like to do "in-place" string filtering using Apache Ant (version 1.7.1 on Linux).
For example, suppose that in directory mydir I have files foo, bar, and baz. Further suppose that all occurences of the regular expression OLD([0-9]) should be changed to NEW\1, e.g. OLD2 → NEW2. (Note that the replace Ant task won't work because it does not support regular expression filtering.)
This test situation can be created with the following Bash commands (ant will be run in the current directory, i.e. mydir's parent directory):
mkdir mydir
for FILE in foo bar baz ; do echo "A OLD1 B OLD2 C OLD3" > mydir/${FILE} ; done
Here is my first attempt to do the filtering with Ant:
<?xml version="1.0"?>
<project name="filter" default="filter">
<target name="filter">
<move todir="mydir">
<fileset dir="mydir"/>
<filterchain>
<tokenfilter>
<replaceregex pattern="OLD([0-9])" replace="NEW\1" flags="g"/>
</tokenfilter>
</filterchain>
</move>
</target>
</project>
Running this first Ant script has no effect on the files in mydir. The overwrite parameter is true by default with the move Ant task. I even fiddled with the granularity setting, but that didn't help.
Here's my second attempt, which "works," but is slightly annoying because of temporary file creation. This version filters the content properly by moving the content to files with a filtered suffix, then the filtered content is "moved back" with original filenames:
<?xml version="1.0"?>
<project name="filter" default="filter">
<target name="filter">
<move todir="mydir">
<globmapper from="*" to="*.filtered"/>
<fileset dir="mydir"/>
<filterchain>
<tokenfilter>
<replaceregex pattern="OLD([0-9])" replace="NEW\1" flags="g"/>
</tokenfilter>
</filterchain>
</move>
<move todir="mydir">
<globmapper from="*.filtered" to="*"/>
<fileset dir="mydir"/>
</move>
</target>
</project>
Can the first attempt (without temporary files) be made to work?
See the replace task:
<replace
dir="mydir"
includes="foo, bar, baz">
<replacefilter token="OLD" value="NEW" />
</replace>
or the replaceregexp task:
<replaceregexp
file="${src}/build.properties"
match="OldProperty=(.*)"
replace="NewProperty=\1"
byline="true"/>

Resources