Remove lines containing keyword from a file - ant

I would like to remove all lines from a textfile which contain a certain keyword.
So far I only found:
<linecontains>
<contains value="assert"/>
</linecontains>
but I don't know how to remove those lines.

You would use that 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:
<project default="test">
<target name="test">
<copy tofile="file.txt.edit" file="file.txt">
<filterchain>
<linecontains negate="true">
<contains value="assert"/>
</linecontains>
</filterchain>
</copy>
</target>
</project>
Before:
$ cat file.txt
abc
assert
def
assert
ghi assert
jkl
After:
$ cat file.txt.edit
abc
def
jkl
To answer your followup question on applying to selected files in a directory:
<copy todir="dest">
<fileset dir="src">
<include name="**/*.txt"/>
</fileset>
<filterchain>
<linecontains negate="true">
<contains value="assert"/>
</linecontains>
</filterchain>
</copy>

You could execute an external command.
I haven't tested but on UNIX you might run something like this:
<exec executable="sed">
<arg value="s/assert//" />
<arg value="YOUR_FILE" />
</exec>

Related

How to solve this ANT issue?

<loadfile property="UIfiles" srcfile="updated.txt">
<filterchain>
<linecontainsregexp>
<regexp pattern="ui/dev/"/>
</linecontainsregexp>
</filterchain>
</loadfile>
<echo file="Filelist.txt" append="true">${UIfiles}</echo>
I have the above code in build.xml file. updated.txt will contain some text like Projects/accounts/spec/ui/dev/dpdl/abc.xml. If this statement is present in the file, then the above code works as expected. If there is no match for regex "ui/dev" in updated.txt, ideally the value of UIfiles should be empty and should not write anything to Filelist.txt. But in my case "${UIfiles}" is getting appended in Filelist.txt. Please suggest how to avoid this. Thank you.
Works as expected. ${...} is the syntax for your property when not set, because
your file doesn't contain a line matching the regexp.
You need some if isset condition, with Ant 1.9.3 and new if unless feature :
<project
xmlns:if="ant:if"
xmlns:unless="ant:unless"
>
<loadfile property="UIfiles" srcfile="updated.txt">
<filterchain>
<linecontainsregexp>
<regexp pattern="ui/dev/"/>
</linecontainsregexp>
</filterchain>
</loadfile>
<echo file="Filelist.txt" append="true">${UIfiles} if:set="UIfiles"</echo>
</project>
otherwise for older Ant versions use:
<project>
<target name="checkfile">
<loadfile property="UIfiles" srcfile="updated.txt">
<filterchain>
<linecontainsregexp>
<regexp pattern="ui/dev/"/>
</linecontainsregexp>
</filterchain>
</loadfile>
</target>
<target name="appendfilelist" depends="checkfile" if="UIfiles">
<echo file="Filelist.txt" append="true">${UIfiles}</echo>
</target>
<project>

Specify Multiple Output Files or Target Files for an Ant Apply Task

