Deleting the bottom line of a file using ant - ant

I have created ant target that is supposed to delete the bottom line of a file and then echo it out to a file of a different name. The code that I'm using for the target is:
<loadfile srcfile="/dir/example/file.txt" property="last.line.removed">
<filterchain>
<filterreader classname="org.apache.tools.ant.filters.TailFilter">
<param name="lines" value="-1"/>
<param name="skip" value="1"/>
</filterreader>
</filterchain>
</loadfile>
<echo message="${last.line.removed}" file="/dir/example/file2.txt" append="true"/>
I have ran this target in the build on its own and it is just echoing back the original file rather than removing the bottom line.
If anyone could tell me why this doesn't work or a better way of doing it then it'd be much appreciated.

I could not replicate the problem...
Example
Running the code produces the expected result (demonstrated by the diff command):
$ ant
$ diff src/file.txt target/file.txt
2d1
< how are you?
Project files
├── build.xml
├── src
│   └── file.txt
└── target
└── file.txt
build.xml
<project name="demo" default="build">
<target name="build">
<mkdir dir="target"/>
<loadfile srcfile="src/file.txt" property="last.line.removed">
<filterchain>
<filterreader classname="org.apache.tools.ant.filters.TailFilter">
<param name="lines" value="-1"/>
<param name="skip" value="1"/>
</filterreader>
</filterchain>
</loadfile>
<echo message="${last.line.removed}" file="target/file.txt" append="true"/>
</target>
<target name="clean">
<delete dir="target"/>
</target>
</project>
src/file.txt
hello world
how are you?
target/file.txt
hello world

Related

ANT replacing strings in specified files using file with properties

I have a properties in file dev.properties and they look like this:
test.url=https://www.example.com/
[...]
and in project files there is a token [[test.url]] which I want to replace by https://www.example.com/. I just want to define all tokens in dev.properties and use them in build script, but without modifying build script and I want to replace those tokens in a specified files like *.php, *.html, etc.
Can someone give me a suggestions how to do it? Thanks.
try this:
<copy file="input.txt" tofile="output.txt">
<filterchain>
<replaceregex pattern="\$\{" replace="{" />
<filterreader classname="org.apache.tools.ant.filters.ReplaceTokens">
<param type="propertiesfile" value="properties.txt"/>
<param type="tokenchar" name="begintoken" value="{"/>
<param type="tokenchar" name="endtoken" value="}"/>
</filterreader>
</filterchain>
</copy>
Founded here: Ant replace token from properties file
In the following Ant script, replace the src-root property with the root directory containing the tokenized files:
<project name="ant-replace-tokens-with-copy-task" default="run">
<target name="run">
<!-- The <copy> task cannot "self-copy" files. So, for each -->
<!-- matched file we'll have <copy> read the file, replace the -->
<!-- tokens, and write the result to a temporary file. Then, we'll -->
<!-- use the <move> task to replace the original files with the -->
<!-- modified files. -->
<property name="src-root" location="src"/>
<property name="filtered-file.extension" value="*.filtered-file"/>
<copy todir="${src-root}">
<fileset dir="${src-root}">
<include name="**/*.html"/>
<include name="**/*.php"/>
</fileset>
<globmapper from="*" to="${filtered-file.extension}"/>
<filterchain>
<filterreader classname="org.apache.tools.ant.filters.ReplaceTokens">
<param type="propertiesfile" value="dev.properties"/>
</filterreader>
</filterchain>
</copy>
<move todir="${src-root}">
<fileset dir="${src-root}" includes="**"/>
<globmapper from="${filtered-file.extension}" to="*"/>
</move>
</target>
</project>
You specified that you do not want to edit your build script so this answer does not qualify but may still be useful to other readers.
If you were willing to edit your target file to use the format ${test.url} instead of [[test.url]] then ExpandProperites would be an excellent choice.

Ant Nested Loop

