Conditional execution in Ant - ant

I have a target, that is executed if my_step==true:
<target name="pre-compile" if="my_step">
...
</target>
But I want to make that pre-compile target available regardless of the value of my_step, so that I could execute my action manually using ant do_my_step:
<target name"-do_my_step">
...
</target>
Question. How can I run make pre-compile execute -do_my_step target?
That is, if property my_step is true, then pre-compile step will execute -do_my_step target.
Obviously, I could simply copy-paste contents of -do_my_step target into pre-compile target, but I want to keep my target cleanly separated.

Target names with prefix '-' are a common practice to make the target somewhat 'private' as it's impossible to call it via commandline. ant -f yourbuildfile.xml -yourprivatetarget won't work as ant commandline interface uses leading '-' for options. So strip the leading '-' from your target name to call it via ant -f yourbuildfile.xml do_my_step
Also consider :
"..Question. How can I run make pre-compile execute -do_my_step target? .."
Ant has antcall task for calling a target within the same buildscript. But antcall should be avoided because it opens a new project scope (so it needs more memory and will slow down your build) and breaks the dependency chain which is normally built via <target name="..." depends"=..."> . antcall is superfluous since ant 1.6 introduced macrodef for that purpose (reuse of functionality).

<target name="pre-compile" if="my_step" depends="-do_my_step">
...
</target>
When pre-compile is called, it will run -do_my_step before.

Related

How to pass an argument to a dependency in Ant Build Tool

I'm creating a target in the build.xml file which depends on three other targets:
<target name="test" depends="target1,target2,target3">
<echo message="Build Successful!"/>
</target>
What I'm trying to do here is to pass some argument to 'target2'. Can this be done in Ant? If so, how can I do it?
Any help is truly appreciated!!
Do you understand how depends works?
When you call target test, it will run the following targets:
target1
target2
target3
test
In that order. There's no way for target test to pass any arguments to target2.
You can pass properties to your build.xml script using the -D parameter:
$ ant -Dsource.version="1.5" compile
When your build script is executed, the property source.version will be set to 1.5.
Otherwise, look at macrodef task as a way of passing arguments to particular routines.
By the way, if I had more information what you want, I could give you a better answer.

Ant: What happens to properties set in antcall build files?

I've got a build that's a mess. In the end, targets are executed up to 15 times. Most targets are executed over a dozen times. This is because the build and targets are divided into 10 separate build files (build.xml, build-base.xml, compile.xml, etc.).
In many build files, you have at the beginning <property> tasks outside of all targets in the build file. These are usually executed first before any targets are called.
Here is my build.xml file:
<import file="build-base.xml"/>
[...]
<target name="compile-base">
<antcall target="setup-tmpj"/>
<ant antfile="compile.xml" target="compile-base"/>
[...]
</target>
Here's the compile.xml file:
<import file="build-base.xml"/>
<property name="target" value="1.5"/>
<available file="target/gensrc/com" property=gensrc.exists"/>
[...]
<target name="buildAndCompileCodeGen" unless=gensrc.exists">
<blah blah blah/>
</target>
<target name="compile-base" depends="buildAndCompileCodeGen">
<blah blah blah/>
</target>
I execute this:
$ ant -f build.xml compile-base
This calls the target compile-base in the compile.xml file. This is dependent upon the target buildAndCompileCodeGen in the compile.xml file. However, the target buildAndCompileCodeGen is only executed if the property gensrc.exists is unset.
In the compile.xml file is an <available> task that will set the gensrc.exists property, but this task is located outside of all targets in compile.xml. Is that <available> task ever called, so that gensrc.exist is set?
Okay I figured out what's going on...
Yes, when I call the compile-base target in the compile.xml file via the <ant> task, all tasks not under a target are executed before the target I call is executed. That means, if the code is already there, the buildAndCompileCodeGen target is called but not executed.
What I did was combine all the build files into one big file and got rid of all of the <ant> and <antcall> tasks. I had put the <available> task in the combined build.xml file.
In the original circumstance, I would first do a clean, then call compile-base in the compile.xml file. At that time, the <available> task would run. Since I did a clean, the file didn't exist, the property gencode.exists isn't set, and buildAndCompileCodeGen target would run.
When I combined everything, the <available> task would run, set the gencode.exists property. Then, when I did a clean, I would delete the generate code. However, the buildAndCompileCodeGen target still wouldn't execute because gencode.exists has already been set.
What should be done is this:
<target name="compile-base"
depends="buildAndCompileCodeGen">
<echo>Executing compile-base</echo>
</target>
<target name="buildAndCompileCodeGen"
depends="test.if.gencode.exists"
unless="gencode.exists">
<echo>Executiing buildAndCompileCodeGen</echo>
</target>
<target name="test.if.gencode.exists">
<available file="${basedir}/target/gensrc/com"
property="gencode.exists"/>
</target>
In this case, I call compile-base. That will call buildAndCompileCodeGen. That will first call test.if.gencode.exists first. This will be done even if the property gencode.exists already is set. Dependent clauses are run on targets before Ant looks at the if or unless parameters. This way, I don't set gencode.exists until I am ready to execute the buildAndCompileCodeGen target. Now, the available task will be run after I do a clean.