I'm trying to figure out a way to have Ant run a .jar executable that accepts a file and spits out several generated files from the single input file. Specifically, I'm trying to generate compiled .js files and at the same time generate .map files.
Normally, the command would look something like this:
java -jar compiler-latest --js a.js --js_output_file a.min.js --create_source_map a.js.map
Where:
compiler-latest is the closure-compiler jar
a.js is the JavaScript file to compile
a.min.js is the compiled JavaScript
a.js.map is the source map
My Ant script looks like this:
<project name="BuildTest" default="Build" basedir=".">
<description>
HTML Build Test with Ant
</description>
<property name="src" location="../js"/>
<property name="dst" location="../build"/>
<property name="compiler" location="../compiler.jar"/>
<!--Make Dest Directory-->
<target name="-destination">
<mkdir dir="${dst}"/>
</target>
<!--Compile JS-->
<target name="Build" depends="-destination">
<!--Filesets and Mappers-->
<fileset id="sourceFiles" dir="${src}" includes="*.js"/>
<mapper id="compiledJs" type="glob" from="*.js" to="*.compiled.js"/>
<mapper id="mapJs" type="glob" from="*.js" to="*.js.map"/>
<!--Apply Everything-->
<apply executable="java" parallel="false" dest="${dst}">
<!--Closure Compiler-->
<arg value="-jar"/>
<arg path="${compiler}"/>
<arg value="--compilation_level=SIMPLE_OPTIMIZATIONS"/>
<!--Source Files-->
<arg value="--js"/>
<srcfile/>
<fileset refid="sourceFiles"/>
<!--Output Files-->
<arg value="--js_output_file"/>
<targetfile/>
<mapper refid="compiledJs"/>
<!--Source Maps-->
<arg value="--source_map_format=V3"/>
<arg value="--create_source_map"/>
<arg value="--js_output_file"/>
<targetfile/>
<mapper refid="mapJs"/>
</apply>
</target>
<!--Clean Project-->
<target name="Clean" description="Cleans the project">
<delete dir="${dst}"/>
</target>
</project>
However, I get an error saying I can't have multiple <targetfile/> elements
apply doesn't support multiple targetfile elements.
This is a workaround, not nice, but effective.
You can use an Ant <compositemapper> to construct the command line for your application.
Below is an illustration. You need to set relative="yes" on the task in order that filenames relative to the build directory are used in preference to absolute filenames, otherwise mapping is harder. To build the command line provide a list of mappers inside the <compositemapper>. Use a <mergemapper> for fixed parts (args like --output_file), and use a suitable other mapper, maybe a glob, when you need to generate filenames.
A series of mappers is needed to separate the arguments passed to the java by <apply>, otherwise they will be passed as one long arg with embedded spaces.
<apply executable="java" parallel="false" relative="yes">
<arg line="-jar compiler-latest --js"/>
<srcfile />
<targetfile />
<compositemapper>
<mergemapper to="--js_output_file" />
<globmapper from="*.js" to="*.compiled.js" />
<mergemapper to="--source_map_format=V3" />
<mergemapper to="--create_source_map" />
<globmapper from="*" to="*.map" />
</compositemapper>
<fileset dir="." includes="*.js" />
</apply>
For a simple test that leads to a command line like:
java -jar compiler-latest --js 1.js --js_output_file 1.compiled.js --source_map_format=V3 --create_source_map 1.js.map

how can i filter whole line which contains a specific string

i have the following Ant script for reading revisionlog.txt file line by line and printing all the line.
<target name="line_by_line">
<loadfile property="file" srcfile="revisionlog.txt"/>
<for param="line" list="${file}" delimiter="${line.separator}">
<sequential>
<echo>#{line}</echo>
</sequential>
</for>
</target>
but here i want to print those line only which contains Comments: string.
how can i do this.
you may use loadfile combined with a filterchain, f.e. :
<loadfile property="yourline" srcfile="revisionlog.txt">
<filterchain>
<linecontains>
<contains value="Comments:"></contains>
</linecontains>
</filterchain>
</loadfile>
<echo>$${yourline} = ${line.separator}${yourline}</echo>
if you need more control, use <linecontainsregexp>
see Ant manual for FilterChains and FilterReaders

How can I echo a filename twice using 'FileSet' and 'PathConvert'?

I have this simple Ant task that lists all '.png' files in a folder:
<target name="listimages">
<!-- Assume files a A and B -->
<fileset id="dist.contents" dir="${basedir}">
<include name="**/*.png"/>
</fileset>
<pathconvert pathsep="${line.separator}"
property="prop.dist.contents"
refid="dist.contents">
<mapper type="flatten" />
<map from="${basedir}" to=""/>
</pathconvert>
<echo>${prop.dist.contents}</echo>
</target>
This prints
[echo] A.png
[echo] B.png
But, what I want is for the filenames to appear twice on each line.
[echo] A.png,A.png
[echo] B.png,B.png
How can I do that?
(This question is a follow up to How can I print a fileset to a file, one file name per line?)
You could use a regexp mapper (instead of the flatten) that implements the flattening and duplication. This is pretty simplistic, but might do:
<mapper type="regexp" from=".*/(.*)" to="\1,\1" />
Would need adjusting for your local path separator.
Better though, use a chainedmapper in place of the flatten:
<chainedmapper>
<mapper type="flatten" />
<mapper type="regexp" from="(.*)" to="\1,\1" />
</chainedmapper>

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