How to identify unused tasks in ant xml files - ant

I was given 20 xml files which are run when the build.xml is called.... I was asked to clear the junk in those files. How do I identify the unused tasks in those xml files?

There's probably no simple, fool-proof solution to this (you'd really just have to ask everyone in your company what they're using), however one very useful tool I like to use with complicated Ant scripts is the "Grand" graphing tool. https://ant-grand.github.io/Grand/grand.html
Download the library and place it in a lib directory, then create a new Ant script like this:
<?xml version="1.0"?>
<project default="graph">
<typedef classpath="lib/grand.jar" resource="net/ggtools/grand/antlib.xml" />
<target name="graph">
<grand buildfile="${script.file}" output="${script.file}.dot">
<filter name="prefixed" />
</grand>
<exec executable="dot">
<arg line="-Grankdir=TB -Tpng ${script.file}.dot -o ${script.file}.png"/>
</exec>
</target>
</project>
Now you can call the script with
ant -f graph.xml -Dscript.file=/path/to/ant/script/build.xml
and you will end up with a build.xml.png image file that shows a clean target dependency tree for whichever script you pointed it to.
I've added an image that was generated from one of my own relatively complicated scripts as an example. When a target has an arrow pointing to another target, that means the former is using the latter as a dependency (and thus the latter can't be removed without disrupting the former). Anything that isn't being pointed to as a dependency can be removed without hurting anything else, however that doesn't necessarily mean it's useless on its own.

Related

How to generate document output from text files in TFS

We store various design documents within TFS in multimarkdown format. We also have an EXE process that can run to take those MMD files and generate PDF's from them - but just by getting the files from a local folder.
What we'd like to do is to have a process run "on-checkin", just as if you'd run an automatic build on checkin (i.e., ultimately calling msbuild to compile an application) but in our case we'd like it to be able to get a list of the checked in files and to process and generate an output of them. The result doesn't need to be in TFS because they're a build output, not the source.
I'm sure this should be somehow possible by taking the same approach as must be taken by the workflow for a "normal" build.
Has anybody done anything like this or can point me in a suitable direction please ?
You could use the exec task in MSBuild to invoke the exe and "build" your output. Create a file called something like buildDocs.proj and check it in to TFS possibly in a folder under the things you want to build. Use the MSbuild below as a guide.
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build">
<Exec Command='"My.exe" -My Paramiters' />
<ItemGroup>
<CopyItems Include="[path to output]\*.*" />
</ItemGroup>
<Copy SourceFiles="#(CopyItems)" DestinationFolder="$(OutDir)\SomeDir" />
</Target>
</Project>
The trick will be in identifying the various paths involved.
Use the default template to build the proj, just as you would a c# project. If you need to pass in additional Parameters to MSBuild you can do this from within the advanced section of the build definition process tab.

Ant - How can I run the same depends from multiple targets

