ant.concat task translation to Gradle / Groovy - ant

<concat destfile="${database_dir}/xxxx-create-constraints.sql">
<filelist dir="${database_dir}" files="XXXX-hsqldb-nodrop.sql" />
<filterchain>
<striplinebreaks />
<replacestring from=";" to=";
" />
<linecontains>
<contains value="add constraint" />
</linecontains>
</filterchain>
</concat>
<concat destfile="${database_dir}/XXXXX-drop-constraints.sql">
<filelist dir="${database_dir}" files="xxxx-hsqldb.sql" />
<filterchain>
<striplinebreaks />
<replacestring from=";" to=";
" />
<linecontains>
<contains value="drop constraint" />
</linecontains>
</filterchain>
</concat>
I am trying to translate this into Gradle, it is part of a larger task the majority of which I have already translated, I am having trouble with the following section.
<filterchain>
<striplinebreaks />
<replacestring from=";" to=";
" />
<linecontains>
<contains value="drop constraint" />
</linecontains>
</filterchain>
I can't find any examples or documentation on how this might look in Groovy.
Thus far I have just:
ant.concat(destFile:"${database_dir}/XXXX-create-constraints.sql"){
files("XXXX-hsqldb-nodrop.sql")
filelist(dir:"${database_dir}")
}
Any help or insight would be appreciated.
EDIT
I've nutted out a version though I'm not sure about correctness, just because its not throwing errors or breaking doesn't mean its right.
ant.concat(destFile:"${database_dir}/XXXX-create-constraints.sql"){
files("XXXX-hsqldb-nodrop.sql")
filelist(dir:"${database_dir}")
filterchain{
striplinebreaks()
replacestring(from:';', to:';
')
linecontains{
'add constraint'
}
}
}

Related

Ant substring by position

I need to extract a substring from property value by length, f.e. :
<property name="prop1" value="nameBLABLABLA" />
I want get the value
name
Is it possible without using javascript code ?
Not with vanilla ant, you would need to add some Ant addon like Antcontrib (latest release 2006 !) or Ant Flaka - means you'll need additional jars/libraries.
With using the jdk builtin Javascript engine it's as easy as :
<project>
<!-- create a macrodef for reuse -->
<macrodef name="getsubstring">
<attribute name="src"/>
<attribute name="from"/>
<attribute name="to"/>
<attribute name="result"/>
<sequential>
<script language="javascript">
project.setProperty(
"#{result}", "#{src}".substring(#{from},#{to})
);
</script>
</sequential>
</macrodef>
<property name="foo" value="nameBLABLABLA"/>
<getsubstring src="${foo}" from="0" to="4" result="foobar"/>
<echo> $${foobar} => ${foobar}</echo>
</project>
No additional libraries needed.
Created a macrodef that works for properties respectively for strings in general.
The JavaScript engine understands Javascript and Java and you'll get full access to Ant api.
I'd use JavaScript as in Rebse's answer, but there is a way to do this without it using <loadresource> and a <tokenfilter>. This uses start/length rather than from/to for the substring:
<macrodef name="getsubstring">
<attribute name="src"/>
<attribute name="start"/>
<attribute name="length"/>
<attribute name="result"/>
<sequential>
<loadresource property="#{result}">
<string value="#{src}}" />
<filterchain>
<tokenfilter>
<replaceregex pattern="^.{#{start}}(.{#{length}}).*" replace="\1" />
</tokenfilter>
</filterchain>
</loadresource>
</sequential>
</macrodef>
<property name="prop1" value="nameBLABLABLA" />
<getsubstring src="${prop1}" start="0" length="4" result="p"/>
<echo message="${p}" />

How do I use a patternset to filter a list of files?

This seems like something that should be obvious, but I don't think it is. Given:
a space-delimited list of files (or comma-delimited, etc.)
a <patternset> of whitelisted patterns
How do I come up with a <fileset> that contains all of the files in the list that match the whitelisted pattern?
Getting a list of files from the list is easy enough:
<patternset id="the-patternset" includes="${list.of.files}" />
<fileset id="the-fileset" dir="${basedir}">
<patternset refid="the-patternset" />
</fileset>
<pathconvert pathsep="${line.separator}" property="the-filelist" refid="the-fileset"/>
<echo>fileset: ${the-filelist}</echo>
…will happily produce a fileset with all of the files in ${list.of.files}. But adding a filter of sorts:
<patternset id="the-filter">
<include name="includeme/**/*.java" />
<exclude name="excludeme/**/*.java" />
</patternset>
<patternset id="the-patternset" includes="${list.of.files}" />
<fileset id="the-fileset" dir="${basedir}">
<patternset refid="the-patternset" />
<patternset refid="the-filter" />
</fileset>
<pathconvert pathsep="${line.separator}" property="the-filelist" refid="the-fileset"/>
<echo>fileset: ${the-filelist}</echo>
…will list a union of the patternsets—i.e., all files that match either the-filter or the-patternset.
How do I produce a fileset containing files that are in ${list.of.files} and match the-patternset?
Here's a potted example. Create two filesets (or perhaps filelists) one from each of your patternsets. I'll just use fixed lists here:
<property name="list.1" value="a,b,c" />
<property name="list.2" value="b,c,d" />
<fileset dir="." id="set.1" includes="${list.1}" />
<fileset dir="." id="set.2" includes="${list.2}" />
Then use the <intersect> resource collection to get the required 'overlap' set:
<intersect id="intersect">
<resources refid="set.1"/>
<resources refid="set.2"/>
</intersect>
Most Ant tasks will allow you to use a resource collection in place of a simple fileset.

Create a Union and Macrodef-style element with dynamic content at runtime in Ant

I've a build script built in Ant which has a macrodef that takes a few default parameters, target, root and the like, and then an optional two, extrasrc-f and extrasrc-c. After they've come in, I like to do a uptodate check on all relevant resources, then only do a build if the target is out of date.
What I have at the moment,
<?xml version="1.0" encoding="UTF-8"?>
<project name="Custom build" default="default">
<taskdef resource="net/sf/antcontrib/antlib.xml"
classpath="C:/dev/ant/ant-contrib/ant-contrib-1.0b3.jar"/>
<macrodef name="checkuptodate">
<attribute name="target" />
<element name="resource" />
<sequential>
<condition property="needbuild">
<and>
<resourcecount when="greater" count="0"> <resource /> </resourcecount>
<not>
<uptodate targetfile="#{target}">
<srcresources> <resource /> </srcresources>
</uptodate>
</not>
</and>
</condition>
</sequential>
</macrodef>
<macrodef name="projbuild">
<attribute name="root" />
<attribute name="target" />
<element name="extrasrc-f" optional="true" />
<element name="extrasrc-c" optional="true" />
<sequential>
<local name="needbuild" />
<checkuptodate target="#{root}/bin/#{target}">
<resource>
<union>
<extrasrc-f />
<fileset dir="#{root}/src" includes="**/*.java" />
</union>
</resource>
</checkuptodate>
<if>
<istrue value="${needbuild}" />
<then>
<javac
srcdir="#{root}/src"
destdir="#{root}/bin"
includeantruntime="false"
>
<extrasrc-c />
</javac>
</then>
</if>
</sequential>
</macrodef>
<target name="default">
<projbuild root="." target="EntryPoint.class">
<extrasrc-f>
<fileset dir="Proj2/src" includes="**/*.java" />
<fileset dir="Proj3/src" includes="**/*.java" />
</extrasrc-f>
<extrasrc-c>
<classpath location="Proj2/src" />
<classpath location="Proj3/src" />
</extrasrc-c>
</projbuild>
</target>
</project>
But as you can see, at this point in time, for me it's inefficient, to do what I want, I've to create and pass in at least one fileset, and multiple classpaths. What I'd really like to do is just pass in a list of directories, then create the extrasrc-f and extrasrc-c elements on the fly from that information, but for the life of me, I've no idea how I'm able to do that.
I've read up plenty about many of Ant and Ant-Contrib funky classes, but I haven't read anything that would allow me to do something like this, which I do find odd, because to me it looks an obvious situation.
Am I approaching this in a very wrong way, or is there something I'm missing? If I'm really misusing Ant, I'd love pointers in the right direction about how to do this properly, create a catchall, template build in a macrodef (or target, if that's the only way to do it) which tests multiple source files against one file that gets built, while also passing in extra class or library paths too, preferably in one single list.
Perhaps you can use a couple of <scriptdef> tasks to help break up those macros.
First, one that takes a comma-separated list of directories and generates the <union> from them. You supply the refid you want to use to refer to the union as the id attribute. There are optional includes and excludes.
<scriptdef name="dirs2union" language="javascript">
<attribute name="dirs" />
<attribute name="id" />
<attribute name="includes" />
<attribute name="excludes" />
<![CDATA[
var dirs = attributes.get( "dirs" ).split( "," );
var includes = attributes.get( "includes" );
var excludes = attributes.get( "excludes" );
var union = project.createDataType( "union" );
project.addReference( attributes.get( "id" ), union );
for ( var i = 0; i < dirs.length; i++ ) {
var fs = project.createDataType( "fileset" );
fs.setDir( new java.io.File( dirs[i] ) );
if ( includes )
fs.setIncludes( includes );
if ( excludes )
fs.setExcludes( excludes );
union.add( fs );
}
]]>
</scriptdef>
The second - very similar - script does the equivalent for path generation:
<scriptdef name="dirs2path" language="javascript">
<attribute name="dirs" />
<attribute name="id" />
<![CDATA[
var dirs = attributes.get( "dirs" ).split( "," );
var path = project.createDataType( "path" );
project.addReference( attributes.get( "id" ), path );
for ( var i = 0; i < dirs.length; i++ ) {
var pe = project.createDataType( "path" );
pe.setLocation( new java.io.File( dirs[i] ) );
path.add( pe );
}
]]>
</scriptdef>
An example use might then be something like:
<property name="dirs" value="Proj2/src,Proj3/src" />
<dirs2union dirs="${dirs}" id="my.union" includes="**/*.java" />
<dirs2path dirs="${dirs}" id="my.path" />
... later (e.g.) ...
<union refid="my.union" />
<classpath refid="my.path" />
You could then modify your macros to either take the dirs attribute and generate the union and classpath internally, or perhaps generate these once elsewhere and just pass in the references.
I've not attempted to include the #{root} directories in this illustration, but it should be possible to adapt the above for that.

Ant: Convert class name to file path

How do I convert Java class names into file paths using Ant tasks?
For example, given a property containing foo.bar.Duck I'd like to get out foo/bar/Duck.class.
I tried (and failed) to implement this in terms of <pathconvert> and <regexpmapper>.
Here's a possible way to do this:
<property name="class.name" value="foo.bar.Duck"/>
<loadresource property="file.name">
<string value="${class.name}" />
<filterchain>
<replaceregex pattern="\." replace="/" flags="g" />
<replaceregex pattern="$" replace=".class" />
</filterchain>
</loadresource>
This puts the desired foo/bar/Duck.class into the file.name property.
Here's another way, using Ant resources and an unpackagemapper, which is designed for this purpose. The opposite package mapper is also available.
<property name="class.name" value="foo.bar.Duck"/>
<resources id="file.name">
<mappedresources>
<string value="${class.name}" />
<unpackagemapper from="*" to="*.class" />
</mappedresources>
</resources>
You use the resource value by means of the property helper syntax ${toString:...}, e.g.:
<echo message="File: ${toString:file.name}" />
Yields
[echo] File: foo/bar/Duck.class
I feel using ant script-javascript for this is much simpler
<property name="class.name" value="foo.bar.duck" />
<script language="javascript">
var className = project.getProperty("class.name");
println("before: " + className);
var filePath= className.replace("\\", "/");
println("File Path: "+filePath);
project.setProperty("filePath", filePath);
</script>
<echo message="${filePath}" />
note: that naming your variable same as argument e.g var wsPath may give error, it gave to me!
courtesy: https://stackoverflow.com/a/16099717/4979331

Ant: how to write optional nested elements

Say that I need to do something like:
<copy todir="${DEPLOYMENT_DIR}" overwrite="true">
<fileset dir="dir1" />
<fileset dir="dir2" />
<fileset dir="dir3" />
...
<if>
<equals arg1="${SPECIAL_BUILD}" arg2="true"/>
<then>
<fileset dir="dir7" />
<fileset dir="dir8" />
...
</then>
</if>
</copy>
(The real task is not copy, I'm just using it to illustrate the point.)
Ant will complain that my task doesn't support nested <if> which is fair enough. I've been thinking along these lines:
I could add a macrodef with an "element" attribute like this:
<macrodef name="myCopy">
<element name="additional-path" />
<sequential>
<copy todir="${DEPLOYMENT_DIR}" overwrite="true">
<fileset dir="dir1" />
<fileset dir="dir2" />
<fileset dir="dir3" />
...
<additional-path/>
</copy>
</sequential>
</macrodef>
But that would mean that the caller (target) must specify the additional path which I want to avoid (if many targets call this task, they would have to repeat the fileset definitions in the additional-path element).
How to code the additional filesets inside the macrodef so that Ant doesn't complain?
AntContrib has an Ant FileSet object augmented with if and unless conditions.
http://ant-contrib.sourceforge.net/fileset.html
if Sets the property name for the 'if' condition. The fileset will be
ignored unless the property is
defined. The value of the property is
insignificant, but values that would
imply misinterpretation ("false",
"no") will throw an exception when
evaluated.
unless Set the property name for the 'unless' condition. If named
property is set, the fileset will be
ignored. The value of the property is
insignificant, but values that would
imply misinterpretation ("false",
"no") of the behavior will throw an
exception when evaluated.
You could use it like this:
<copy todir="${DEPLOYMENT_DIR}" overwrite="true">
<fileset dir="dir1" />
<fileset dir="dir2" />
<fileset dir="dir3" />
...
<fileset dir="dir7" if="SPECIAL_BUILD" />
<fileset dir="dir8" if="SPECIAL_BUILD" />
</copy>
One way (not sure if a good one) to achieve that is to create two macrodefs - one "public" for general use and one "internal" that does the real work and is intended to be called only from the "public" macro. Like this:
<macrodef name="task-for-public-use">
<sequential>
<if>
<equal arg1="${SPECIAL_BUILD}" arg2="true" />
<then>
<internal-task>
<additional-path>
...
</additional-path>
</internal-task>
</then>
<else>
<internal-task ... />
</else>
</if>
</sequential>
</macrodef>
<macrodef name="internal-task">
<element name="additional-path" />
<sequential>
<copy ...>
...
<additional-path/>
</copy>
</sequential>
</macrodef>
I don't like it much though and hope there's a better way.

Resources