Copy a single file to multiple directories in Ant - file

I would like to copy one file to multiple directories during a build process.
The value in ${prop.fmt} has two directories, I just want to copy a single WAR file to those two directories:
/apps/phxadmin-dev/devd/ui_tomcats/tomcat_c345tczuwdvd2/webapps
/apps/phxadmin-dev/devd/ui_tomcats/tomcat_c404gxduwdvd1/webapps
My Ant script:
<target name="test" >
<dirset id="dir.name" dir="${phx.tomcat.dir}" includes="*/webapps"/>
<property name="prop.dist.contents" refid="dir.name"/>
<loadresource property="prop.fmt">
<string value="${prop.dist.contents}"/>
<filterchain>
<tokenfilter>
<replaceregex pattern=";" replace="${line.separator}" flags="g"/>
</tokenfilter>
<prefixlines prefix="${phx.tomcat.dir}/" />
</filterchain>
</loadresource>
<echo message="${prop.fmt}"/>
<copy file="${phx.deploy.dir}/${war.file.name}" todir="${prop.fmt}"/>
</target>
Please can someone help me?

The <copy> task can copy to multiple destinations by:
setting the enableMultipleMappings attribute to true
and using a <scriptmapper>
In your example, the entire <target name="test"> block can be replaced with...
<target name="test">
<dirset id="dir.name" dir="${phx.tomcat.dir}" includes="*/webapps"/>
<copy todir="${phx.tomcat.dir}" enableMultipleMappings="true" verbose="true">
<fileset file="${phx.deploy.dir}/${war.file.name}"/>
<scriptmapper language="javascript">
<![CDATA[
var dirSet = project.getReference( "dir.name" );
var ds = dirSet.getDirectoryScanner( project );
var includes = ds.getIncludedDirectories( );
for ( var i = 0; i < includes.length; i++ )
{
self.addMappedName( includes[i] + "/" + source );
}
]]>
</scriptmapper>
</copy>
</target>
Running the above script results in output that looks somewhat like the following:
test:
[copy] Copying 1 file to /apps/phxadmin-dev/devd/ui_tomcats
[copy] Copying my.war to /apps/phxadmin-dev/devd/ui_tomcats/tomcat_c345tczuwdvd2/webapps/my.war
[copy] Copying my.war to /apps/phxadmin-dev/devd/ui_tomcats/tomcat_c404gxduwdvd1/webapps/my.war

Related

Copy file in Ant to dynamic directory name

I need to copy a file using ant from one folder to the other.
I know the exact name of the src file but for the destination file it's unknown since it's a version based folder I used the following script but it didn't work (please notice the * in the todir attribute:
<copy todir="${env.WORKSPACE}/my_dist_folder*" >
<fileset dir="${env.WORKSPACE}/my_src_folder">
<exclude name="**/*.svn"/>
</fileset>
</copy>
Please Advice!
Thanks
assuming there may be multiple my_dist_folder-xx.. folders:
<!-- goups all directories of the form "my_dist_folder-xx" -->
<dirset id="dir_list" dir="${env.WORKSPACE}">
<include name="my_dist_folder*"/>
</dirset>
<!-- generate path names of the above dirs and sort them -->
<pathconvert property="dir_names_list" refid="dir_list" pathsep=","/>
<sortlist property="sorted_names_list" value="${dir_names_list}" delimiter="," />
<!-- pick the last path-name (as it corresponds with the latest version-number directory ) -->
<propertyregex property="dist_folder" input="${sorted_names_list}" regexp=",?([^,]+)$" select="\1"/>
<!-- use this "dist_folder" as "todir" in the copy task -->
<copy todir="${dist_folder}" >
<fileset dir="${env.WORKSPACE}/my_src_folder">
<exclude name="**/*.svn"/>
</fileset>
</copy>
although, from your question, it appears that all such my_dist_folder-xx.. folders would be directly under the basedir ${env.WORKSPACE}... in case they may be under sub-directories within the basedir, then replace the line <include name="my_dist_folder*"/> with <include name="**/my_dist_folder*"/> in the <dirset> task.
UPDATE: also, if you're sure that there'll always be only one such folder my_dist_folder-xx.. on the system, then you may remove the following two lines- <sortlist> and <propertyregexp>, because the <dirset> will generate only one path-name and therefore you won't need to sort/pick-the-last-one. so you may use the <pathconvert> property to directly set the destination folder. eg:
<dirset id="dir_list" dir="${env.WORKSPACE}">
<include name="my_dist_folder*"/>
</dirset>
<!-- generate path name of the above dir -->
<pathconvert property="dir_names_list" refid="dir_list" pathsep=","/>
<!-- use this "dir_names_list" as "todir" in the copy task -->
<copy todir="${dir_names_list}" >
<fileset dir="${env.WORKSPACE}/my_src_folder">
<exclude name="**/*.svn"/>
</fileset>
</copy>