I have two txt files: File1.txt – contains list of src dir; and File2.txt – contains list of dest dir. I need to do the copy using a loop from src dir to dest dir.
File1.txt (SVN dire structure)
abcBIN
abcBIN/fdPro
...so on
File2.txt (LINUX structure)
apps/xxx/yyy/bin/abc
apps/xxx/yyy/bin/abc/fdpro
...so on
I need to copy the abcBIN files dir to apps/xxx/yyy/bin/abc and so on. One to one mapping.
<project xmlns:ac="antlib:net.sf.antcontrib">
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="path-to-ant-contrib.jar"/>
</classpath>
</taskdef>
<loadfile property="file1" srcfile="File1.txt"/>
<loadfile property="file2" srcfile="File2.txt"/>
<ac:for param="i" list="${file1}">
<ac:for param="j" list="${file2}">
<sequential>
<echo>#{i}#{j}</echo>
<echo>copying....</echo>
<property name="src.dir" value="/home/name/svn_repo/dir" />
<property name="dest.dir" value="/home/name/mapp" />
<copy todir="${dest.dir}/#{j}">
<fileset dir="${src.dir}/#{i}">
</fileset>
</copy>
</sequential>
</ac:for>
</ac:for>
</project>
It is not working though.
I am getting an error:
ac:for doesn't support the nested "for" element
I can’t use UNIX shell or Perl. It has to be done in Ant.
Please let me know if you have any better idea about the nested loop in Ant.
#PulakAgrawal: I combined two text files into one using colon as a line separator and the magic began :)
e.g. src path:dest path
<loadfile property="allfiles" srcFile="mapping"/>
<ac:for list="${allfiles}" param="line" delimiter="${line.separator}">
<ac:sequential>
<ac:propertyregex property="from" input="#{line}" regexp="(.*):(.*)" select="\1" override="true"/>
<ac:propertyregex property="to" input="#{line}" regexp="(.*):(.*)" select="\2" override="true"/>
<echo>Copying dir ${from} to ${to} ...</echo>
<property name="src.dir" value="." /> <property name="dest.dir" value="." />
<copy todir="${dest.dir}/${to}"> <fileset dir="${src.dir}/${from}"> </fileset> </copy>
</ac:sequential>
</ac:for>

Ant - Run a Build.xml for all subdirectories

I have a build.xml sitting at the top level and I want the script to run a target for each subdirectory and pass in the subdirectory name as a parameter to the ANT target.
Can you help ?/??
Thanks
Take a look at the subant task. From that page:
<project name="subant" default="subant1">
<property name="build.dir" value="subant.build"/>
<target name="subant1">
<subant target="">
<property name="build.dir" value="subant1.build"/>
<property name="not.overloaded" value="not.overloaded"/>
<fileset dir="." includes="*/build.xml"/>
</subant>
</target>
</project>
this snippet build file will run ant in each subdirectory of the project directory, where a file called build.xml can be found. The property build.dir will have the value subant1.build in the ant projects called by subant.
this is might be what you looking for,
put this as one of your target in your parent build.xml
<target name="executeChildBuild">
<ant antfile="sub1/build.xml" target="build" />
<ant antfile="sub2/build.xml" target="build" />
</target>
If you would like to do it in ant build file, you could use Ant Contrib's for task to iterate over list of subdirectories and execute ant task for each of them.
<for param="subdir">
<dirset dir="${build.dir}">
<include name="./**"/>
</dirset>
<sequential>
<subant target="${target}">
<property name="subdir.name" value="#{subdir}"/>
</subant>
</sequential>
</for>
I didn't test this code since don't have ant installed, but it is close to what you're trying to do I suppose.
If I read the question correctly, this may be what you are looking for instead.
So for your example...
<target name="do-all">
<antcall target="do-first">
<param name="dir-name" value="first"/>
<param name="intented-target" value="init"/>
</antcall>
<antcall target="do-first">
<param name="dir-name" value="second"/>
<param name="intented-target" value="build"/>
</antcall>
<antcall target="do-first">
<param name="dir-name" value="third"/>
<param name="intented-target" value="compile"/>
</antcall>
</target>
<target name="do-first">
<echo>Hello from ${dir-name} ${intented-target}</echo>
<ant antfile="${dir-name}/build.xml" target="${intented-target}"/>
</target>
When you are calling this from Ant, you would enter this at the command line:
ant do-all
and your output should look like this:
do-all:
do-first:
[echo] Hello from first init
do-first:
[echo] Hello from second build
do-first:
[echo] Hello from third compile
BUILD SUCCESSFUL
Total time: 1 second
You will of course need to make sure that the directory name that you are using as a param actually exists, or the build will fail.
You can also always feed the variable that you want to use by adding the value to the build.properties file.

