I'm trying to figure out how the DITA Open Toolkit performs DITA to XHTML conversions, and it's difficult since the process is managed by dozens of ant targets spread over multiple ant files.
I need a tool that can provide a visualization of the execution flow plus property dependencies of an ant invocation. VizAnt and Grand only graph target invocations, so I'm looking for something heavier-duty. Ideally, such a tool would identify the order of target invocations, as well as property values live at invocation, and properties, files, directories, classpath entries, etc. that are referenced in the body of a target.
My first thought was to manually graph it all in OmniGraffle, but the complexity quickly became unmanageable. Surely there's something more recent out there?
yWorks Ant Explorer is kind of cool.
Graphical representation of the ANT build targets and dependencies http://www.yworks.com/demos/images/ae1.jpg
Execute code through the GUI explorer of the ANT build file http://www.yworks.com/demos/images/ae3.jpg
Run it by executing the jar file: java -jar antexplorer.jar
It looks like yWorks no longer supports it and have removed it from their website. Links that used to go to Ant Explorer now just take you to their product listing page.
But there appear to be several places that have it available for download:
http://yworks-ant-explorer.software.informer.com/
http://webscripts.softpedia.com/script/Development-Scripts-js/yWorks-Ant-Explorer-29247.html
http://plugins.jetbrains.com/plugin/?idea&id=135
Related
So, at work, I frequently have to create virtually identical ant scripts. Basically the application we provide to our clients is designed to be easily extensible, and we offer a service of designing and creating custom modules for it. Because of the complexity of our application, with lots of cross dependencies, I tend to develop the module within our core dev environment, compile it using IntelliJ, and then run a basic ant script that does the following tasks:
1) Clean build directory
2) Create build directory and directory hierarchy based on package paths.
3) Copy class files (and source files to a separate sources directory).
4) Jar it up.
The thing is, to do this I need to go through the script line by line and change a bunch of property names, so it works for the new use case. I also save all the scripts in case I need to go back to them.
This isn't the worst thing in the world, but I'm always looking for a better way to do things. Hence my idea:
For each specific implementation I would provide an ant script (or other file) of just properties. Key-value pairs, which would have specific prefixes for each key based on what it's used for. I would then want my ant script to run the various tasks, executing each one for the key-value pairs that are appropriate.
For example, copying the class files. I would have a property with a name like "classFile.filePath". I would want the script to call the task for every property it detects that starts with "classFile...".
Honestly, from my current research so far, I'm not confident that this is possible. But... I'm super stubborn, and always looking for new creative options. So, what options do I have? Or are there none?
It's possible to dynamically generate ANT scripts, for example the following does this using an XML input file:
Use pure Ant to search if list of files exists and take action based on condition
Personally I would always try and avoid this level of complexity. Ant is not a programming language.
Looking at what you're trying to achieve it does appear you could benefit from packaging your dependencies as jars and using a Maven repository manager like Nexus or Artifactory for storage. This would simplify each sub-project build. When building projects that depend on these published libraries you can use a dependency management tool like Apache ivy to download them.
Hope that helps your question is fairly broad.
i have this ant build.xml file with 3 targets in it:
target1, target2 and target3.
If the user simply runs ant and not an explicit ant target1 or something like that, i want to prompt the user asking which target he would like to call.
Remember, the user should only be prompted for this only if he doesnt explicitly call a target while running ant
Ant is not a programming language, it's a dependency matrix language. There's a big difference between the two.
In a program language, you can specify the absolute order of sequence. Plus, you have a lot more flexibility in doing things. In Ant, you don't specify the execution order. You specify various short how to build this steps and then specify their dependencies. Ant automatically will figure out the execution order needed.
It's one of the hardest things for developers to learn about Ant. I've seen too many times when developers try to force execution order and end up executing the same set of targets dozens of times over and over. I recently had a build her that took almost 10 minutes to build, and I rewrote the build.xml to produce the same build in under 2 minutes.
You could use <input/> to get the user input, then use <exec> or <java> to execute another Ant process to execute the requested target. However, this breaks the way Ant is suppose to work.
The default target should be the default target that developers would want to execute on a regular basis while they program. It should not clean the build. It should not run 10 minutes of testing. It should compile any changed files, and rebuild the war or jar. That's what I want about 99% of the time. The whole process takes 10 seconds.
I get really, really pissed when someone doesn't understand this. I hate it when I type ant and I get directions on how to execute my build. I get really irritated when the default target cleans out my previous compiles. And, I get filled with the deadly desire to pummel the person who wrote the damn build file with a large blunt object if I am prompted for something. That's because I will run Ant, do something else while the build happens, then come back to that command window when I think the build is done. Nothing makes me angrier to come back to a build only to find out it's sitting there waiting for me to tell it which target.
If you really, really need to do this. Use a shell script called build.sh. Don't futz with the build.xmlto do this because that affects development.
What you really need to do is teach everyone how to use Ant:
Ant will list user executable targets when you type in ant -p. This will list all targets, and their descriptions. If a target doesn't have a description, it won't list it. This is great for internal targets that a user shouldn't execute on their own. (For example, a target that merely does some sort of test to see if another target should execute). To make this work, make sure your targets have descriptions. I get angry when the person who wrote the Ant file puts a description for some minor target that I don't want, but forgets the description of the target I do want (like compile). Don't make David angry. You don't want to make David angry.
Use default target names for your group. That way, I know what targets do what across the entire project instead of one project using BUILD vs. build-programs vs. Compile vs build-my-stuff vs. StuffBuild. We standardized on Maven lifecycle names names. They're documented and there's no arguments or debates.
Do not use <ant/> or <antcall> to enforce build order. Do not divide your build.xml into a dozen separate build.xml programs. All of these probably break Ant's ability to build a target dependency matrix. Besides, many Ant tools that show dependency hierarchy in a build and they can't work across multiple build files.
Do not wrap your builds inside a shell script. If you do this, you're probably not understanding how builds work.
The build should not update any files in my working directory that were checked out by me. It shouldn't polute my working directory with all sorts of build artifacts spread out all over the place. It shouldn't do anything outside of the working directory (except maybe do some sort of deploy, but only when I run the deploy target). In fact, all build processing should take place in a sub-directory INSIDE my working directory. A clean should merely delete this one directory. Sometimes, this is called build, sometimes dist. I usually call it target because I've adopted Maven naming conventions.
Your build script should be a build script. It shouldn't do checkouts or updates -- at least not automatically. I know that if you use CruiseControl as a continuous build process, you have to have update and checkout functionality inside your build.xml. It's one of the reasons I now use Jenkins.
Sorry about this answer not necessarily being the one you're looking for. You didn't really state what you're doing with Ant. If you're doing builds, don't do what you're trying to do. If you're writing some sort of program, use a real programming language and not Ant.
An Ant build should typically finish in under a minute or two, and redoing a build because you changed a file shouldn't take more than 30 seconds. This is important to understand because I want to encourage my developers to build with Ant, and to use the same targets that my Jenkins server uses. That way, they can test out their build the same way my Jenkins server will do the official build.
you may use the input task provided by ant and make it your default target.
<input
message="Please enter Target ID (1,2 or 3):"
validargs="1,2,3"
addproperty="targetID"
/>
Use the value of this property to decide which target to execute.
From the ant documentation:
message : The Message which gets displayed to the user during the build run.
validargs: Comma separated String containing valid input arguments. If set, input task will reject any input not defined here.
You may pass any arguments according to your needs.
addproperty : The name of a property to be created from input.Behaviour is equal to property task which means that existing
properties cannot be overridden.
Being a Maven newbie, I want to know if its possible to use multiple classifiers at once; in my case it would be for generating different jars in a single run. I use this command to build my project:
mvn -Dclassifier=bootstrap package
Logically I would think that this is possible:
mvn -Dclassifier=bootstrap,api package
I am using Maven 3.0.4
Your project seems like a candidate for refactoring into a couple of what Maven calls "modules". This involves splitting the code into separate projects within a single directory tree, where the topmost level is normally a parent or aggregator POM with <packaging>pom</packaging> and a <modules/> list containing the sub-project directory names.
Then, I'd advise putting the API interfaces/exceptions/whatnot into an api/ subdirectory with its own pom.xml, and putting the bootstrap classes into a bootstrap/ subdirectory with its own pom.xml. The top-level pom.xml would then list the modules like this:
<modules>
<module>api</module>
<module>bootstrap</module>
</module>
Once you've refactored the project, you will probably want to add a dependency from the bootstrap module to the api module, since I'm guessing the bootstrap will depend on interfaces/etc. from the api.
Now, you should be able to go into the top level of the directory structure and simply call:
mvn clean install
This approach is good because it forces you to think about how different use cases are supported in your code, and it makes dependency cycles between classes harder to miss.
If you want an example to follow, have a look at one of my github projects: Aprox.
NOTE: If you have many modules dependent on the api module, you might want to list it in the top-level pom.xml in the <dependencyManagement/> section, so you can leave off the version in submodule dependency declarations (see Introduction to the Dependency Mechanism).
UPDATE: Legacy Considerations
If you can't refactor the codebase for legacy reasons, etc. then you basically have two options:
Construct a series of pom.xml files in an empty multimodule structure, and use the build-helper-maven-plugin along with source includes/excludes to fragment the codebase and allocate the classes to different modules out of a single source tree.
Maybe use a plugin like the assembly plugin to carve up the target/classes directory (${project.build.directory}) and allocate classes to the different jars. In this scenario, each assembly descriptor requires an <id/> and by default this value becomes the classifier for that assembly jar. Under this plan, the "main" jar output will still be the monolithic one created by the Maven build. If you don't want this, you can use a separate execution of the assembly plugin, and in the configuration use <appendAssemblyId>false</appendAssemblyId>. If the output of that assembly is a jar, then it will effectively replace the old output from the jar plugin. If you decide to pursue this approach, you might want to read the assembly plugin documents to get as much exposure to different examples as you can.
Also, I should note that in both cases you would be stuck with manipulating the list of things produced by using a set of profiles in the pom in order to turn on/off different parts of the build. I'd highly recommend making the default, un-qualified build one that produces everything. This makes it more likely for things like the release plugin to catch everything you want to release, and up-rev versions, etc. appropriately.
These solutions are usually what I promote as migration steps when you can't refactor the codebase all at once. They are especially useful when migrating from something like an Ant build that produces multiple jars out of a single source tree.
I was trying to perform java compilation using ant 1.8.1. Due to the requirement, I have to compile number of java source folders (containing java files) in a loop. These folder names will be derived from the java project mentioned in the property file. From the loop itself I need to perform java compilation. So I used a macrodef where I am passing all the required parameters for java source compilation. Essentially, I have a main build.xml file from where I am calling build_Compile.xml (responsibility of this is to figure out which Java projects to build and their corresponding source folders and perform compilation in loop for each project). To achieve this I use a macrodef defined in a helper file (Helper.xml) file which contains number of macrodef.
However, when I execute the task, I am getting an error which implies that java src path(being passed as parameter) is not being found properly. What I noticed is the path of the build files (where all my build*.xml files reside) is being appended before the java src directory path(passed as parameter in the macrodef). I printed the parameter being passed to the macrodef which looks as expected. Here is the snippet which I am using for java source compilation -
.....
.....
<javac srcdir="#{srcpath}"
destdir="./Temp/build/classes/"
includeAntRuntime="false"
classpath="${classpath}"
includes="${replacedartefacts}">
</javac>
Sorry for the long story. Appreciate any pointer/guideline. Thanks.
I'm a bit confused by the loop idea. There are two ways I can think about this:
You have a single project, but compiling different source directories depending upon the project.
You have a master build.xml that's calling a bunch of sub projects that contain source folders to compile.
In the first example, each <javac> call depends upon already compiled classfiles. In the second scenario, each set of Java sources you're compiling is independent of the rest
You don't give the error you're getting or the value of #{srcdir} which would help.
I notice you have an includes parameter. This is the list of java files to include. I also notice this is a property. That means this cannot be changed once it is set. Why do you have an includes parameter? How will specifying a particular set of files to compile for ALL project affect what you want to do. Is this some value like *.java? Is this something that will be the same for each set of source directories you're compiling?
Could this be an issue with the ${basedir} property? When you use <ant> or <import>, your ${basedir} is set to the calling program's ${basedir} and not to the ${basedir} in the called programs.
Run Ant with the -d parameter. This will produce hundreds of lines of output, but will show exactly what is going on with each call to <javac>. We can give you more help if you also post the exact error message and maybe a bit more information on how your project is setup.
Talking about loops, take a look at the Ant-Contrib tasks, especially the for task. Also look into the Ant subant task. The <for> task gives you a way to easily loop through a bunch of directory parameters. The <subant> task is made for a master build building sub-projects.
I would like to simplify my main build scripts, and I'd like to have the ability to reuse certain common ant tasks as a library, but I'd also like them to be easily available as a package.
For instance, I've got a task which sets up the Flex environment variables that I need to build a variety of projects. I can (And am currently) include those scripts by relative path from another location in source control. But what I want to do is make a single download-able package that I can grab via Ivy that contains all of these generic tasks.
A jar seems the most natural solution, since this is doable from java (Use the class loader to access the file inside the jar.), but I can't seem to find a "native" way in Ant to just get the xml file.
In short, I want to do:
<import file="some.jar!bootstrap.xml">
But that doesn't work.
Is there someway to do this? Any other suggestions for making a library of ant scripts would be much appreciated as well.
From what I understand you're trying to extract a file containing more ant tasks from your jar and then tell ant to execute the tasks in those extracted files. Since the files are static, you'd probably be better off creating actual java Task definitions in your jar and declaring them in your ant build file. However, if you don't want to do that, you can just use the Unzip ant task to extract the resource out of the jar and onto the file system and then use the Ant task to execute the extracted file.
IIRC there's ongoing work in Ant to support this but it's not supported in any published version.