Use Ant to find file with latest version number

I want to use ant to find the file with the latest version number. For example, I have a file directory named tomcat with the following files:
apache-tomcat-6.0.37.zip
apache-tomcat-6.0.38.zip
apache-tomcat-6.0.39.zip
I want ant to determine that apache-tomcat-6.0.39.zip is the latest file. Is there a way to do this?
Thanks!
Use resource collections, see last and sort. f.e. :
<project>
<path id="foo">
<last>
<sort>
<fileset dir="C:/some/path" includes="**/apache-tomcat-*.zip"/>
</sort>
</last>
</path>
<echo>$${foo} => ${toString:foo}</echo>
</project>
output :
[echo] ${foo} => C:\some\path\apache-tomcat-6.0.39.zip
use <pathconvert>to get file names from the relevant <fileset>.
use <sortlist> to sort the filenames in natural String order.
pick the last filename from the list.
try this:
<fileset dir="${your.base.dir}" id="one">
<include name="**/apache-tomcat-.*.zip"/>
</fileset>
<pathconvert property="orig.list" refid="one" pathsep=","/>
<sortlist property="sorted.list" value="${orig.list}" delimiter="," />
<propertyregex property="result" input="${sorted.list}" regexp=",?([^,]+?)$" select="\1"/>
inputList: <property name="one" value="a.b-2,a.b-5,a.b-1,a.b-3,a.b-4"/>
outputList: [echo] a.b-5

Ant script -- split string and access via indexing

I need to write an Ant script which would load a properties file, read a single property out of it. The value (multiline) is something like:
path/to/file1a;path/to/file1b,
path/to/file2a;path/to/file2b,
..
..
I need to iterate over every line, and execute a shell command which looks like:
myCommand -param1 path/to/file1a -param2 path/to/file1b #Command inside a single iteration
I have able to figure out how to loop:
<for list="${ValueFromPropertyFile}" param="a">
<sequential>
<exec executable="myCommand">
<arg value="-param1" />
<arg value="---- split(#{a}, ";")[0] ----" />
<arg value="-param2" />
<arg value="---- split(#{a}, ";")[1] ----" />
</exec>
</sequential>
</for>
This is quite a simple task in my opinion. I tried searching, but without any success.
I would appreciate if someone could help me out with this, or point me to a relevant document.
Many thanks,
Pratik
Couple of problems with your assumptions:
The format of your input file is not a standard Java properties file, so it can't be loaded using the standard loadproperties task in ANT.
ANT is not a programming language. The "for" task you've quoted is not part of core ANT (Requires the 3rd party ant-contrib.jar)
So I'd suggest using an embedded script to solve your problem.
Example
The project is self documenting:
$ ant -p
Buildfile: /home/mark/tmp/build.xml
This is a demo project answering the following stackoverflow question:
http://stackoverflow.com/questions/14625896
First install 3rd party dependencies and generate the test files
ant bootstrap generate-test-files
Then run the build
ant
Expect the following output
parse-data-file:
[exec] build/myCommand -param1 path/to/file1a -param2 path/to/file1b
[exec] build/myCommand -param1 path/to/file2a -param2 path/to/file2b
build.xml
<project name="demo" default="parse-data-file">
<description>
This is a demo project answering the following stackoverflow question:
http://stackoverflow.com/questions/14625896
First install 3rd party dependencies and generate the test files
ant bootstrap generate-test-files
Then run the build
ant
Expect the following output
parse-data-file:
[exec] build/myCommand -param1 path/to/file1a -param2 path/to/file1b
[exec] build/myCommand -param1 path/to/file2a -param2 path/to/file2b
</description>
<target name="bootstrap" description="Install 3rd party dependencies">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/groovy-all.jar" src="http://search.maven.org/remotecontent?filepath=org/codehaus/groovy/groovy-all/2.1.0/groovy-all-2.1.0.jar"/>
</target>
<target name="generate-test-files" description="Generate the input data and sample script">
<echo file="build/input.txt">path/to/file1a;path/to/file1b,
path/to/file2a;path/to/file2b,</echo>
<echo file="build/myCommand"> #!/bin/bash
echo $0 $*</echo>
<chmod file="build/myCommand" perm="755"/>
</target>
<target name="parse-data-file" description="Parse data file">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<groovy>
new File("build/input.txt").eachLine { line ->
def fields = line.split(/[;,]/)
ant.exec(executable:"build/myCommand") {
arg(value:"-param1")
arg(value:fields[0])
arg(value:"-param2")
arg(value:fields[1])
}
}
</groovy>
</target>
<target name="clean" description="Cleanup build files">
<delete dir="build"/>
</target>
</project>

