ANT replacing strings in specified files using file with properties - ant

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.

Related

Replaceregexp with property value depending on the matched group

I'd like to replace some replace marks in css files with values out of a property file. What i did so far is:
<target depends="prepare" name="build_css">
<replaceregexp>
<fileset refid="temp_css_files"/>
<regexp pattern="\{(.*)\}"/>
<substitution expression="${testprop}"/>
</replaceregexp>
</target>
which will successfully replace the matched string with the value of the testprop property.But what i like to do is, to replace the matched string by a property whose name is the matched string.
So a replacement mark {myprop} will be replaced by the value of the property myprop.
I tried:
<target depends="prepare" name="build_css">
<replaceregexp>
<fileset refid="temp_css_files"/>
<regexp pattern="\{(.*)\}"/>
<substitution expression="${\1}"/>
</replaceregexp>
</target>
with no success since the matched string is then replaced by the String ${myprop}.
Is it possible to to this? Or is there an easier way with another task that i'm missing?
If you can use the typical Ant ${...} syntax to represent properties in your CSS files, then Ant's <expandproperties> FilterReader may be useful:
<project name="ant-replace-tokens-with-copy-task" default="run">
<target name="run">
<property name="src-root" location="src"/>
<fileset id="temp_css_files" dir="${src-root}">
<include name="**/*.css"/>
</fileset>
<!-- 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="filtered-file.extension" value="*.filtered-file"/>
<copy todir="${src-root}">
<fileset refid="temp_css_files"/>
<globmapper from="*" to="${filtered-file.extension}"/>
<filterchain>
<expandproperties/>
</filterchain>
</copy>
<move todir="${src-root}">
<fileset dir="${src-root}" includes="**"/>
<globmapper from="${filtered-file.extension}" to="*"/>
</move>
</target>
</project>
If you need to stick with the {...} syntax, the ReplaceTokens FilterReader replaces tokens with properties defined in a properties file:
<project name="ant-replace-tokens-with-copy-task" default="run">
<target name="run">
<property name="src-root" location="src"/>
<fileset id="temp_css_files" dir="${src-root}">
<include name="**/*.css"/>
</fileset>
<!-- 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="filtered-file.extension" value="*.filtered-file"/>
<copy todir="${src-root}">
<fileset refid="temp_css_files"/>
<globmapper from="*" to="${filtered-file.extension}"/>
<filterchain>
<filterreader classname="org.apache.tools.ant.filters.ReplaceTokens">
<param type="tokenchar" name="begintoken" value="{"/>
<param type="tokenchar" name="endtoken" value="}"/>
<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>

How to preserve file order in Ant concat?

How to preserve file order in Ant concat?
Simple concat with fileset & includesfile produces rather "random" order, as order is not guaranteed:
<concat destfile="C:/targetdir/concatenated.file">
<fileset dir="C:/sourcedir/">
<includesfile name="C:/targetdir/includes.file" />
</fileset>
</concat>
What I need is concatenation in specific order that the files are listed in the includes file.
So far I've found resourcelist, which should preserve order, but I can't seem to be able to produce any concatenated file with it. :/
<concat destfile="C:/targetdir/concatenated.file">
<resourcelist>
<file file="C:/targetdir/includes.file"/>
<filterchain>
<striplinecomments>
<comment value="#"/>
</striplinecomments>
<prefixlines prefix="C:/sourcedir/"/>
</filterchain>
</resourcelist>
</concat>
Plus, the resourcelist can't seem to handle rows like
LibraryX/A/Stuff/Morestuff/*
Instead the row just produces a ".../Morestuff/* does not exist." -error
Includes file has list of relative paths:
LibraryX/A/Stuff/FileA.txt
LibraryX/A/Stuff/FileB.txt
LibraryX/A/Stuff/FileC.txt
LibraryX/A/Stuff/FileY.txt
I was able to get a filelist working pretty easily:
<concat destfile="C:/targetdir/concatenated.file">
<filelist dir="C:/sourcedir/">
<file name="i.txt" />
<file name="n.txt" />
<file name="o.txt" />
<file name="r.txt" />
<file name="d.txt" />
<file name="e.txt" />
<file name="r.txt" />
</filelist>
</concat>
Hope that helps!
If you are using Ant 1.7+, you can use the sort command
<concat destfile="C:/targetdir/concatenated.file">
<sort>
<fileset dir="C:/sourcedir/">
<include name="C:/targetdir/*.file" />
</fileset>
</sort>
</concat>
You can find the documentation of sort here
[On Ant 1.8.2+] You can also pass the fileset via a sort, and sort on filename, like below:
<concat destfile="./${dir.publish}/${dir.js}/b.main-${build.number}.debug.js">
<sort xmlns:rcmp="antlib:org.apache.tools.ant.types.resources.comparators">
<fileset dir="./${dir.publish}/">
<include name="**/${dir.js.main}/**/*.js"/>
<exclude name="**/${dir.js.main}/**/*.min.js"/>
</fileset>
<rcmp:name />
</sort>
</concat>
Couple of things to watch out for:
Directories are sorted before files
Capitals come before lowercase
UPDATE: Another alternative if you need to manually specify order:
<!-- create a ordered list of all the build files so that CIAPI & CIAPI.widget are built first
(can't find a smarter way to do this, since ant filesets are unordered) -->
<fileset id="a" dir="."><include name="CIAPI/build.project.xml"/></fileset>
<fileset id="b" dir="."><include name="CIAPI.widget/build.project.xml"/></fileset>
<fileset id="c" dir=".">
<include name="**/build.project.xml"/>
<exclude name="CIAPI/build.project.xml" />
<exclude name="CIAPI.widget/build.project.xml" />
</fileset>
<union id="all_build_files">
<fileset refid="a"/>
<fileset refid="b"/>
<fileset refid="c"/>
</union>
Ugly, but, erm, this is ant?
try this, put in alphabetical order
<project name="concatPath" default="full">
<target name="full">
<fileset id="fs" dir="./files" />
<pathconvert refid="fs" property="concatList" pathsep=";" targetos="unix"/>
<echo>${concatList}</echo>
</target>
</project>
this can be used with hierarchical structure of directories, and the order will be the exposed by David.
Remember that XML is not order-dependent, by definition.
To concatenate files in a sorted order, consider using <replace> instead.
Create an order file that defines the order. Then, in your build file:
Copy the order file to the destination file with <copy>
Concatenate your files together into a temporary file with <concat>
Load the files into properties with <loadfile>
Insert the text from those files into the destination file with <replace>
Example order file order_file.txt:
FILE_A_HERE
CONCAT_FILES_HERE
Example ant build file build.xml:
<copy file="order_file.txt" tofile="destination.txt" overwrite="yes">
<concat destfile="tempfile.txt">
<fileset dir="includes/">
<include name="*.txt">
<exclude name="fileA.txt">
</fileset>
</concat>
<loadfile property="fileA" srcFile="includes/fileA.txt" />
<loadfile property="concatFile" srcFile="tempfile.txt" />
<replace file="destination.txt" token="FILE_A_HERE" value="fileA" />
<replace file="destination.txt" token="CONCAT_FILES_HERE" value="concatFile" />

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}" />

