Reasons for using Ant Properties files over "Properties Tasks" - ant

I'm currently working with some developers who like to set up Ant tasks that define environment specific variables rather than using properties files. It seems they prefer to do this because it's easier to type:
ant <environment task> dist
Than it is to type:
ant -propertyfile <environment property file> dist
So for example:
<project name="whatever" default="dist">
<target name="local">
<property name="webXml" value="WebContent/WEB-INF/web-local.xml"/>
</target>
<target name="remote">
<property name="webXml" value="WebContent/WEB-INF/web-remote.xml"/>
</target>
<target name="build">
<!-- build tasks here --->
</target>
<target name="dist" depends="build">
<war destfile="/dist/foo.war" webxml="${webXml}">
<!-- rest of war tasks here -->
</war>
</target>
I am finding it hard to convince them that properties files are they right way to go. I believe properties files are better because:
They provides more flexibility - if you need a new environment just add a new properties file
It's clearer what's going on - You have to know about this little "trick" to realize what they're accomplishing
Doesn't provide default values and the ability to use overrides - if they used property files they could provide defaults at the top of the project but have the ability to override them with a file
Script won't break if an environment task isn't supplied on command line
Of course all they hear is that they need to change their Ant script and have to type more on the command line.
Can you provide any additional arguments in favor of properties files over "property tasks"?

Properties tasks tightly couple the build file to environments. If your fellow developers are arguing that they "have to change their ant script" with your suggestions, why aren't they arguing about changing it every time they have to deploy to a new environment? :)
Perhaps you can convince them to allow both properties file and command-line configuration. I set up my Ant builds so that if a build.properties exists in the same directory as the build.xml, it reads it in. Otherwise it uses a set of default properties hard-coded into the build. This is very flexible.
<project name="example">
<property file="build.properties"/>
<property name="foo.property" value="foo"/>
<property name="bar.property" value="bar"/>
...
</project>
I don't provide a build.properties with the project (i.e. build.properties is not versioned in SCM). This way developers aren't forced to use the property file. I do provide a build.properties.example file that developers can reference.
Since Ant properties, once set, are immutable, the build file will use properties defined in this order:
Properties provided with -D or -propertyfile via the command line
Properties loaded from build.properties
Default properties within build.xml
Advantages of this approach:
The build file is smaller and therefore more maintainable, less bug-prone
Developers that just can't get away from setting properties at the command line can still use them.
Properties files can be used, but aren't required

The arguments you have are already pretty compelling. If those arguments haven't worked, then arguing isn't going to solve the problem. In fact, nothing is going to solve the problem. Don't assume that people are rational and will do the most practical thing. Their egos are involved.
Stop arguing. Even if you win, the resentment and irritation you create will not be worth it. Winning an argument can be worse than losing.
Make your case, then let it go. It's possible that after a while they will decide to switch to your way (because it actually is better). If that happens, they will act like it was their own idea. There will be no mention of your having proposed it.
On the other hand, they may never switch.
The only solution is to work towards a position of authority, where you can say how things are to be done.

The problem with the first solution (using ant property) is basically hardcoding.
It can be convenient when you start a project for yourself but quickly you have to remove that bad habit.
I'm using a property file close to what said robhruska except that I have committed the build.properties file directly. This way you have a default one.
In other hand, I understand I could add those default values in the build.xml. (I will probably try that in the next hours/days ;-) ).
Anyway, I really don't like the first approach and I would force those guys to follow the second one ...

Related

Reading property names from a properties file before loading it (ANT)