Ant: Find the path of a file in a directory

I want to find the path of a file in a directory (similar to unix 'find' command or the 'which' command, but I need it to work platform-independent) and save it as a property.
Tried to use the whichresource ant task, but it doesn't do the trick (I think it's only good for looking inside jar files).
I would prefer if it would be pure ant and not to write my own task or use a 3rd-party extension.
Notice that there might be several instances of a file by that name in the path - I want it to only return the first instance (or at least I want to be able to choose only one).
Any suggestions?
One possibility is to use the first resource selector. For example to find a file called a.jar somewhere under directory jars:
<first id="first">
<fileset dir="jars" includes="**/a.jar" />
</first>
<echo message="${toString:first}" />
If there are no matching files nothing will be echoed, otherwise you'll get the path to the first match.
Here is an example which selects the first matching file. The logic is as follows:
find all matches using a fileset.
using pathconvert, store the result in a property, separating each matching file with line separator.
use a head filter to match the first matching file.
The functionality is encapsulated in a macrodef for reusability.
<project default="test">
<target name="test">
<find dir="test" name="*" property="match.1"/>
<echo message="found: ${match.1}"/>
<find dir="test" name="*.html" property="match.2"/>
<echo message="found: ${match.2}"/>
</target>
<macrodef name="find">
<attribute name="dir"/>
<attribute name="name"/>
<attribute name="property"/>
<sequential>
<pathconvert property="#{property}.matches" pathsep="${line.separator}">
<fileset dir="#{dir}">
<include name="#{name}"/>
</fileset>
</pathconvert>
<loadresource property="#{property}">
<string value="${#{property}.matches}"/>
<filterchain>
<headfilter lines="1"/>
</filterchain>
</loadresource>
</sequential>
</macrodef>
</project>
I created a macro based on martin-clayton's answer.
sample project with macro and a property file that is read from the found file
<?xml version="1.0" encoding="utf-8"?>
<project name="test properties file read" default="info">
<macrodef name="searchfile">
<attribute name="file" />
<attribute name="path" default="custom,." />
<attribute name="name" />
<sequential>
<first id="#{name}">
<multirootfileset basedirs="#{path}" includes="#{file}" erroronmissingdir="false" />
</first>
<property name="#{name}" value="${toString:#{name}}" />
</sequential>
</macrodef>
<searchfile name="custom.properties.file" file="config.properties" />
<property file="${custom.properties.file}" />
<target name="info" >
<echo>
origin ${config.origin}
</echo>
</target>

Ant: How do I interate over all subfolders and perform a task in ant

Currently I do
<foreach list="${myfolders}" target="bundle"
param="worksheet" inheritall="true"/>
to execute the target "bundle" on a list of folders. However the problem is I need to set this list. How do I use Ant to just loop through all the folders given the parent directory?
If there is a way to do this and also exclude specific folders that would be even better. Thanks.
You can provide a <dirset> for the <foreach> task to operate on:
<foreach target="bundle" param="worksheet" inheritall="true">
<path>
<dirset dir="${subDir}">
<include name="*"/>
</dirset>
</path>
</foreach>
Notice that the list parameter isn't used when I do it this way.
You can't use <dirset> directly under the <foreach> as you can with <fileset>. However, you can put the <dirset> under the <path> as shown above. The <include name="*"/> prevents recursing down the directory tree.
You can do this with subant
Example:
<?xml version="1.0" encoding="UTF-8"?>
<project name="subant" default="subant1">
<target name="subant1">
<subant target="">
<dirset dir="." includes="*"/>
<target name="release" />
</subant>
</target>
</project>
I use the foreach task from ant-contrib for a similar job. This will call a specified target for each entry in a list, passing the entry as a parameter each time.

Resources