ANT task to move and rename, files and folders, recursively - java

I have have a folder structure like so:
/PROJECT/PROJECT.html
/PROJECT/PROJECT_readme.txt
/PROJECT/PROJECT.css
/PROJECT/PROJECT.js
/PROJECT/abc_PROJECT_def.txt
/PROJECT/something.js
/PROJECT/other.txt
/PROJECT/somefolder/PROJECT_other.txt
I want to use ANT to copy the complete directory and also change the PROJECT string in the files or folder to a specified value e.g. mysuperproject, so the result folder structure is so :
/mysuperproject/mysuperproject.html
/mysuperproject/mysuperproject_readme.txt
/mysuperproject/mysuperproject.css
/mysuperproject/mysuperproject.js
/mysuperproject/abc_mysuperproject_def.txt
/mysuperproject/something.js
/mysuperproject/other.txt
/mysuperproject/somefolder/mysuperproject_other.txt
Is there a easy way to do that in ANT ?

The Move task should suit you. Read the linked docs carefully.
It's a core task, so you can use it without downloading of configuring anything.

I have a similar requirement. This is what I did:
<target name="move-and-rename" description="Move and Rename">
<copy todir="${toDir}" verbose="true" overwrite="true">
<fileset dir="${fromDir}" includes="**" />
<regexpmapper from="(.*)${fromName}(.*)" to="\1${toName}\2"/>
</copy>
</target>
Invoke on command line as
ant move-and-rename -DfromName=project -DtoName=xxxproject -DfromDir=. -DtoDir=proj2
Hope it helps somebody else.

Related

Ant Better way to <sleep> instead of skipping it

