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>
Related
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)\]"
I've got foo.js, and an ant build process that results in foo.min.js.
foo.js has a header comment that includes:
* $Id: foo.js 12345 2011-10-04 14:35:23Z itoltz $
Where 12345 is the revision of the file when committed to SVN.
I'd like to copy foo.min.js to foo.min.12345.js
You can extract the revision number into a property using loadfile and regex. Then you can copy the file using the property.
<project default="rename">
<target name="rename" depends="get-rev">
<copy file="foo.min.js" toFile="foo.min.${revision.number}.js"/>
</target>
<target name="get-rev">
<loadfile srcFile="foo.js" property="revision.number">
<filterchain>
<linecontainsregexp>
<regexp pattern="\* \$Id: foo.js"/>
</linecontainsregexp>
<tokenfilter>
<replaceregex pattern="\* \$Id: foo.js (\d+).*" replace="\1"/>
</tokenfilter>
<striplinebreaks/>
</filterchain>
</loadfile>
<echo message="revision.number: ${revision.number}"/>
</target>
</project>
Output:
$ ls
build.xml foo.js foo.min.js
$
$ ant
Buildfile: C:\tmp\build.xml
get-rev:
[echo] revision.number: 12345
rename:
[copy] Copying 1 file to C:\tmp
BUILD SUCCESSFUL
Total time: 0 seconds
$
$ ls
build.xml foo.js foo.min.12345.js foo.min.js
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.
In my build.xml, I want to do the equivalent of cmd1 | xargs cmd2 (and also store the list of files from cmd1 into the variable ${dependencies}), where cmd1 gives a newline-separated list of paths. I can't figure out how to do this in Ant.
<project default="main">
<target name="main">
<exec executable="echo"
outputproperty="dependencies">
<arg value="closure/a.js
closure/b.js
closure/c.js"/>
<redirector>
<outputfilterchain>
<replacestring from="${line.separator}" to=" "/>
<!-- None of these do anything either:
<replacestring from="\n" to=" "/>
<replacestring from="
" to=" "/>
<replaceregex pattern="
" replace=" " flags="m"/>
<replaceregex pattern="\n" replace=" " flags="m"/>
<replaceregex pattern="${line.separator}" replace=" " flags="m"/>
-->
</outputfilterchain>
</redirector>
</exec>
<!-- Later, I need to use each file from ${dependencies} as an argument
to a command. -->
<exec executable="echo">
<!--This should turn into 3 arguments, not 1 with newlines.-->
<arg line="${dependencies}"/>
</exec>
</target>
</project>
This filter might do for the first part - it assumes though that none of your files start with a space character.
<outputfilterchain>
<prefixlines prefix=" " />
<striplinebreaks />
<trim />
</outputfilterchain>
It prefixes each line with a space, then removes the line breaks - giving a single line with all the filenames separated by single spaces, but with one space at the beginning. So the trim is used to chop that off.
Thanks martin. I also found another solution upon reading the filterchain documentation more carefully.
<outputfilterchain>
<tokenfilter delimoutput=" ">
<!--The following line can be omitted since it is the default.-->
<linetokenizer/>
</tokenfilter>
</outputfilterchain>
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"/>