Turning an ant propertyset into a fileset - ant

I have a propertyset, where the values of the properties in the set specify a list of files I want to include in a jar. But I can't seem to figure out how to build a jar from a propertyset, only a fileset. How can I convert the values of a propertyset into an ant fileset?

I did some work and found an approach that works. I build a comma-separated list of the property values, then pass that as the include attribute of a fileset.
<target name="buildjarfromprops">
<!-- read list of files to include from properties -->
<property file="files.properties"/>
<!-- select the properties to include -->
<propertyset id="includeFiles">
<propertyref prefix="files."/>
</propertyset>
<!-- build a comma-separated list of files to include -->
<pathconvert refid="includeFiles" pathsep="," property="includeFiles"/>
<!-- now jar them all up -->
<property name="sourcedir" value="/dir"/>
<jar destfile="destjar.jar" basedir="${sourcedir}" includes="${includeFiles}"/>
</target>

Related

Ant: If property contains certain string, change the name of the property

I am trying to check a folder's name, and if it contains a certain string, I want that folder path to be changed.
So far I came up with this:
<property name="component.release.dir" value="${install.dir}/${component.name}" />
<!-- Check if the component is a part of projectL -->
<condition property="projectLFolderSpotted">
<matches pattern="projectL" string="${component.release.dir}"/>
<!-- if so, put the component in an appropriate folder -->
<property name="component.release.dir" value="${install.dir}/projectL/${component.name}" />
<echo message="projectL component has been detected, and moved accordingly!"/>
</condition>
But I get the following error:
condition doesn't support the nested "property" element.
Is there a way to achieve this?
Thanks in advance.
Properties in ANT are immutable, once they're assigned a value it doesn't change.
Here's how I'd suggest you do it:
<project name="demo" default="build">
<property name="release.dir.seed" location="build/helloworld"/>
<condition property="release.dir" value="build/found/helloworld" else="build/notfound/helloworld">
<contains string="${release.dir.seed}" substring="helloworld"/>
</condition>
<target name="build">
<echo message="Result: ${release.dir}"/>
</target>
</project>

Phing alternative for fixlastline from ant

I'm rewriting build.xml file from Ant to Phing and everything goes fine with one exception.
I need to add new line at the end of each appended file but I can't find any alternative for fixlastline="true".
In Ant it was
<concat destfile="${libraryFilePrefix}.js" fixlastline="yes">
<!-- many filesets -->
</concat>
In Phing it's like
<append destfile="${libraryFilePrefix}.js">
<!-- many filesets -->
</append>
Is there any attribute that works like fixlastline or maybe I need to find another way to achieve this?
I believe, one of the approaches (and possibly the only one) is applying replaceregexp filter on each fileset. You only need to apply filterchain at the beginning and it will do the job for each fileset, like this:
<append destfile="${libraryFilePrefix}.js">
<filterchain>
<replaceregexp>
<regexp pattern="([^\n])$" replace="$1${line.separator}" ignoreCase="true"/>
</replaceregexp>
</filterchain>
<!-- many filesets -->
</append>
As of Phing 3.x the AppendTask is aware of the fixlastline attribute. Your Ant script provided is now working as expected
<project name="concat-supports-fixlastline" default="concat-fixed-lastline" basedir=".">
<target name="concat-fixed-lastline">
<concat destfile="${libraryFilePrefix}.js" fixlastline="yes">
<!-- many filesets -->
</concat>
</target>
</project>

How to to pass configurable file mapping lists to ant macros?

I'm trying to refactor an Ant buildfile with many similar targets into a buildfile that uses macros. This roughly is what it looks like:
<macrodef name="build-text">
<argument name="lang" />
<element name="file-list"/>
<sequential>
<property name="lang" value="#{lang}" />
<xslt style="my_stylesheet.xsl" destdir="build" basedir="src">
<!-- lots of params here -->
<file-list />
</xslt>
</sequential>
</macrodef>
<target name="buildTextDE">
<build-text lang="DE">
<file-list>
<mapper>
<mapper type="glob" from="Text1_${lang}.html" to="Text1_${lang}.fo"/>
<mapper type="glob" from="Text2_${lang}.html" to="Text2_${lang}.fo"/>
</mapper>
</file-list>
</build-text>
</target>
There is another task called buildTextEN that is nearly identical except for the lang attribute. In some cases, the file list differs however. Now how would I like to simplify the buildfile further by defining a "global" mapping list that contains the file lists for German and English, each file with the placeholder for the language. I would like to reference this global mapping where no special case is needed. How would I do that?