I need to retrieve all the properties' names from a properties file before loading it (using Ant)
I'll go into detail to explain the whole process:
A first properties file (let's name it as a.properties) is read and
all its properties loaded as project's properties.
#a.properties's contents
myvar1=1
myvar2=someTextHere
A second file (let's say b.properties) has to be loaded on the
project. Some already-set properties can also be contained in this
second file, so what we have to do is to update such variables with
the value found on it (by means of the ant-contrib's var target)
#b.properties's contents
myvar1=2 #updated value for a property that's is already set on the project
myvar3=1,2,3,4,5,6
So the expected subset (from a ANT project's properties perspective)
of property/value pairs would be:
myvar1=2
myvar2=someTextHere
myvar3=1,2,3,4,5,6
We cannot change the order in which those files are loaded on the project, which would be the easiest way of solving the issue (because of the behavior adopted by Ant when setting's properties)
Any feedback will be highly appreciated.
Regards
I assume that you need to read properties from different files before you build your source code
<target name=-init-const-properties description="read all properties required">
<propertyfile file="AbsolutePathToPropertyFile" comment="Write meaningfull
about the properties">
<entry value="${myvar1}" key="VAR1"/>
<entry value="${myvar2}" key="VAR2"/>
</propertyfile>
</target>
Note: you need to add proper AbsolutePathToPropertyFileand comment if required
In the target -init-const-properties you can add as many files you want to read and use this target as dependent target in which you going to use these property values. hope this will answer your question
I recommend having a standard file for build defaults called "build.properties". If you need to override any settings, then create an optional file called "build-local.properties".
My advice is to keep build logic simple. Using the ant-contrib extension to make properties act like variables is rarely needed in my experience.
Example
├── build-local.properties
├── build.properties
└── build.xml
Running the project produces the following output, where the value "two" is substituted:
$ ant
build:
[echo] Testing one, dos, three
Delete the optional file and it goes back to default values:
$ rm build-local.properties
$ ant
build:
[echo] Testing one, two, three
build.xml
The secret is the order in which the property files are loaded. If they don't exist then they don't create properties.
<project name="demo" default="build">
<property file="build-local.properties"/>
<property file="build.properties"/>
<target name="build">
<echo message="hello ${myvar1}, ${myvar2}, ${myvar3}"/>
</target>
</project>
build.properties
myvar1=one
myvar2=two
myvar3=three
build-local.properties
myvar2=dos
Finally, the approach I followed was to specify the second properties file (b.properties) from the command line:
ant <my_target> -propertyfile b.properties
So that's work fine to me...
Thanks all of you for your help.

Exclude fileset from another fileset using a property

I've been using Gradle almost exclusively lately, but every now and again I have to dive back into our antiquated ant build system and figure out how to do something. Then I realize how little I know about ant and/or how difficult even some of the simplest tasks appear to be.
For example, I have a target that does some operation on a fileset:
<target name="some-operation">
<fileset dir="blah" id="stuff">
<filename name="**/*.txt" />
<not>
<filename name="**/foo/*" />
</not>
</fileset>
<!-- do some operations on "stuff" -->
</target>
Imagine this is in some old build system that multiple projects use. I want to exclude additional things in the fileset (let's say, files inside directory "bar", similar to "foo"), but since this is something multiple projects use, I can't just go putting my custom exclusions into the build system. I need some way to plug that additional fileset in (it could contain multiple exclusions).
What's the best way of doing this? I'm thinking I'll set a property in my build with the files to exclude, but the some-operation target will have to handle it gracefully when that property is missing. However, if I set a fileset to a property, I'm not quite sure how to get it excluded from the original fileset in some-operation.
Any ideas of the best/cleanest way to do this?
For reuse create a macrodef with nested element holding 1-n filesets for flexibility.
See this answer providing an example of macrodef using nested element.

ant ${java.home} points to $JAVA_HOME/jre, not $JAVA_HOME

When trying to compile a Javadoc taglet, which requires $JAVA_HOME/lib/tools.jar, I discovered that ant (version 1.8.4) sets java.home to $JAVA_HOME/jre rather than just $JAVA_HOME. I verified this thusly:
<echo>${java.home}</echo>
<echo>${env.JAVA_HOME}</echo>
[echo] /usr/java/jdk1.7.0_21/jre
[echo] /usr/java/jdk1.7.0_21
According to ant -diagnostics, there isn't any property like a jdk.home. Thus, to use tools.jar I have to do:
<classpath location="${java.home}/../lib/tools.jar"/>
So, I have two questions:
1) Is there something wrong with my setup of ant that's causing java.home to point to the JRE instead of the JDK?
2) If this is the way ant is supposed to work, is using the .. in my classpath the way I'm supposed to do things? Or should I do ${env.JAVA_HOME}/lib/tools.jar? Or something else entirely?
Here are the answers:
"Is there something wrong with my setup ...?" No. Ant is setting it's internal java.home based on JVM System properties. The code for HotSpot (JVM internals) sets it with "/jre" appended on purpose. In fact, the Java(TM) Tutorials for System Properties describes it exactly that way. The "java.home" variable from inside ant really isn't one-in-the-same as the "JAVA_HOME" that is set in your environment -- different but with similar names.
"(What is) the way I'm supposed to do things?" You can really do whatever you feel is appropriate, but remember that Ant can and usually does run in a separate JVM process. I'd assume that your system environment is probably specifying the JVM that was used to develop the app, so I would just use "${env.JAVA_HOME}" to ensure that development expectations meet build expectations.
For more information, please see another similar answer here.
Also, consider that more info can be collected from ant by running it with the -debug, -diagnostics and/or -verbose flags.
Had the same problem. I found that adding fork="true" to the javac tag solves this issue. So do something like this:
<javac target="1.7" source="1.7" fork="true" ...>
I will thank whoever can explain why this works.

Condition Property Override

I want to use an condition property to set the property value to X if another property is defined and Y otherwise. However, I don't want the user to be able to override the condition property from the command line.
How can this be achieved?
Starting from ant 1.8 for some use cases local task may be applicable. Since a property is made local it starts with an empty value. It's scope is limited to current target, but you may pass it to subsequent targets using param argument in antcall.
Nope, you can't override a property set on the command line. At least, it's not easy to do. The whole purpose of overriding properties on the command line is to allow users to override defaults in order to make modification in the way your project builds. For example:
<property file="${basedir}/build.properties"/>
<property name="javac.debug" value="no"/>
<target name="compile">
<javac destdir="${main.destdir}"
debug="${javac.debug}">
By default, the Java code is compiled without debugging information. Maybe this is done to make jar files smaller, or faster interpretation, or maybe to make the code harder to decompile and read. Whatever reason, this build won't put debug information into the classfiles.
However, developers do want this debugging information, so they want to be able to override this setting:
$ ant -Djavac.debug=true compile
Or, they can create a build.properties file and put the value in there.
This type of issue comes up when you're not using Ant for builds. I know several sites that use Ant scripts to do deployments. I usually discourage this because Ant isn't really made for this type of thing. For example, Ant doesn't have any built in logic or loops. Once a property is set, it can't be changed. These are good ideas for a build language, but a terrible idea for a general purpose programming language.
Also, developers shouldn't be doing builds for QA or production. Those should be done by a build server that won't override defaults.
Now how to destroy this whole well thought out system and cause absolute havoc:
You can use the ant-contrib tasks in your project. Doing this will allow you to access the Ant Contrib var task to unset properties.
Download the ant-contrib.jar file (whatever the latest version is), and put it in a lib directory under your project. Then you can do this:
<project name="danger-will-robinson" default="package" basedir="."
xmlns:ac="http://ant-contrib.sourceforge.net">
<!-- Define the Ant-Contrib tasks -->
<taskdef=resource="net/sf/antcontrib/antlib.xml"
uri="http://ant-contrib.sourceforge.net">
<classpath>
<fileset dir="${basedir}/lib">
<include name="ant-contrib*.jar"/>
</fileset>
</classpath>
</taskdef>
<!-- Unset Property "foo", so you can use it -->
<ac:var name="foo" unset="true"/>
Note that the <classpath> points to the ant-contrib jar in the ${basedir}/lib directory. If you check that into your source repository, it will allow everyone who checks out your project to be able to do the build without installing the ant-contrib jar on their system.
Note that I've defined a "ac" XML namespace, so Ant-Contrib tasks won't overlap other possible third party tasks.
Properties in ant once set are immutable by design. You may overwrite an existing property with any scripting language that provides access to ant api, i.e. javascript.
JDK >= 1.6 already ships with a javascript engine, so you may use something like :
<project>
<property name="x" value="whatever"/>
<script language="javascript">
project.getProperty('x') ?
project.setProperty('foo', 'true') :
project.setProperty('foo', 'false');
</script>
<echo>$$[foo} => ${foo}</echo>
</project>
out of the box.But that won't help if someone uses ant -f yourbuild.xml -Dfoo=bla !! as userproperties (those properties defined via -Dkey=value) have a special protection.
So your requirement "..However, I don't want the user to be able to override the condition property from the command line". is not fullfilled.
But the let task from Ant addon Flaka provides the possibillity to overwrite even userproperties :
<project xmlns:fl="antlib:it.haefelinger.flaka">
<property name="x" value="whatever"/>
<!--
:= defines a new property whereas
::= overwrites any existing property
even userproperties
-->
<fl:let> foo ::= has.property['x'] ? 'true' : 'false'</fl:let>
<echo>$$[foo} => ${foo}</echo>
</project>
Run both scripts with ant -f yourbuild.xml -Dfoo=bla to see the difference.
Ant api has also method project.setUserProperty(String,String) so you may use also:
...
<script language="javascript">
project.getProperty('x') ?
project.setProperty('foo', 'true') :
project.setProperty('foo', 'false');
project.getUserProperty('x') ?
project.setUserProperty('foo', 'true') :
project.setUserProperty('foo', 'false');
</script>
...
to prevent the foo property to be set via .. -D .. and it will work even if property x is defined on commandline -Dx=whatever You have to make your choice, script task with javascript out of the box or Flaka let task
oneline solution but Flaka jar needed.

Findbugs ant task submitting several dynamically detected JAR files for analysis

I'm currently looking to run static analysis over a pre-existing project. As the project is created and supplied by an off-site company, I cannot change the build process radically.
The project is split into a lot of sub-modules, located in various places. For other analyisi tools (JDepend, Google Testability Explorer, etc.), I have dynamically detected all build JAR files into a path element as follows:
<path id="built-libs">
<fileset dir="${overall-base}">
<include name="${some-common-base}/**/lib/*.jar" />
</fileset>
</path>
<property name="built-libs-string" refid="built-libs" />
For some tools, I use the build-libs, for others I use the string (in classpath form; x.jar;y.jar).
The trouble is, FindBugs uses a completely different format to any other;
<class location="x.jar"/>
<class location="y.jar"/>
...
Now, I could list all the JAR files manually, but then run the risk of this list going out of synch with the other tool's lists, or of introducing typos.
Another complication is that I also want to run the reports in Jenkins, in this case the extract directory for individual modules will depend on the job that has previously built the module (pipeline builds, modules extracted from SCM and built in parallel, the reporting occurring at the end of the pipline).
I could make a call out to the OS to run FindBugs, passing in the JARs in a space separated list (as in Invoking FindBugs from Ant: passing a space-separated list of files to java). However, I prefer a, Ant solution to an OS <exec... hack.
Note I know I have a similar problem for the sourcepath element, however, I'm assuming that solving the class element problem also solves the sourcepath one.
Ideally, FindBugs should be taking a resource collection rather than separate class elements. I'm not familiar with FindBugs, so I can't comment on why they have chose to go the class element route instead of a resource collection, however your comment about using exec implies that using a resource collection is a valid design alternative.
I would try rolling your own Ant macro, which invokes FindBugs directly using the java task. This should give you the control you need and avoiding the redundancy that the FindBugs Ant task would introduce.
Another option (which is an ugly hack) is to use the fileset to write a mini ant file with a FindBugs target, which you then invoke using the ant task. shudders
The Findbugs Ant task allows you to specify a filelist which can be used to specify multiple files. Quoting from the Findbugs documentation
"In addition to or instead of specifying a class element, the FindBugs
task can contain one or more fileset element(s) that specify files to
be analyzed. For example, you might use a fileset to specify that all
of the jar files in a directory should be analyzed."
Example that includes all jars at ${lib.dir}:
<findbugs home="${findbugs.home}" output="xml" outputFile="findbugs.xml" >
<auxClasspath path="${basedir}/lib/Regex.jar" />
<sourcePath path="${basedir}/src/java" />
<fileset dir="${lib.dir}">
<include name="*.jar"/>
</fileset>
</findbugs>

Resources