Is there a way to get ant to execute multiple depend targets multiple times. Consider this:
<target name="buildall" depends="mycommon,myDAO" />
<target name="myCommon" depends="initCommon, clean, makedir, compile" description="">
<echo> Build completed for myCommon </echo>
</target>
<target name="myDAO" depends="initDAO, clean, makedir, compile" description="">
<echo> Build completed for myDao </echo>
</target>
I would like buildAll to call myCommon, which calls initCommon, clean, makedir, compile, then call myDAO which calls initDAO, clean, makedire, compile.
So I want the clean, makedir and compile tasks to be executed multiple times. They are generic and run based on properties set in the initXXX task.
I tried this:
<target name="buildall">
<antcall target="myCommon" />
<antcall target="myDao" />
</target>
but that runs everything outside of tasks everytime which is not what I want. Any thoughts?
First: Do not use <antcall/> it's usually a sign you've done something wrong.
Now, understand that Ant is not a programming language where you tell Ant what you want to do and the order you want it to be done. Ant is a matrix dependency language. You merely tell Ant what you want (I want to build this jar), and let Ant figure out what it should do. Ant does its very best not to run a target multiple times.
For example, both myCommon and myDAO call the clean target. Ant duly notes that both require clean target, and then calls clean once and only once before it runs both of your targets. It's the way Ant is suppose to work.
So, let Ant do its job. First, Thou shall not clean under normal circumstances. Builds are suppose to minimize rebuilding in order to speed up a task. If you haven't modified a *.java file, why should you force me to rebuild the corresponding *.class file?
Second: Don't double up dependencies: For example, if I want to build the target myDAO, I want to compile the code (maybe build a jar or war). That's all my myDAO target should depend upon. Now, when I compile, I might need to make my directory, and when I make my directory, I might need to do my init:
<target name="clean">
<echo>Clean up my working directory to be nice and sparkly</echo>
</target>
<target name="initDAO">
<echo>Initialize stuff for my DAO build</echo>
<echo>Maybe setup some properties?</echo>
</target>
<target name="makedir"
depends="initDAO">
<echo>I need my directories for building.</echo>
<echo>But first, I need to setup stuff"</echo>
</target>
<target name="compile"
depends="makedir">
<echo>I need to compile my dao source"</echo>
<echo>But first, I need to make the necessary directories</echo>
<target>
<target name="myDAO"
depends="compile">
<echo>Here's where I package up my DAO</echo>
<echo>But I have to compile stuff before I can package it</echo>
</target>
Note the above structure. If I run the target myDAO, Ant will look at the dependencies and then run initDAO, makedir, compile, and finally myDAO to package everything up. Again, I have a clean target that will restore my working space to pristine (before anything was built) condition, but I don't call it as part of a package because I don't want to redo work.
"Ah!", you say, "But I have to clean up because myCommon and myDAO use the same directories for building and packaging."
Well don't do that. Instead, make sure your two packages use different target directories for building and packaging. This way, you don't have to clean up the mess from one to another. And, you can change a single source file, rebuild, and not have to recompile everything again.
You can save yourself from trouble by defining macros to handle stuff in common between the two. For example, you might be able to define a compile macro that takes as its parameters the name of a source directory and it will create a destdir based upon that source directory name and compile your common and DAO targets.
So, let Ant work its magic. Use dependencies not as a means of telling Ant how to do something, but merely telling Ant that a particular target depends upon another target. Let Ant figure out the order of execution. Also, don't set up your tasks to require you to scrub directories and reinitialize everything. You want Ant to help minimize the build by not having to rebuild or recopy over files that haven't changed.

Generate Ant tasks with macro