Replacing all tokens based on properties file with ANT

I'm pretty sure this is a simple question to answer and ive seen it asked before just no solid answers.
I have several properties files that are used for different environments, i.e xxxx-dev, xxxx-test, xxxx-live
The properties files contain something like:
server.name=dummy_server_name
server.ip=127.0.0.1
The template files im using look something like:
<...>
<server name="#server.name#" ip="#server.ip#"/>
</...>
The above is a really primitive example, but im wondering if there is a way to just tell ANT to replace all tokens based on the properties file, rather than having to hardcode a token line for each... i.e
<replacetokens>
<token key="server.name" value="${server.name}"/>
<token key="server.ip" value="${server.ip}"/>
</replacetokens>
Any help would be great!
You can specify the properties file from which to read the list of tokens for the 'replace' task using replacefilterfile:
<replace file="input.txt" replacefilterfile="properties.txt"/>
Similarly, in a filter chain, you can use 'replacetokens' propertyfile:
This will treat each properties file
entry in sample.properties as a
token/key pair:
<loadfile srcfile="${src.file}" property="${src.file.replaced}">
<filterchain>
<filterreader classname="org.apache.tools.ant.filters.ReplaceTokens">
<param type="propertiesfile" value="sample.properties"/>
</filterreader>
</filterchain>
</loadfile>
With the replace task by itself I missed the # delimiters around tokens so I came up with the following solution. You can use any ant property in the template file
<project name="replace" default="replace">
<property file="build.properties" />
<target name="replace">
<!-- create temp file with properties -->
<tempfile property="temp.replace" suffix=".properties"/>
<echoproperties destfile="${temp.replace}" />
<!-- replace name=value with #name#=value -->
<replaceregexp file="${temp.replace}" match="([^=]*)=" replace="#\1#=" byline="true" />
<!-- copy template and replace properties -->
<copy file="template.txt" tofile="replaced.txt" />
<replace file="replaced.txt" replacefilterfile="${temp.replace}" />
</target>
with a template
ANT home #ant.home#
ANT version #ant.java.version#
server name #server.name# ip #server.ip#
this results in
ANT home /usr/share/ant
ANT version 1.7
server name dummy_server_name ip 127.0.0.1
Using fileset form ant-contrib you can read the tokens form properties file and replace multiple tokens over multiple files.
<project name="MyProject" default="replaceToklens" basedir=".">
<property name="profilesProperties" value="${basedir}/environment.properties" />
<property name="build.dir" location="build"/>
<!-- File to Load/ Accessable -->
<property file="${profilesProperties}" />
<target name="replaceToklens">
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="${basedir}/ant-contrib-1.0b3.jar" />
</classpath>
</taskdef>
<mkdir dir="${build.dir}"/>
<filter filtersfile="${profilesProperties}" />
<copy todir="${build.dir}" filtering="true" overwrite="true">
<fileset dir="${basedir}"> <!-- target/MyProject -->
<include name="*.xml" />
<exclude name="build.xml" />
</fileset>
</copy>
</target>
</project>
folder structure:
ANT
\_ build.xml
\_ environment.properties
\_ server.xml
\_ build
\_ server.xml [replaced with token value]
In order to replace single toke use the following:
<replace file="build/server.xml" token="#keyName#" value="${keyValue}" />

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