How to access filters in web.xml file set by a .properties file

I am using WAS6.1 as the server(but I guess this should not matter).I have a filters.properties file. It has key value pair (e.g. config.file.name=/usr/home/config.xml). These values are being used in web.xml as shown below:
<context-param>
<param-name>config.file</param-name>
<param-value>#config.file.name#</param-value>
</context-param>
So I have defined a build.xml which uses filterset task from ant to define all those filters but when I try to access the home page it says that not able to find location #config.file.name#. Obviously, these filters are not being loaded properly. Here is my build.xml code which defines the filters during the compilation. What do you think I am missing?
<target name="compile">
<property name="compile.target" location="${project.build.dir}/WEB-INF/classes" />
<property name="project.build.dir.lib" location="${project.build.dir}/WEB-INF/lib" />
<mkdir dir="${compile.target}" />
<mkdir dir="${project.build.dir.lib}" />
<!-- copy the web content into the build location -->
<copy todir="${project.build.dir}">
<fileset dir="${web.project.webcontent.dir}" excludes="**/classes/**" />
**<filterset>
<filtersfile file="${web.project.src.dir}/filters/${file.filter.name}" />
</filterset>**
</copy>
<!-- compile the java source and put it in the classes directory -->
<javac classpathref="classpath" srcdir="${web.project.src.dir}" destdir="${compile.target}" debug="${javac.debug}" deprecation="${javac.deprecation}" fork="${javac.fork}" memoryMaximumSize="${javac.memoryMaximumSize}" nowarn="${javac.nowarn}" failonerror="${javac.failonerror}">
</javac>
<!-- copy all the non-java resources (properties, etc) into the classes directory-->
<copy todir="${compile.target}">
<fileset dir="${web.project.src.dir}">
<exclude name="**/*.java" />
<exclude name="filters/**" />
</fileset>
</copy>
<!-- Create a jar file from the ${compile.target} folder -->
<jar jarfile="${project.build.dir.lib}/${ant.jar.file}.jar" excludes="filters/**" basedir="${compile.target}" />
</target>
Your feedback is highly appreciated.
Thanks for looking at my post. It is working fine. The main issue was that the path to the properties file was not correct.

Ant - using variables in .properties files

I am trying to replace placeholders in source files with values defined in a .properties file using the copy task with **
My build.xml contains
<target name="configure">
<echo message="Creating DB configuration" />
<copy todir="${dir.out}" overwrite="true">
<fileset dir="${dir.in}" />
<filterchain>
<expandproperties/>
<replacetokens begintoken="<" endtoken=">" propertiesResource="conf.properties" />
</filterchain>
</copy>
</target>
A sample from the conf.properties:
tbs.base_directory = d:/oracle/oradata/my_app
tbs.data_file = ${tbs.base_directory}/data01.dbf
I want to refer from within the .properties file to variables, in this case I would like to substitute tbs.base_directory in tbs.data_file.
Unfortunately it is not substituted. Any ideas?
Thanks
Problem is that expandproperties applies to copied file not to the property resource you are using to define your tokens. A possible solution is to first load conf.properties to force properties expansion and dump it into a temporary file that is used for token substitution. Something like the following should work:
<target name="configure">
<echo message="Creating DB configuration" />
<!-- force expanding properties in tokens property file -->
<loadproperties srcfile="conf.properties" />
<!-- dump expanded properties in a temp file -->
<echoproperties prefix="tbs" destfile="conf.expanded.properties"/>
<copy todir="${dst.out}" overwrite="true">
<fileset dir="${dir.in}" />
<filterchain>
<expandproperties/>
<!-- use temporary file for token substitution -->
<replacetokens begintoken="<" endtoken=">" propertiesResource="conf.expanded.properties" />
</filterchain>
</copy>
<!-- delete temp file (optinal)-->
<delete file="conf.expanded.properties"/>
</target>
Drawback of this solution is that it only works as long as you can select the properties to write in the temporary file (i.e all properties in the conf.properties file starts with the same prefix).

Resources