I've been searching for a possibility to generate ANT targets from top-level macro.
Details:
We have heterogenic build system. ANT+IVY is used as top-level (inherited solutin, can't be changed). Some projects are built via MSBuild, called from ANT via exec task. For each of these projects, there's at least two distinct calls to msbuild (wrapped with macro for brevity), one in "build" target, and one in "clean". Two of them are different only by "target" parameter. So I was guessing, if there's possibility for something like this:
Extension nodes:
<extensionpoint name="build-ext-point" />
<extensionpoint name="clean-ext-point" />
<target name="build" depends="build-ext-point" />
<target name="clean" depends="clean-ext-point" />
My magic macro:
<macrodef name="msbuild-proj" />
<attribute name="project" />
<sequential>
<target name="#{project}-build" >
<msbuild project="#{project}" target="Build" />
</target>
<target name="#{project}-clean" >
<msbuild project="#{project}" target="Clean" />
</target>
</sequential>
</macrodef>
How it would be used:
<msbuild-proj project="CPP-proj" />
Thanks!
P.S: Yeah I know that I can define those build and clean overridden, or via ext point, or whatever. The question is actually whether I can remove some code duplication.
UPD: I'd answer this by myself. At the point, there's no such possibility. Mainly, because Target class is a task container, but not a task. So, it cannot be placed into container. So I guess I'll write some kind of extensible task.
ANT has a couple of mechanisms for building modular builds.
First of all I think your main question was on how to build "extension points" to your build? The following ANT tasks are designed to import common build logic from another build file:
import
include
Since you're already planning to extend your build using macrodefs, I'd recommend packaging these as a reusable ANTlib. The ANTlib can live within your project, but it's really designed to be packaged within a jarfile which another build can pickup, for example by installing it in the standard ANT lib directory:
$ANT_HOME/lib
$HOME/.ant/lib
Finally, if you're already using ivy and you package your taskdefs as ANT libs, you could version your build logic by installing it in a Maven repository manager like Nexus. This addresses one of the key problems with large ANT builds. Over time they become so big it's impossible to change the common logic without impacting older builds (Demonstrating that the builds are not properly isolated from each other).
Actually done this.
Does its job, although some caveats are present.
For those interested: https://bitbucket.org/targetsan/ant-events

Working with ant namespace / directory structure

I'm working with ant on linux using the command line. I've got a simple build step with javac. This compiles correctly but it creates a directory structure under build like my namespace.
ie: ./build/com/crosse/samplespace/SampleProgram.class
How can I get this output into one directory (where it's easier to call java on it).
I tried
<target name="output" depends="compile">
<copy todir="${output}">
<fileset dir="${build}" includes="**/*.class"/>
</copy>
</target>
but that repeats the same thing in my output directory. How can I use ant to get everything into a single directory?
Alternatively how could I use an ant step to copy another file into the root of that path (an apache commons configuration file)?
Edit: This is mainly a convenience factor, I get tired of navigating through the same 3 directories to run my program.
What about creating a jar file containing all your files (classes and other resources)?
A jar also has a 'default' class the main method of which gets executed when the user double clicks it or calls it using java -jar <jar-file>.
You can use the Ant jar task.
Beside that, it is important that you keep your directory structure (outside a jar), otherwise the java class loader won't be happy when it has to load these classes. Or did I get your question wrong?
To answer your question, you would use a flatten mapper, as carej points out. The copy task even has a shortcut for it:
<copy todir="${output}" flatten="yes">
<fileset dir="${build}" includes="**/*.class"/>
</copy>
However, I also don't understand what you hope to accomplish with this. The java runtime expects class files to be in a directory structure that mirrors the package structure. Copying the class files to the top-level directory won't work, unless the classes are in the default package (there is no package statement in the .java files).
If you want to avoid having to manually change directories, you can always add a target to your ant build file that calls the java task with the appropriate classpath and other parameters. For example:
<target name="run" depends="compile">
<java classname="com.crosse.samplespace.SampleProgram"
classpath=".:build"/>
</target>
You can accomplish what you want to do by using the flattenmapper but I'm at a loss to understand what possible valid reason you'd have for doing it.

How to load an optional task into ant without -lib or global installation?

I want to use the FTP task in ant, and I have found the appropriate jar files and got everything working fine. I have put the jar files in a "libs" directory alongside the other files used in the build. The only problem is that the user must run "ant -lib commons-net-ftp-2.0.jar" to make a build; I would really prefer that it were possible to just run "ant" with no arguments.
Reading the ant optional tasks intallation page, I see that there are five ways one can load up extra libraries in ant, and none of them are really what I'm looking for. I do not want to force the user to make any modifications to their system to run this task; it should be possible to just load it from the "libs" directory inside of our product's source folder. So that means setting the global CLASSPATH is also out (which is a bad idea anyways).
The last option, as noted in the documentation, is the preferred approach... loading the jarfiles individually from the build script itself. I have done this in the past with the ant-contrib tasks and JUnit, and would like to do that here, but I don't see how I can accomplish this. The FTP task doesn't support a nested classpath element, and I don't know the XML resource I would need to load this library via a taskdef. How can I load the libraries from within ant?
Edit: In response to the answers and questions which have been posted here so far, I'm using ant 1.7.1. Making an ftp taskdef definitely does not work; that throws the following error:
BUILD FAILED
/my/path/build.xml:13: taskdef class org.apache.tools.ant.taskdefs.optional.net.FTP cannot be found
Perhaps this is because the classname is wrong. How exactly do I find the classname I'm supposed to use if I only have a jarfile? It's not documented anywhere, and I couldn't find anything in the jar itself resembling that path.
The problem you are having is due to the different class-loaders in use. The Commons Net classes must be loaded by the same class-loader that loads the FTP task. Because the FTP task is loaded by Ant on start-up, you need to add the Commons Net to Ant's classpath so that it is loaded by the same class-loader. That's why the documentation gives you 4 different ways to do this.
I agree that none of them are ideal (the CLASSPATH environment variable being the worst). One way around this is to supply a shell script with your project that invokes Ant and passes the apporpriate -lib argument. You then get people to use this rather than invoking Ant directly. In fact, you could deviously name it 'ant' so that it gets run instead of the existing 'ant' on the path (this only works if the current directory is on the path, ahead of other directories).
The fifth option in the documentation is great in theory. They finally fixed the class-loading problems in 1.7.0. Unfortunately, as you mention, nobody retro-fitted the FTP task to take a classpath. You could try submitting an enhancement request, but this won't help in the short term.
There is one other option, which isn't any better than the others. Instead of making sure that the Commons Net classes are loaded by the class-loader that loads the FTP task, you could make sure that the FTP task is loaded by the class-loader that loads the Commons Net classes. To do this you have to remove the ant-commons-lib.jar file from the 'lib' directory of the Ant installation. This means that the FTP task won't get loaded on start-up. This is actually why the optional tasks are broken up into so many separate JARs - so that they can be individually removed. Put this JAR file alongside the Commons Net JAR file so that it can be loaded at the same time. Then you can do something like this (I tried this and it works):
<taskdef name="ftp"
classname="org.apache.tools.ant.taskdefs.optional.net.FTP">
<classpath>
<pathelement location="${basedir}/lib/ant-commons-net.jar"/>
<pathelement location="${basedir}/lib/commons-net-2.0.jar"/>
</classpath>
</taskdef>
<ftp server="yourserver.com"
userid="anonymous"
password="blah">
<fileset dir="somedirectory"/>
</ftp>
But this is probably a worse option than just using the -lib switch (with or without a wrapper script). The only other thing I can think of is to try to find a third-party FTP task to use instead of the default one.
I have a solution:
you can download a new "classloader" task from http://enitsys.sourceforge.net/ant-classloadertask/ and load it whith:
<taskdef resource="net/jtools/classloadertask/antlib.xml"
classpath="XXX/ant-classloadertask.jar"/>
Naw can do things like loading classes with the same classloader that ant use for his task:
<classloader loader="system" classpath="XXX/commons-net-2.0.jar"/>
or "loader="project""
Then you definde your task:
<taskdef name="ftp" classname="org.apache.tools.ant.taskdefs.optional.net.FTP"/>
and go :-)
So I succeeded in doing this for the ant-salesforce.jar that you get when trying to do salesforce work (fun...)
Check to see if the jar has an xml file in it that looks something like this:
<antlib>
<typedef name="compileAndTest" classname="com.salesforce.ant.CompileAndTest"/>
....
</antlib>
Then in ant give it a taskdev that reads that file from inside the given jar, like this:
<taskdef resource="com/salesforce/antlib.xml" classpath="lib/ant-salesforce.jar" />
Hope that helps some.
Ah, man, this is just so nasty. I run ant from eclipse. I don't want to reconfigure ant in eclipse for new workspaces, so here's what I decided to do, to decouple running the task and configuring ant. I extracted the ftp task to a separate build file. Next I added a native call to the command line to start a completely new ant process with the required libraries on the path:
<target name="deploy-ftp">
<exec command="ant">
<arg line="-buildfile ftp.xml deploy-ftp -lib lib/ant"/>
</exec>
</target>
Now the master build file can be run without any special arguments and no modifications are required to the ant installation. It's nasty though, since the ftp task runs in a completely clean environment. None of the properties and paths from the master build file are available. Luckily I had all of these in a separate property file anyway, so I only needed a single import.
I would like to add a big thanks to Dan Dyer. Without your extensive explanation of what's going on behind the scenes, I wouldn't have found this solution.
Will this work assuming libs is directly under you project's base directory
<taskdef name="ftp" classname="org.apache.tools.ant.taskdefs.optional.net.FTP">
<classpath>
<pathelement location="${basedir}\libs\commons-net-1.4.0.jar"/>
</classpath>
</taskdef>
Your users all have ant installed on their machines but you can't / don't want to make them add the FTP jar? Can you bundle ant with your project make tasks that call YOUR ant bundle, with the jars placed so it'll work as follows?
<taskdef name="ftp" classname="org.apache.tools.ant.taskdefs.optional.net.FTP">
<classpath>
<pathelement location="\lib\commons-net-1.4.0.jar"/>
</classpath>
</taskdef>
<target name="testFtp">
<ftp server="blah" userid="foo" password="bar">
<fileset file="test.file" />
</ftp>
</target>

Resources