What's the use of Ant's extension-point if/unless attributes? - ant

When you define an extension-point in an Ant build file you can have it conditional by using the if or unless attribute. On a target the if/unless prevent it's tasks from being run. But an extension-point doesn't have any tasks to conditionally run, so what does the condition do? My thought (which proved to be incorrect in Ant 1.8.0) is it would prevent any tasks that extend the extension-point from being run. Here is an example build script showing the problem:
<project name = "ext-test"
default = "main">
<property name = "do.it" value = "false" />
<extension-point name = "init"/>
<extension-point name = "doit" depends = "init" if = "${do.it}" />
<target name = "extend-init" extensionOf = "init">
<echo message = "Doing extend-init." />
</target>
<target name = "extend-doit" extensionOf = "doit">
<echo message = "Do It! (${do.it})" />
</target>
<target name = "main" depends = "doit">
<echo message = "Doing main." />
</target>
</project>
Using the command:
ant -v
Relults in:
Apache Ant version 1.8.0 compiled on February 1 2010
Trying the default build file: build.xml
Buildfile: /Users/bob/build.xml
Detected Java version: 1.6 in: /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home
Detected OS: Mac OS X
parsing buildfile /Users/bob/build.xml with URI = file:/Users/bob/build.xml
Project base dir set to: /Users/bob
parsing buildfile jar:file:/Users/bob/Documents/Development/3P-Tools/apache-ant-1.8.0/lib/ant.jar!/org/apache/tools/ant/antlib.xml with URI = jar:file:/Users/bob/Documents/Development/3P-Tools/apache-ant-1.8.0/lib/ant.jar!/org/apache/tools/ant/antlib.xml from a zip file
Build sequence for target(s) `main' is [extend-init, init, extend-doit, doit, main]
Complete build sequence is [extend-init, init, extend-doit, doit, main, ]
extend-init:
[echo] Doing extend-init.
init:
extend-doit:
[echo] Do It! (false)
doit:
Skipped because property 'false' not set.
main:
[echo] Doing main.
BUILD SUCCESSFUL
Total time: 0 seconds
You will notice the target extend-doit is executed but the extention-point itself is skipped. Since an extention-point doesn't have any tasks exactly what has been skipped? Any targets that depend on the extention-point still get executed since a skipped target is a successful target. What is the value of the if/unless attributes on an extention-point?

I'm guessing there is no actual use for them, they probably appear as attributes because extension-point extends target (the associated java classes do).

Related

Ant conditional target not running

I have the following ant file:
<project name="admin" default="dirCheck" basedir=".">
<property name="directory" location="node_modules" />
<target name="run.npm.install" depends="dirCheck" unless="${dirExists}">
<echo>${directory} does not exist. Running 'npm install'</echo>
<exec executable="npm">
<arg value="install" />
</exec>
</target>
<target name="run.npm.update" depends="dirCheck" if="${dirExists}">
<echo>${directory} exists. Running 'npm update'</echo>
<exec executable="npm">
<arg value="update" />
</exec>
</target>
<target name="node_modules.check">
<condition property="dirExists">
<available file="${directory}" type="dir"/>
</condition>
</target>
<target name="dirCheck" depends="node_modules.check">
<echo>Checking for ${directory}. Exists? ${dirExists}</echo>
</target>
</project>
For some reason, neither runNPMInstall nor runNPMUpdate are ever run, regardless of whether the node_modules directory exists or not. Anyone have any idea what might be causing this? From all examples online at least one of the dependent tasks should be run.
EDIT: Changed:
<condition property="dirExists" value="true" else="false">
To:
<condition property="dirExists">
With the same result. Additional information is that I am using Ant 1.8.2. Thanks for anyone's help!
EDIT 2: Updated code to reflect my latest tests. Output from the build for new code above is:
Buildfile: /ws_html/app/client/build.xml
node_modules.check:
dirCheck:
[echo] Checking for /ws_html/app/client/node_modules. Exists? true
BUILD SUCCESSFUL
Total time: 0 seconds
Edit 3: Output when running ant -debug -f build.xml:
jjung-m2:client-dir jjung$ ant -debug -f build.xml
Apache Ant(TM) version 1.8.2 compiled on June 16 2012
Buildfile: /ws_html/client-dir/app/client-dir/build.xml
Adding reference: ant.PropertyHelper
Detected Java version: 1.7 in: /Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home/jre
Detected OS: Mac OS X
Adding reference: ant.ComponentHelper
Setting ro project property: ant.file -> /ws_html/client-dir/app/client-dir/build.xml
Setting ro project property: ant.file.type -> file
Adding reference: ant.projectHelper
Adding reference: ant.parsing.context
Adding reference: ant.targets
parsing buildfile /ws_html/client-dir/app/client-dir/build.xml with URI = file:/ws_html/client-dir/app/client-dir/build.xml
Setting ro project property: ant.project.name -> ClientApp
Adding reference: ClientApp
Setting ro project property: ant.project.default-target -> dirCheck
Setting ro project property: ant.file.ClientApp -> /ws_html/client-dir/app/client-dir/build.xml
Setting ro project property: ant.file.type.ClientApp -> file
Project base dir set to: /ws_html/client-dir/app/client-dir
+Target:
+Target: run.npm.install
+Target: run.npm.update
+Target: node_modules.check
+Target: dirCheck
Adding reference: ant.LocalProperties
parsing buildfile jar:file:/usr/share/ant/lib/ant.jar!/org/apache/tools/ant/antlib.xml with URI = jar:file:/usr/share/ant/lib/ant.jar!/org/apache/tools/ant/antlib.xml from a zip file
Setting project property: directory -> /ws_html/client-dir/app/client-dir/node_modules
Setting ro project property: ant.project.invoked-targets -> dirCheck
Attempting to create object of type org.apache.tools.ant.helper.DefaultExecutor
Adding reference: ant.executor
Build sequence for target(s) `dirCheck' is [node_modules.check, dirCheck]
Complete build sequence is [node_modules.check, dirCheck, run.npm.update, run.npm.install, ]
node_modules.check:
[available] Found directory: node_modules
Condition true; setting dirExists to true
Setting project property: dirExists -> true
dirCheck:
[echo] Checking for /ws_html/client-dir/app/client-dir/node_modules. Exists? true
BUILD SUCCESSFUL
Total time: 0 seconds
Your runNPMInstall target will never run, because the dirExists property will always be set either true or false, because you used condition task with attribute else="false".
When using the old syntax (Ant Version < 1.8.0) , means just the plain propertyname if="propertyname" the target is only activated if the property is defined - independent of its actual value. On the contrary unless="propertyname" means the target is only activated if the property is not defined, but your property will always be set from condition task => true or false.
Since ant 1.8.0 you may use the new syntax if="${propertyname} means the target is only activated if the property holds true | yes | on, respectively unless="${propertyname}" means the target will only be activated if the property hold false | no | off, see ant manual if / unless
When using if / unless with ${propertyname} it should work as expected with Ant >= 1.8.0Alternatively use the condition task without the else attribute to make it work with the old syntax :
The value to set the property to if the condition evaluates to false. By default the property will remain unset.
Also value="true" is not needed, as :
The value to set the property to. Defaults to "true".
So that should be sufficient to make it work 'old style' :
<condition property="dirExists">
<available file="${directory}" type="dir"/>
</condition>
-- EDIT after comment --
When starting your ant file it will run the default target dir.check and nothing else happens. Use :<project name="admin" default="main" basedir=".">
and create a new target :<target name="main" depends="dir.check,runNPMInstall,runNPMUpdate"/>