run all tests marked #Ignore

I want to make a Jenkins job to run an ant task to run all tests in my codebase which are tagged #Ignore because using annotations like #Category(IgnoredTest.class) do not work with our test run parallelization. After a lot of searching it looks undoable, but I still have hope. Help?
JUnit 4.10
I'm not sure what the impediment is with your "test run parallelization", but you might be able to do this with a rule if you're willing to use a custom "ignore" annotation instead of the JUnit one. The reason for that is that JUnit handles #Ignored tests at the Runner level, specifically in the BlockJUnit4ClassRunner.runChild() (by default). If you could find a way to use a custom Runner in Ant, you could come up with one to meet your needs pretty easily, but I don't know if that's easily doable in Ant.
As I first mentioned, though, you can easily use a different annotation and a rule to choose which methods to run. I made up a quick example of such a rule on github, along with a test that uses it. My little example uses a system property for switching, but you can also obviously make it switch on anything you can think of that you can get your hands on here.
You can clone and run this example with:
git clone git#github.com:zzantozz/testbed tmp
cd tmp
mvn test -pl stackoverflow/9611070-toggleable-custom-ignore -q
mvn test -pl stackoverflow/9611070-toggleable-custom-ignore -q -D junit.invertIgnores
The one downside of this approach that I can think of is that your tests won't get properly marked as "ignored" because that's also done by the BlockJUnit4ClassRunner.runChild() method, and if you peek at ParentRunner.runLeaf() (which runChild() delegates to), you'll see that the notifier, which is what you need to report ignored tests, isn't passed down far enough to be used by a Rule. Again, it's something you'd need a custom Runner for.
You could create a special ant target that removes the #Ignore annotation and add an #ignore annotation to any active #Test annotated method
the target would be something like this:
<project name="anyname" default="test" basedir=".">
..
..
<target name="enable-ignored-test" depends="copy-code-to-replace-ignored">
<fileset id="fsTestCase" dir="." includes="**/*Test.java">
</fileset>
<replaceregexp flags="gm">
<regexp pattern="^#Ignore"/>
<substitution expression=""/>
<fileset refid="${fsTestCase}"/>
</replaceregexp>
<replaceregexp flags="gm">
<regexp pattern="#Test"/>
<substitution expression="#Ignore #Test"/>
<fileset refid="${fsTestCase}"/>
</replaceregexp>
</target>
<target name="run-ignored-tests" depends="enable-ignored-test,test" />
..
..
</project>

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.

Ant build scripts, antcall, dependencies, etc

I have a build script and as part of that script it copies a jar file to a directory, for ease lets call it the utils jar. the utils jar is built by another build script sitting in another directory. What im trying to do have my build script run the utils build script so that I can ensure the utils jar is up to date.
So I know I need to import the utils build file.
<import file="../utils/build/build.xml" />
Which doesn't work because the import task, unlike almost every other ant taks, doesn't run from basedir, it runs from the pwd. So to get around that I have this little ditty, which does successfully import the build file
<property name="baseDirUpOne" location=".." />
<import file="${baseDirUpOne}/utils/build/build.xml" />
So now that ive solved my import problem I need to call the task, well that should be easy right:
<antcall target="utils.package" />
note that in the above, utils is the project name of ../utils/build/build.xml
the problem I'm now running into is that ant call doesn't execute in ../utils/build so what I need, and cant find, is a runat property or something similar, essentially:
<antcall target="utils.package" runat="../utils/build" />
The reason I need this is that in my utils build file the step to select which code to copy to the jar is based on relative paths so as to avoid hardcoding paths in my ant file. Any ideas?
I've got something similar set up: I have a main Ant build.xml which calls a separate build.xml that takes care of building my tests. This is how I do it:
<target name="build-tests">
<subant target="build">
<fileset dir="${test.home}" includes="build.xml"/>
</subant>
</target>
The trick is to use subant instead of antcall. You don't have to import the other build file.
Try using the "ant" task instead of the "antcall" task, which runs the imported build directly instead of importing it into the current build file. It has a "dir" parameter:
the directory to use as a basedir
for the new Ant project. Defaults to
the current project's basedir, unless
inheritall has been set to false, in
which case it doesn't have a default
value. This will override the basedir
setting of the called project.
So you could do:
<ant antfile="${baseDirUpOne}/utils/build/build.xml" dir="../utils/build" />
or something like that.
You can pass params down to antcall using nested in the antcall block. So, you can pass the properties down that way (probably even basedir since properties are immutable).

Resources