Ant Fileset to Comma Separated List

I'm trying to pass a fileset to a macrodef, and have the macro generate a comma separated list of the classes. More over, I also need to change the list to contain java package & class names instead of "/" delimmited names.
We're using Ant, OSGi, and bnd and what I'm ultimately trying to do is create an entry in the Manifest that contains the fully qualified class name of each entry of the fileset.
End Goal example:
Manifest-Entry: org.foo.bar.ClassOne, org.foo.bar.ClassTo
You could do this using the Ant pathconvert task with a nested mapper, for example:
<property name="classes" location="classes" />
<fileset dir="${classes}" id="classes" />
<pathconvert dirsep="." refid="classes" property="manifest.entry" pathsep=", ">
<mapper type="regexp" from="${classes}/(.*).class" to="\1" />
</pathconvert>
<echo message="Manifest-Entry: ${manifest.entry}" />
Since you are using bnd, you could also try using the ${classes} macro in the bnd file.

Ant manifestclasspath: property already set

I want to use manifestclasspath Ant task. I have a very large build.xml file with a couple of imported other build files and when I run it I get this:
build.xml:1289: The following error occurred while executing this line:
build.xml:165: Property 'some.property' already set!
I am sure that this property is defined only in manifestclasspath task. Here is my code:
<manifestclasspath property="some.property" jarfile="some.jar">
<classpath refid="some.classpath"/>
</manifestclasspath>
This code is located inside of <project>.
What am I doing wrong? Is there a way to add something like condition to set property only if it is not already set? I don't want to use custom Ant tasks such as Ant Contrib's if if there is other way around.
Antcall opens a new project scope, but by default, all of the properties of the current project will be available in the new project. Also if you used something like =
<antcall target="whatever">
<param name="some.property" value="somevalue"/>
</antcall>
in the calling project then ${some.property} is also already set and won't be overwritten, as properties once set are immutable in ant by design.
Alternatively, you may set the inheritAll attribute to false and only "user" properties (those passed on the command-line with -Dproperty=value) will be passed to the new project.
So, when ${some.property} ain't no user property, then use inheritAll="false" and you're done.
btw. it's better to use a dependency between targets via depends="..." attribute than to use antcall, because it opens a new project scope and properties set in the new project won't get back to the calling target because it lives in another project scope..
Following a snippet, note the difference, first without inheritAll attribute
<project default="foo">
<target name="foo">
<property name="name" value="value1" />
<antcall target="bar"/>
</target>
<target name="bar">
<property name="name" value="value2" />
<echo>$${name} = ${name}</echo>
</target>
</project>
output :
[echo] ${name} = value1
second with inheritAll=false
<project default="foo">
<target name="foo">
<property name="name" value="value1" />
<antcall target="bar" inheritAll="false" />
</target>
<target name="bar">
<property name="name" value="value2" />
<echo>$${name} = ${name}</echo>
</target>
</project>
output :
[echo] ${name} = value2
some rules of thumb for antcall, it's rarely used for good reasons :
1. it opens a new project scope (starting a new 'ant -buildfile yourfile.xml yourtarget') so it uses more memory, slowing down your build
2. depending targets of the called target will be called also !
3. properties don't get passed back to the calling target
In some cases it might be ok when calling the same 'standalone' target (a target that has no target it depends on) with different params for reuse. Normally macrodef or scriptdef are used for that purpose. So, think twice before using antcall which also puts superfluous complexity to your scripts, because it works against the normal flow.
Answer to your question in the comment, using a dependency graph instead of antcall
you have some target that holds all conditions and sets the appropriate properties which may be evaluated by targets via if and unless attributes to control the further flow
<project default="main">
<target name="some.target">
<echo>starting..</echo>
</target>
<!-- checking requirements.. -->
<target name="this.target">
<condition property="windowsbuild">
<os family="windows"/>
</condition>
<condition property="windowsbuild">
<os family="unix"/>
</condition>
<!-- ... -->
</target>
<!-- alternatively
<target name="yet.another.target" depends="this.target" if="unixbuild">
-->
<target name="another.target" depends="this.target" unless="windowsbuild">
<!-- your unixspecific stuff goes here .. -->
</target>
<!-- alternatively
<target name="yet.another.target" depends="this.target" if="windowsbuild">
-->
<target name="yet.another.target" depends="this.target" unless="unixbuild">
<!-- your windowspecific stuff goes here .. -->
</target>

Resources