Ant: Referencing dynamic properties - java

I want to use the same ant script to do a build in either my local windows environment or on our redhat build server.
I have a variable 'buildDirectory' in two files (build_unix.properties & build_windows). I want to set variables depending on the environment.
<osfamily property="os.family"/>
<property file="./build_${os.family}.properties" />
<property name="tmp-base.folder" value="${buildDirectory}/tmp/"/>
I also tried
<if>
<os family="unix"/>
<then>
<property file="./build_unix.properties" />
</then>
<else>
<property file="./build_windows.properties" />
</else>
</if>
Any ideas?

Are you asking how you can automatically set the os.family property in the first place?
If so, here's one approach:
<available file="C:\\" property="os.family" value="windows" />
<available file="/usr/bin/" property="os.family" value="unix" />
Ah! Edited question makes it more clear what you are asking (not this), and I see that you're using the "osfamily" task from ant-contrib to determine the OS family. But I'll leave this answer up for anyone who is just using ant without ant-contrib.

I would expect your if...then...else version to work. As it apparently isn't I would add some extra echo's to make sure your build is doing what you think it is doing.
An echo inside the then and the else would let you know for certain what path is being executed.
Add a prefix to the properties (e.g. <property file="..." prefix="test" />) and then add an <echoproperties prefix="test" /> to ensure the properties you think are being loaded are.

you can have two files : build-unix.properties and build-windows.properites and in your init target, you simply do a copy:
<copy file="build-${os.family}.properties" tofile="build.properties">
your main build.xml could simply reference the build.properties file.
This could be quite tricky to make it work properly so what I would do is to keep all properties of the build server in the build.properties file and allow local override (for your Windows box) in a build-local.properties. You can also move properties to a build-common.properties so that your build file would include the properties files in the following order
<property file="build-local.properties"/>
<property file="build-common.properties"/>
<property file="build.properties"/>

Related

"Override" properties of an imported Ant file