How to determine Jenkins build directory from Ant?

I am trying to migrate an Ant script I wrote to build and deploy projects from within the Jenkins framework (instead of triggered from an SVN post-commit hook, which was the expedient way we initially approached things). Everything is great, except I need to stage files for the deploy step and I want to stuff them into the 'build' directory Jenkins creates for the job (and since my build.xml lives in a non-project-specific location, ${basedir} and ${user.dir} do not point to the desired location).
within the Jenkins configuration, I've setup the following:
[Jenkins]
Build Record Root Directory: E:/builds/${ITEM_FULLNAME}
[Job-Specific]
Build File: C:\vc-tools\shadow\build.xml
when running a build, the script is appropriately launched and a job-specific build directory is created, e.g.
E:\builds\Test\2012-08-07_12-51-21
I want to get at this directory from within the build script, but cannot figure out how. some of the things I've tried:
[echo] ${basedir}: C:\vc-tools\shadow
[echo] ${user.dir}: C:\vc-tools
[echo] ${env.workspace}: C:\Program Files (x86)\Jenkins\workspace\Test
[echo] ${env.build_id}: 2012-08-07_12-51-21
[echo] ${jenkins_home}: C:\Program Files (x86)\Jenkins
[echo] ${BuildDir}: E:/builds/${ITEM_FULLNAME}
note: for that last one, I tried passing in:
BuildDir=E:/builds/${ITEM_FULLNAME}
as a property configured from the job within Jenkins (clearly ${} expansion doesn't take place in this context).
according to the documentation, there are no specific environment variables that are set to the full build directory path -- I can fudge it by hardcoding the E:\builds root and tacking on ${env.build_id}, but was hoping there would be an easier way to access the complete path from something Jenkins exposes (either an Ant property and an environment variable) in order to make the script more flexible.
I am using Jenkins version 1.476.
thanks
It's always a good idea for your project to have a copy of it's build logic included alongside the source code. It makes your build more portable across machines.
Having said that it's also quite common to setup build files containing common shared build logic. ANT defines the following tasks to support such activity:
include
import
So a possible solution is to store a simple build.xml file, in the root of your project directory:
<project name="my project" default="build">
<include file="C:\vc-tools\shadow\common-build-1.0.xml" as="common"/>
<target name="build" depends="common.build"/>
</project>
Notes:
It's a good idea to use a revision number in the common build file name. This assists in preserving backward compatibility with other builds using the older logic.
Update
When Jenkins runs a job is sets a number of environment variables.
The following ANT logic will print the location of the Jenkins workspace directory:
<property environment="env"/>
<target name="run">
<echo message="Jenkins workspace: ${env.WORKSPACE}"/>
<echo message="Job directory: ${env.WORKSPACE}../../jobs/${env.JOB_NAME}"/>
<echo message="Build data: ${env.WORKSPACE}../../jobs/${env.JOB_NAME}/build/${env.BUILD_ID}"/>
</target>
These days (Jenkins v. 1.484) 'run' target from answer above should look like this:
<target name="run">
<echo message="Jenkins workspace: ${env.WORKSPACE}"/>
<echo message="Job directory: ${env.WORKSPACE}/../../${env.JOB_NAME}"/>
<echo message="Build data: ${env.WORKSPACE}/../../${env.JOB_NAME}/builds/${env.BUILD_ID}"/>
</target>

Passing a variable into ant

If I pass a variable to ant by doing
ant -Dsomething=blah
How can I refer to it in my build.xml? I tried #something# and ${something} but neither seem to work.
Ultimately what I am trying to do is set some properties (versions) at compile time.
update: the problem of course turned out to be somewhere else - accepting the most complete looking answer with examples
Don't you hate it when you over think these things:
<project name="test">
<echo message="The value of foo is ${foo}"/>
</project>
Now, I'll run my program. Notice that I never defined a value for property foo in my build.xml. Instead, I'll get it from the command line:
$ ant -Dfoo=BAR_BAR_FOO
test:
[echo] The value of foo is BAR_BAR_FOO
BUILD SUCCESSFUL
time: 0 seconds
See. Nothing special at all. You treat properties set on the command line just like normal properties.
Here's where the fun comes in. Notice that I've defined the property foo in my build.xml this time around:
<project name="test">
<property name="foo" value="barfu"/>
<echo message="The value of foo is ${foo}"/>
</project>
Now watch the fun:
$ ant
test:
[echo] The value of foo is barfu
BUILD SUCCESSFUL
time: 0 seconds
Now, we'll set the property foo on the command line:
$ ant -Dfoo=BAR_BAR_FOO
test:
[echo] The value of foo is BAR_BAR_FOO
BUILD SUCCESSFUL
time: 0 seconds
See the command line overrides the value I set in the build.xml file itself. This way, you can have defaults that can be overwritten by the command line parameters.
It sounds like you want to do something like the following:
<mkdir dir="build/src"/>
<copy todir="build/src" overwrite="true">
<fileset dir="src" includes="**/*.java"/>
<filterset>
<filter token="VERSION" value="${version}"/>
</filterset>
</copy>
...which will cause your source to get copied, replacing #VERSION#:
public class a { public static final String VERSION = "#VERSION#"; }
...and then include build/src in your javac src.
That said, I don't recommend this approach since the source copy step is expensive, and it will undoubtedly cause confusion. In the past, I've stored a version.properties file in my package with version=x.y. In my Java code, I used Class.getResourceAsStream("version.properties") and java.util.Properties. In my build.xml, I used <property file="my/pkg/version.properties"/> so that I could create an output-${version}.jar.
${argsOne} works for me and is easily referenced if the invoking command is
ant -DargsOne=cmd_line_argument
Ant documentation also says so. This should work, try running with ant -debug and paste the output.

checking latest version in version control

i am currently writing an ANT script which will include some intelligence to check for things. I am using SnapshotCM from True Blue Software as my version control and using CruiseControl as a framework for my nightly build.
Basically, I will need to always check for the latest version found in my version control and execute commands. In this case here is an example:
<project name="nightly_build" default="main" basedir="checkout">
<target name="init">
<property file="initial.properties"/>
</target>
<target name="main" depends="init">
<!-- need some code to set variable -->
<!-- need some code to increment variable -->
<!-- need some code here to check for the latest version -->
<exec executable="C:/Program Files/True Blue Software/SnapshotCM/wco.exe">
<arg line='-f -R "C:/Work/7.10.000_Tip/7.10.000_Tip_GUI_TEST/"'/>
</exec>
</target>
</project>
In the code above, I will load the "initial.properties" file.
The algorithm should be as follow:
load the initial properties file
get the build_number
increment build_number by 1 (let this new variable be X)
if X is found, increament X by 1 (if not found jump to 6.)
if X is found, repeat 4 (until X cannot be found)
else use the build number inside the <arg line ='-f -R "C:/..../7.10.100.X..../"'/>
The initial.properties file is as follow:
Major_Version=7
Minor_Version=10
Project_Number=100
Build_Number=036
Product_Version=${Major_Version}.${Minor_Version}.${Project_Number}.${Build_Number}
can anyone guide me on that?
Ant is not a programming language. It's a dependency matrix language.
That means you don't specify execution order in Ant. Ant will calculate the order it needs to run the targets. It also means Ant doesn't have the ability to do loops, or even change the value of a property once it is set.
There are a few packages that build upon Ant. The old standby is the Antcontrib. Antcontrib has the concept of variables which are like mutable properties. It also has various looping structures. However, I'm not sure if the <foreach> or <for> tasks will do what you want...
Searching sequentially for the next build number is something you can do in a shell script. In fact, I highly recommend this.
I use Ant for builds only and keep my CM functions outside of my build.xml file. Instead, I rely on my build system to do everything that's not related to the build itself. This includes checking out the code, saving the artifacts, and compiling unit tests. This way, if I change the way I use my continuous build system or my version control system, I don't have to modify my build.xml files.

Passing filepath to ANT from BAT script

I am trying to invoke an ANT target from Windows (right-click) file context menu.
I have setup the registry entries to invoke a batch script which invokes my ANT EXEC target.
I need to pass the path of the file (on which user right-clicked) to my ANT target. So I am using %~dp1 to set an ANT properties in my bat script:
Set tobeusedfilepath=%~dp1
Set tobeusedfile=%~n1
resulting in:
tobeusedfilepath=D:\Project\Rel L\
tobeusedfile=file
The problem is %~dp1 returns a string with "\" as file separator. But ANT EXEC task wants "/"
[exec] '-source'
[exec] 'D:ProjectRel L/file'
[exec] ......
[exec] The file, 'D:ProjectRel L/file', does not exist.
Any suggestions how to get around this path separators?
set AntPath="D:\Project\Rel L\"
set AntPath=%AntPath:\=/%
set AntPath=%AntPath::/=:%
gives
set AntPath="D:\Project\Rel L\"
set AntPath="D:/Project/Rel L/"
set AntPath="D:Project/Rel L/"
If you are running on Windows Ant will happily accept OS directory separator which is \.
Upon examination of the output of your program I see that the path separators are missing: you have D:ProjectRel not D:\Project\Rel. I may only guess that you are trying to exec a Cygwin program. Cygwin programs will use \ as an escape character. Therefore you need to use a <pathconvert> property to adjust the directory separators.
Code snippet below illustrates how to do this
<property name="tobeusedfilepath" location="D:\Project\Rel L\"/>
<property name="tobeusedfile" value="file"/>
<property name="system-path-filename"
location="${tobeusedfilepath}/${tobeusedfile}"
/>
<pathconvert property="unixized-filename" targetos="unix">
<path location="${system-path-filename}"/>
</pathconvert>
<echo message="system-path-filename=${system-path-filename}"/>
<echo message="unixized-filename=${unixized-filename}"/>
And here is the output of this run:
[echo] system-path-filename=D:\Project\Rel L\file
[echo] unixized-filename=D:/Project/Rel L/file

Resources