I am adding more than 20 files to a fileset with various includes and excludes file. This takes a bit so the dependent task on Ant fileset is skipped by Ant. It wont run the dependent operation at all. This is inefficient. Does anyone know a better way to make the fileset to add files and then perform dependent instead of skipping it?
A way to do that is to use sleep https://ant.apache.org/manual/Tasks/sleep.html. I cannot use waitfor.
Example:
<fileset id="scr" dir="dir1/*" casesensitive="yes"
includes="bin/*, lib/* excludes="dir1/*.py />
<foreach param="file" in="scr">
<echo message="${file}"/>
</foreach>
</fileset>
The above example will skip printing the file name completely since Ant is still adding files to fileset.
The foreach task is not part of ANT, it is a 3rd party extension and I'm not entirely certain it's designed to work the way you think.
Instead could I suggest you print your fileset contents as follows:
<apply executable="echo">
<fileset dir="dir1/*" casesensitive="yes" includes="bin/*, lib/* excludes="dir1/*.py />
</apply>
Or like this if you want to use a fileset reference:
<fileset id="scr" dir="dir1/*" casesensitive="yes" includes="bin/*, lib/* excludes="dir1/*.py />
<apply executable="echo">
<fileset refid="scr"/>
</apply>
Note:
Ant is not a programming language so looping is not fun. If you need complex logic I highly recommend embedding a scripting language. I don't recommend ant-contrib

Building either a Swing and Android app from the same code base using Ant

Based on suggestions from my previous question on programmers.SE, I have split my current project into three subdirectories (swing, common, and android) and created separate Ant scripts in each one. Now I easily created NetBeans projects in the swing and common and was able to set the proper dependencies to compile the Swing app. Then when I go to use classes from the "common" project, I realize that I need to have another Ant script for the Android build process.
So now I have four Ant scripts used to build different parts of my project, along with separate src, test, and other supporting directories for each project. The first problem I encountered is that both NetBeans and the ant script for my "android" project want to use "build.xml" in my "common" project for various build tasks, some of which have name clashes. I decided I want to consolidate all of these projects back into one directory with src, test, etc. subdirectories. The source code is already organized into separate packages for each of the projects and I thought this would make it simpler since I can have a single Ant build script with separate tragets for the Swing and Android builds.
Now the problem I am running into is that when I try to build the "android" project, it wants to build all the Swing classes as well. This brings up a lot of compiler errors. I have even modified the <javac> task in an attempt to exclude the bbct.swing package hierarchy from compileing:
<javac encoding="${java.encoding}"
source="${java.source}" target="${java.target}"
debug="true" extdirs="" includeantruntime="false"
destdir="${out.classes.absolute.dir}"
bootclasspathref="project.target.class.path"
verbose="${verbose}"
classpathref="project.javac.classpath"
fork="${need.javac.fork}"
excludes="${source.dir}/bbct/swing/**"> <------- here
<src path="${source.absolute.dir}" />
<src path="${gen.absolute.dir}" />
<compilerarg line="${java.compilerargs}" />
</javac>
Ant still insists on compiling my classes which use Swing, though.
So I have two questions:
What is the best way to organize this project? Would you suggest one of the two that I have tried or something else entirely?
If I stick with my most recent solution, how do I make javac ignore the Swing-based source files in my project?
Between How to exclude a source package using javac in Ant? and How can I exclude sources in a javac task in ant?, I found a solution using an <exclude> elements, rather than the excludes attribute. Here is the relevant <javac> task:
<javac encoding="${java.encoding}"
source="${java.source}" target="${java.target}"
debug="true" extdirs="" includeantruntime="false"
destdir="${out.classes.absolute.dir}"
bootclasspathref="project.target.class.path"
verbose="${verbose}"
classpathref="project.javac.classpath"
fork="${need.javac.fork}">
<src path="${source.absolute.dir}" />
<exclude name="bbct/swing/**" />
<src path="${gen.absolute.dir}" />
<compilerarg line="${java.compilerargs}" />
</javac>
Addendum:
I suspect that the core of this solution lies in using a path relative to the source attribute or the <src> element. This means that an excludes element should work just as well using a relative path. I haven't tested this yet, though.

Ant start target after

In my ant script, I have target, which zipped a project. How can I start another target after this target finished?
Thanks a lot!
Let's assume the target you have is zip-project and the next target you want to execute is next-target-for-something
One way of doing this is using antcall
<target name="zip-project">
<!-- Your Zipping Task-->
<antcall target="next-target-for-something"/>
</target>
Remember antcall can be invoked inside a target only
Another way of doing this is using depends
You would have something like:
<target name="zip-project" >
<!-- Your Zipping Task-->
</target>
Now define the next task as
<target name="next-target-for-something" depends="zip-project" >
<!-- Your Next Task-->
</target>
though this works in opposite manner of what you would have asked. So you need to call the ant like...
ant -buildfile <build.xml> next-target-for-something
and it will make sure that first zip-project is completed and then next-target-for-something will be executed.
Hope this helps!!
You can use depencencies to achive this. Here is an example:
<target name="nextstep" depends="target">
[Do what ever ...]
</target>
This will run after target has been finished if you run "ant nextstep".

use system classpath for ant javac task

I want the javac task to use jars from the system classpath, by which I mean the classpath that is set in the shell's environment before ant is started. That classpath is
CLASSPATH=D:\local\lib\java\*;.;C:\lib\java\*;C:\lib\java\db\*
on my system. I have popular jars there that are used by many projects. The basic snippet I use in the build file is
<target name="build">
<mkdir dir="${obj}" />
<javac srcdir="${src}" destdir="${obj}"
includes="**/*.java"
excludes="**/package-info.java **/deprecated/*.java"
includeAntRuntime="no" debug="true" debuglevel="source,lines"
>
<compilerarg value="-Xlint"/>
</javac>
</target>
That way ant only passes the output directory as classpath.
[javac] '-classpath'
[javac] 'D:\dev\tbull-projects\jsonc\obj'
(jsonc is the project I'm working on, and D:\dev\tbull-projects\jsonc is the working directory.)
I browsed the documentation for a while and came up with two attempts. First one was adding the attribute classpath="${java.class.path}" to the javac tag. That would pass a tremendously long classpath to the compiler, listing every single jar from ant's own lib directory and finally tools.jar from the JDK. Not the classpath that I wanted.
The second shot was setting
<property name="build.sysclasspath" value="first" />
before javac was invoked, and that got me in the right direction. Now these lines were among the output:
dropping D:\dev\tbull-projects\jsonc\D:\local\lib\java\* from path as it doesn't exist
dropping D:\dev\tbull-projects\jsonc\C:\lib\java\* from path as it doesn't exist
dropping D:\dev\tbull-projects\jsonc\C:\lib\java\db\* from path as it doesn't exist
dropping D:\dev\tbull-projects\jsonc\C:\Program Files\Java\jdk1.6.0_18\jre\lib\sunrsasign.jar from path as it doesn't exist
dropping D:\dev\tbull-projects\jsonc\C:\Program Files\Java\jdk1.6.0_18\jre\classes from path as it doesn't exist
Well, you can imagine that these paths really don't exist. I just don't get why ant constructed them this way. It would know how to do path arithmetic on Windows, would it?
Maybe my approach is flawed more fundamentally, so I'll let you know what I'm actually after. So I'm developing this project (a library), which uses another library. The project is gonna be open source, so I want other developers to be able to build it after they have downloaded the dependency library and placed it somewhere in their classpath.
From what I saw in other questions about ant+classpath, it appears that it's a custom fashion to distribute the dependency libs with the source code (so the classpath can be just like ./libs). But I surely don't want to have jars in my git repo. So how could that be done?
Set includeJavaRuntime=true in javac task.
<target name="build">
<mkdir dir="${obj}" />
<javac srcdir="${src}" destdir="${obj}"
includes="**/*.java"
excludes="**/package-info.java **/deprecated/*.java"
includeAntRuntime="no" includeJavaRuntime="true"
debug="true" debuglevel="source,lines">
<compilerarg value="-Xlint"/>
</javac>
</target>
Why wouldn't you set CLASSPATH in Ant? It's perfectly suited to do just that. You're making a mistake if you do anything else. Not only will it work, bu your build.xml will document the requirements as well.
When javac compiles the code , it tries to find the files in rt.jar in a symbol file called ct.sym (which is also present in lib directory). some files are missing in this symbol file.
i have to add a compile option to ignore symbol file and look directly in rt.jar.
so i have used this option -XDignore.symbol.file for ant i put this value in javac tag. it works perfectly if you use eclipse or any other ide .
<compilerarg value="-XDignore.symbol.file"/>
So , whenever you get ClassNotFoundException in using classes from rt.jar , and if the class is still present there , just try to add this argument in java compiler
To reference rt.jar from ant you may use:
<fileset dir="${java.home}/lib" includes="rt.jar"/>
Original details were found here: http://www.javaroots.com/2013/01/javac-error-using-classes-from-rtjar.html
If someone is new to java/ANT world, people who suggest maven are idiots
whatever happened to KISS principle?
OP, instead of using javascript abomination try this
<project default="build">
<property name="src" value="src" />
<property name="obj" value="obj" />
<property name="parent.dir" value="/jakarta-tomcat/common/lib" />
<path id="project.class.path">
<pathelement location="lib/" />
<fileset dir="${parent.dir}" includes="**/*.jar" />
</path>
<target name="build">
<delete dir="${obj}" />
<mkdir dir="${obj}" />
<javac srcdir="${src}" destdir="${obj}" includes="**/*.java" excludes="**/package-info.java **/deprecated/*.java" debug="true" debuglevel="source,lines" classpathref="project.class.path" />
</target>
It's pretty clear the folks behind java, and (or at least), ant, really really really don't want to see $CLASSPATH end up as storage for user installed libraries of the sort that 95% of other mainstream languages (C/C++, perl, python, ruby, etc. etc.) use. So this is a tough paradigm to swallow if you are used to general programming in most other mainstream languages.
The disinclination goes so far that it is obvious ant intentionally strips $CLASSPATH out of the environment, but an easy way around this is to just use a different variable.
<property name="classpath" location="${env.JAVALIBPATH}"/>
This will then work, no fuss, with both <javac> and <java> commands (classpath="${classpath}) which is good, because if you try this instead:
<property name="classpath" location="${env.CLASSPATH}"/>
There is no includeAntRuntime="false" option to <java> which would allow this to work. You simply cannot get $CLASSPATH in and someone has gone to lengths to make sure of it (without, apparently, and yikes, adding in a ponderous javascript hack).
Of course that means you need to use a separate env variable and for your distributed/production version stick to the Java "Sorry no user libs!" paradigm. That's not a big problem if you use a variable name that, if it becomes involved, will almost certainly be undefined on the target system.
Alternatively, there are the Maven Ant Tasks. These will allow you to use Maven's dependency mechanism in a way that, IMO, is cleaner than Ivy. But it's still not a great solution.
Soo... seems I have to answer the question myself. Passing the original classpath to the javac task can be achieved with this:
<!-- load environment into the env property -->
<property environment="env" />
<javac srcdir="${src}" destdir="${obj}"
includes="**/*.java"
excludes="**/package-info.java **/deprecated/*.java"
includeAntRuntime="no" includeJavaRuntime="no"
debug="true" debuglevel="source,lines"
>
<!-- add -classpath option manually -->
<compilerarg value="-classpath" />
<compilerarg value="${env.CLASSPATH}" />
<compilerarg value="-Xlint"/>
</javac>
That does the trick at least so far that the javac task now gets passed the correct classpath. Yet it will still not work, javac now spits these complaints:
[javac] warning: [path] bad path element "D:\local\lib\java\*": no such file or directory
[javac] warning: [path] bad path element "C:\lib\java\*": no such file or directory
[javac] warning: [path] bad path element "C:\lib\java\db\*": no such file or directory
This is a straight lie, these paths do very much exist. I use them all the time, and if I manually craft an equivalent javac invocation at the shell, it works like a charm. I suspect ant's javac doesn't resolve the jar files in those directories. I have to examine that.
UPDATE
It is indeed as I suspected, the wildcard is not resolved to the individual present jar files by the javac task. I managed to do the resolving manually, and now it works as it should. And that resolving was in fact a struggle on its own. So I'll leave the solution here for those poor souls fighting the same stupidity, hopefully before they ask people that have nothing else to do than bullshitting around (yes Anon, talking about you).
Turns out, ant lacks the most basic functionality that you would expect from a build tool. Also turns out that I'm not the first one to notice that. While solutions are rare, there is a very good post about Using JavaScript to make Apache Ant less painful, which really saved my day. Yes, ant can indeed be scripted, which seems not to be widely known, although it is not kept secret. You can safely assume, that Javascript is already available without installing additional libraries if you run ant on Java 6.
Soo... down to business. Here is the thing:
<target name="expand_classpath">
<script language="javascript"><![CDATA[
// the original classpath
var ocp = java.lang.System.getenv("CLASSPATH");
// ... split in parts
var ocp_parts = ocp.split(project.getProperty("path.separator"));
// where our individual jar filenames go,
// together with pure directories from ocp_parts
var expanded_parts = [ ];
for each (var part in ocp_parts) {
if (part.endsWith('*')) {
var dir = part.substring(0, part.length() - 1);
var f = new java.io.File(dir);
// don't know how to construct a java.io.FilenameFilter,
// therefore filter the filenames manually
for each (var file in f.listFiles())
if (file.getPath().endsWith('.jar'))
expanded_parts.push(file.getPath());
} else
expanded_parts.push(part);
}
var expanded = expanded_parts.join(project.getProperty("path.separator"));
project.setProperty("classpath.expanded", expanded);
]]></script>
<!-- <echo message="classpath.expanded = ${classpath.expanded}" /> -->
</target>
<target name="build" depends="expand_classpath">
<mkdir dir="${obj}" />
<javac srcdir="${src}" destdir="${obj}"
classpath="${classpath.expanded}"
includes="**/*.java"
excludes="**/package-info.java **/deprecated/*.java"
includeAntRuntime="no" includeJavaRuntime="no"
debug="true" debuglevel="source,lines"
>
<compilerarg value="-Xlint"/>
<compilerarg value="-Xlint:-fallthrough"/>
</javac>
</target>
I will assume that your "popular" JARs are well-known open-source projects. This means that they're available in the Maven central repository.
While I believe that using Maven is the best answer to this question, you can also hack something using Ant's <get> task. For example, to download the JUnit JAR (may have typos):
<property name="dependency.dir" value="${basedir}/dependencies"/>
<property name="junit.jar" value="junit-4.8.2.jar"/>
<property name="junit.url" value="http://search.maven.org/remotecontent?filepath=junit/junit/4.8.2/${junit.jar}"/>
<target name="download.dependencies">
<mkdir dir="${dependency.dir}/>
<get url="${junit.url}" dest="${dependency.dir}/${junit.jar}"/>
</target>
Of course, if you do this then you'll have to carefully configure your build scripts so that you don't do the download with every run. And you'll increase load on the Maven Central repository.

Calling multiple ant targets from ant

From my main build file, I would like to call the same target in multiple other build files. My current solution is to call them separately, like so:
<ant antfile="${lib_src_dir}/mylib1/build.xml" target="build" inheritAll="false"/>
<ant antfile="${lib_src_dir}/mylib2/build.xml" target="build" inheritAll="false"/>
I would like my build file to just call the build target on the build files in all of the subdirectories of ${lib_src_dir}. I know I could use the foreach tasks from ant-contrib, but I'd like to stay away from an external library if possible.
I've tried the following, which didn't work:
<ant antfile="${lib_src_dir}/*/build.xml" target="build" inheritAll="false"/>
You want the subant task.
Here's what I ended up with, using the subant task:
<subant target="clean">
<fileset dir="${lib_src_dir}" includes="*/build.xml" />
</subant>

Categories