I´d like to override some properties of an imported Ant-File which handles most of the basic stuff to deploy an application. First of all I know that Properties in Ant are immutable. But I can think of two ways to "override" properties for my needs and I´d like to know, which one should be the prefered approach, and/or if there are any things to consider by doing it one way or the other.
Imagine we have following master-build-script, which I like to import in my build-script:
<project name="Application" default="build" basedir=".">
<property name="overridden" value="false" />
<target name="build">
<echo message="Value of overridden is ${overridden}" />
</target>
</project>
Now I want to override the overridden property. In both cases I import the master-build-file. I use import over include, because I also want to override some targets. I know of two possible solutions to override them:
1) Since Properties are immutable I can just define the properties I´d like to "override" by defining them before I actually import the master-file:
<project name="MyApplication" default="buildApplication" basedir=".">
<property name="overridden" value="true" />
<import file="master-build.xml" />
<target name="buildApplication">
<antcall target="build" />
</target>
</project>
2) I define Params within the Ant call which seems to redefine a properties value as well:
<project name="MyApplication" default="buildApplication" basedir=".">
<import file="master-build.xml" />
<target name="buildApplication">
<antcall target="build" >
<param name="overridden" value="true"/>
</antcall>
</target>
</project>
In both cases the result is:
build:
[echo] Value of overridden is true
BUILD SUCCESSFUL
Would anyone be so kind and could explain me the difference and might also explain why I should use one way over the other, or even should use a different approach to get the same result?
The main difference between your first and second examples is that in the second case the property is only defined for the sub-build, which might sometimes be what you want, rather than globally for the build.
Other ways you can preemptively define properties globally...
Pass as JVM args when you execute ant, e.g.
ant -Doverridden=true
Define the properties in a file and load at start of your build, e.g.
build.properties:
overridden=true
build.xml:
<project name="MyApplication" default="buildApplication" basedir=".">
<property file="build.properties/>
A useful variant is to load user definable properties from the user home directory, e.g. something like:
<property file="${user.home}/MyApplication/build.properties/>
The advantage of both of these methods over the examples you gave are that the properties are overridden without changing the build file.
Ant versions 1.8 and later come with the <local/> task which allows you to declare a property as local. This might be what you need.
Another choice is to use <macrodef> which allows you to define your own macro (which is better than using <antcall> since <antcall> can break Ant's ability to create a execution matrix).

Package a runnable JPA jar putting persistence.xml outside

I want to export my jpa/swing project to a runnable jar. But I want the persistence.xml to be outside the jar not packaged inside, so I can change it without the need to export the jar again after each config.
According to JPA specifications, persistence.xml file cannot be detected outside the JAR file where the persistence unit is defined. By convention, it should be placed inside META-INF directory.
Read JSR-317, paragraph 8.2.1 for more details (http://download.oracle.com/otndocs/jcp/persistence-2.0-fr-eval-oth-JSpec/).
Nevertheless, you can try the hint proposed by this guy here and deploy your archives in exploded form.
I had the same problem, but I only needed to change Server, database, user and password. So this did it for me:
In JBoss AS, you can even have the property value as a placeholder, for example:
<property name="javax.persistence.jdbc.url" value="jdbc:sqlserver://${DbServer}:1234;databaseName=${DbName}" />
<property name="javax.persistence.jdbc.user" value="${DbUser}" />
<property name="javax.persistence.jdbc.password" value="${DbPassword}" />
and then pass the "DbServer", "DbName", "DbUser" and "DbPassword" value as a Java system property:
-DDbServer=sql99 -DDbName=db_Name -DDbUser=USER -DDbPassword=pw
In Eclipse:

Where do I put my credentials when using Ivy and a private company repository?

I'm using Ant + Ivy, and my company has recently set up a Nexus server for our own private libraries. Ivy can get dependencies from the Nexus server by using a ibilio resolver and m2compatible=true, but I have to put my credentials in a ivysettings.xml file.
How are different developers supposed to store their credentials?
Is the ivysettings.xml file not supposed to be commited in vcs?
I really don't want to store my password in plain text.
Use a settings file with properties controlling the Nexus credentials:
<ivysettings>
<property name="repo.host" value="default.mycompany.com" override="false"/>
<property name="repo.realm" value="Sonatype Nexus Repository Manager" override="false"/>
<property name="repo.user" value="deployment" override="false"/>
<property name="repo.pass" value="deployment123" override="false"/>
<credentials host="${repo.host}" realm="${repo.realm}" username="${repo.user}" passwd="${repo.pass}"/>
..
..
</ivysettings>
When you run the build you can then specify the true username and password:
ant -Drepo.user=mark -Drepo.pass=s3Cret
Update/Enhancement
Storing passwords as properties on the file system requires encryption.
Jasypt has a command-line program that can generate encrypted strings:
$ encrypt.sh verbose=0 password=123 input=s3Cret
hXiMYkpsPY7j3aIh/2/vfQ==
This can be saved in the build's property file:
username=bill
password=ENC(hXiMYkpsPY7j3aIh/2/vfQ==)
The following ANT target will decrypt any encrypted ANT properties:
<target name="decrypt">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>
<groovy>
import org.jasypt.properties.EncryptableProperties
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor()
encryptor.setPassword(properties["master.pass"])
Properties props = new EncryptableProperties((Properties)properties, encryptor);
props.propertyNames().each {
properties[it] = props.getProperty(it)
}
</groovy>
</target>
Of course to make this work, the password used for encrypting the properties needs to be specified as part of the build.
ant -Dmaster.pass=123
This means the solution is only good for hiding data at rest.
For my purposes the command-line credentials weren't an option because I'm running through Jenkins and they'd be clearly pasted on the build output, so here was my solution which strikes a balance by being reasonably secure.
Create a properties file in your home directory that contains the sensitive information (we'll call it "maven.repo.properties")
repo.username=admin
repo.password=password
Near the top of your build file, import the property file
<property file="${user.home}/maven.repo.properties"/>
In your publish target under build.xml, set your ivy settings file location (which does get checked in to code control) but embed your credential properties
<target name="publish">
<ivy:settings file="ivysettings.xml">
<credentials host="repohostname" realm="Artifactory Realm" username="${repo.username}" passwd="${repo.password}"/>
</ivy:settings>
<!-- ivy:makepom and ivy:publish targets go here -->
</target>
Create your ivysettings.xml just as you did before, but strip out the username and passwd attributes
You can then leverage your operating system's permissions to make sure that the maven.repo.properties file is properly hidden from everybody except you (or your automatic build implementation).
The ivysettings.xml sample in Mark O'Connor's answer should actually be as follows:
<ivysettings>
<property name="repo.host" value="default.mycompany.com" override="false"/>
<property name="repo.realm" value="Sonatype Nexus Repository Manager" override="false"/>
<property name="repo.user" value="deployment" override="false"/>
<property name="repo.pass" value="deployment123" override="false"/>
<credentials host="${repo.host}" realm="${repo.realm}" username="${repo.user}" passwd="${repo.pass}"/>
..
</ivysettings>
Means, the property names should not be surrounded by ${...} (it took me quite a while to find out why this failed - but now I know how to debug ivy access - use commons-httpclient-3.0, set everything to verbose etc.)
Additional to Mark O'Connor's answer you can hide the password from your daily work and from the prying eyes of your workmates by putting these properties either into the antrc startup file or into the environment variables used by ant. Please note that they are not very secure in either place.

Java Ant - how to pass a ProGuard task arguments and use them inside a configuration file?

I have this in my build.xml:
<target depends="build-jar" name="proguard">
<taskdef resource="proguard/ant/task.properties" classpath="tools/proguard4.6/lib/proguard.jar" />
<proguard configuration="ant/proguard.conf" />
</target>
It works fine.
Inside the configuration file (i.e "ant/proguard.conf") I'm trying to access properties defined in this build.xml file but I'm always getting this kind of error:
Value of system property 'jar.final_name' is undefined in '<jar.final_name>' in line 1 of file '.......\ant\proguard.conf'
The error is clear. Question is how I do what I'm trying to?
If I'd do it the "Embedded ProGuard configuration options" way I could use these properties like any other property in build.xml, but I'm trying to keep the files separate.
How do I do that then?
By default, Ant doesn't provide a way to set java system properties for its tasks. You can only specify -D options in the ANT_OPTS system variable when starting Ant itself.
I'll consider supporting the use of Ant properties in referenced ProGuard configurations (being the developer of ProGuard).
For the time being, an acceptable solution might be to specify input and output jars in Ant's XML-style:
<proguard configuration="ant/proguard.conf">
<injar name="${injar}" />
<outjar name="${outjar}" />
<libraryjar name="${java.home}/lib/rt.jar" />
</proguard>
This part of the configuration is more closely tied to the Ant script anyway.

Is there a way to generalize an Apache ANT target?

We have an Apache ANT script to build our application, then check in the resulting JAR file into version control (VSS in this case). However, now we have a change that requires us to build 2 JAR files for this project, then check both into VSS.
The current target that checks the original JAR file into VSS discovers the name of the JAR file through some property. Is there an easy way to "generalize" this target so that I can reuse it to check in a JAR file with any name? In a normal language this would obviously call for a function parameter but, to my knowledge, there really isn't an equivalent concept in ANT.
I would suggest to work with macros over subant/antcall because the main advantage I found with macros is that you're in complete control over the properties that are passed to the macro (especially if you want to add new properties).
You simply refactor your Ant script starting with your target:
<target name="vss.check">
<vssadd localpath="D:\build\build.00012.zip"
comment="Added by automatic build"/>
</target>
creating a macro (notice the copy/paste and replacement with the #{file}):
<macrodef name="private-vssadd">
<attribute name="file"/>
<sequential>
<vssadd localpath="#{file}"
comment="Added by automatic build"/>
</sequential>
</macrodef>
and invoke the macros with your files:
<target name="vss.check">
<private-vssadd file="D:\build\File1.zip"/>
<private-vssadd file="D:\build\File2.zip"/>
</target>
Refactoring, "the Ant way"
It is generally considered a bad idea to version control your binaries and I do not recommend doing so. But if you absolutely have to, you can use antcall combined with param to pass parameters and call a target.
<antcall target="reusable">
<param name="some.variable" value="var1"/>
</antcall>
<target name="reusable">
<!-- Do something with ${some.variable} -->
</target>
You can find more information about the antcall task here.
Take a look at Ant macros. They allow you to define reusable "routines" for Ant builds. You can find an example here (item 15).
Also check out the subant task, which lets you call the same target on multiple build files:
<project name="subant" default="subant1">
<property name="build.dir" value="subant.build"/>
<target name="subant1">
<subant target="">
<property name="build.dir" value="subant1.build"/>
<property name="not.overloaded" value="not.overloaded"/>
<fileset dir="." includes="*/build.xml"/>
</subant>
</target>
</project>
You can use Gant to script your build with groovy to do what you want or have a look at the groovy ant task.

Categories