Ant - using variables in .properties files - ant

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).

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.

Expanding * in Ant copy task

In ant copy task, in destination location there is a "random number" folder in the path. When i try to put a * in the path to handle it, Ant takes it literally, ie doesnt expand it, but creates a folder called "*" and copies there. How do I tell Ant to expand the * to actual folder name there (there is only 1 folder in there, so * wont expand to multiple folders)
<property name="dest" value="a/*/b/my.jar" />
<property name="src" value="my.jar" />
<copy file="${src}" tofile="${dest}" overwrite="true" verbose="true"/>
The copy task doesn't support wildcards in the tofile attribute. If the destination directory exists, but the destination file may not, then you can use a dirset to capture the directory. Something like:
<dirset dir="${basedir}" id="dest.dir">
<include name="a/*/b" />
</dirset>
<property name="dest" value="${toString:dest.dir}/my.jar"/>
<property name="src" value="my.jar" />
<copy file="${src}" tofile="${dest}" overwrite="true" verbose="true"/>
Instead of using the property helper (${toString:....}) syntax you might use the pathconvert task:
<pathconvert property="destdir" refid="dest.dir"/>
<property name="dest" value="${destdir}/my.jar"/>

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 use filelist as fileset in uptodate Ant command?

I have a target of build.xml that creates a Zip file. To avoid creating the Zip if no file has been updated, I'd like to check for updates beforehand. AFAIK, uptodate is the task to use.
Here is the relevant (simplified) script sections:
<filelist id="zip-files">
<file name="C:/main.exe" />
<file name="D:/other.dll" />
</filelist>
<target name="zip" depends="zip-check" unless="zip-uptodate">
<zip destfile="${zip-file}" >
<filelist refid="zip-files" />
</zip>
</target>
<target name="zip-check">
<uptodate property="zip-uptodate"
targetfile="${zip-file}">
<srcfiles refid="zip-files" />
</uptodate>
</target>
However, uptodate fails because srcfiles must reference a fileset, not a filelist. Still, I can't use a fileset because it would require a dir attribute, which I can't set because source files do not share a base directory.
Of course, I could just copy all files to a common directory before zipping them, thus being able to use fileset, but I was wondering whether there was an alternative solution.
I'm using Ant 1.8.1
Instead of using <srcfiles>, try using <srcresources>. <srcfiles> must be a fileset, but <srcresource> can be a union of any collection of resources, and that should include a filelist.
I can't do any test right now, but it should look something like this:
<filelist id="zip-files">
<file name="C:/main.exe" />
<file name="D:/other.dll" />
</filelist>
<target name="zip" depends="zip-check" unless="zip-uptodate">
<zip destfile="${zip-file}" >
<filelist refid="zip-files" />
</zip>
</target>
<target name="zip-check">
<union id="zip-union">
<filelist refid="zip-files"/>
</union>
<uptodate property="zip-uptodate"
targetfile="${zip-file}">
<srcresources refid="zip-union" />
</uptodate>
</target>
Hope it works for you.

How do I "expand" an ant path (accessed with refId=..) to all files in the path except some?

I am trying to get ant4eclipse to work and I have used ant a bit, but not much above a simple scripting language. We have multiple source folders in our Eclipse projects so the example in the ant4eclipse documentation needs adapting:
Currently I have the following:
<target name="build">
<!-- resolve the eclipse output location -->
<getOutputpath property="classes.dir" workspace="${workspace}" projectName="${project.name}" />
<!-- init output location -->
<delete dir="${classes.dir}" />
<mkdir dir="${classes.dir}" />
<!-- resolve the eclipse source location -->
<getSourcepath pathId="source.path" project="." allowMultipleFolders='true'/>
<!-- read the eclipse classpath -->
<getEclipseClasspath pathId="build.classpath"
workspace="${workspace}" projectName="${project.name}" />
<!-- compile -->
<javac destdir="${classes.dir}" classpathref="build.classpath" verbose="false" encoding="iso-8859-1">
<src refid="source.path" />
</javac>
<!-- copy resources from src to bin -->
<copy todir="${classes.dir}" preservelastmodified="true">
<fileset refid="source.path">
<include name="**/*"/>
<!--
patternset refid="not.java.files"/>
-->
</fileset>
</copy>
</target>
The task runs successfully, but I cannot get the to work - it is supposed to copy all non-java files over too to emulate the behaviour of eclipse.
So, I have a pathId named source.path which contains multiple directories, which I somehow needs to massage into something the copy-task like. I have tried nesting which is not valid, and some other wild guesses.
How can I do this - thanks in advance.
You might consider using pathconvert to build a pattern that fileset includes can work with.
<pathconvert pathsep="/**/*," refid="source.path" property="my_fileset_pattern">
<filtermapper>
<replacestring from="${basedir}/" to="" />
</filtermapper>
</pathconvert>
That will populate ${my_fileset_pattern} with a string like:
1/**/*,2/**/*,3
if source.path consisted of the three directories 1, 2, and 3 under the basedir. We're using the pathsep to insert wildcards that will expand to the full set of files later.
The property can now be used to generate a fileset of all the files. Note that an extra trailing /**/* is needed to expand out the last directory in the set. Exclusion can be applied at this point.
<fileset dir="." id="my_fileset" includes="${my_fileset_pattern}/**/*">
<exclude name="**/*.java" />
</fileset>
The copy of all the non-java files then becomes:
<copy todir="${classes.dir}" preservelastmodified="true">
<fileset refid="my_fileset" />
</copy>
That will copy the source files over retaining the source directory structure under todir. If needed, the flatten attribute of the copy task can be set to instead make all the source files copy directly to todir.
Note that the pathconvert example here is for a unix fileseystem, rather than windows. If something portable is needed, then the file.separator property should be used to build up the pattern:
<property name="wildcard" value="${file.separator}**${file.separator}*" />
<pathconvert pathsep="${wildcard}," refid="source.path" property="my_fileset">
...
You could use the foreach task from the ant-contrib library:
<target name="build">
...
<!-- copy resources from src to bin -->
<foreach target="copy.resources" param="resource.dir">
<path refid="source.path"/>
</foreach>
</target>
<target name="copy.resources">
<copy todir="${classes.dir}" preservelastmodified="true">
<fileset dir="${resource.dir}" exclude="**/*.java">
</copy>
</target>
If your source.path contains file paths as well then you could the if task (also from ant-contrib) to prevent attempting to copy files for a file path, e.g.
<target name="copy.resources">
<if>
<available file="${classes.dir}" type="dir"/>
<then>
<copy todir="${classes.dir}" preservelastmodified="true">
<fileset dir="${resource.dir}" exclude="**/*.java">
</copy>
</then>
</if>
</target>

Resources