How to override classpath for taskdef when using maven-antrun-plugin - maven

I'm invoking an ant build from within a maven project using the maven-antrun-plugin. The ant build declares a taskdef and I need to set the classpath of the taskdef to be composed of the dependencies associated with the maven-antrun-plugin (i.e. maven.plugin.classpath) as well as some additional resources. I can only get the classpath to be maven.plugin.classpath.
A snippet of my pom.xml
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>test</phase>
<configuration>
<target>
<path id="my.classpath">
<pathelement location="src/test/resources" />
<path refid="maven.plugin.classpath" />
</path>
<property name="my_classpath" refid="my.classpath" />
<property name="plugin_classpath" refid="maven.plugin.classpath"/>
<echo message="my classpath: ${my_classpath}"/>
<echo message="plugin classpath: ${plugin_classpath}"/>
<!-- define the taskdef, specifying the classpathref from above -->
<taskdef name="sqlunit" classname="net.sourceforge.sqlunit.ant.SqlunitTask" classpathref="my.classpath"/>
<!-- invoke the tests -->
<sqlunit>
<fileset dir="src/test/db">
<include name="**/*.xml" />
</fileset>
</sqlunit>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
Inside of SQLUnit, I'm printing out the urls of the classpath:
ClassLoader cl = SQLUnit.class.getClassLoader();
URL[] urls = ((URLClassLoader)cl).getURLs();
for(URL url: urls){
System.out.println(url.getFile());
}
Executing "mvn test", I can see the my.classpath includes src/test/resources:
main:
[echo] my classpath: /Users/szalwinb/playpen/bszalwin/DbDmsApp/src/test/resources:/Users/szalwinb/.m2/repository/org/apache/maven/plugins/maven-antrun-plugin/1.8/maven-antrun-plugin-1.8.jar:/Users/szalwinb/.m2/repository/net/sourceforge/sqlunit/5.0/sqlunit-5.0.jar:/Users/szalwinb/.m2/repository/ant-contrib/ant-contrib/20020829/ant-contrib-20020829.jar:/Users/szalwinb/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar:/Users/szalwinb/.m2/repository/org/jdom/jdom/1.1.3/jdom-1.1.3.jar:/Users/szalwinb/.m2/repository/postgresql/postgresql/8.4-701.jdbc4/postgresql-8.4-701.jdbc4.jar:/Users/szalwinb/.m2/repository/backport-util-concurrent/backport-util-concurrent/3.1/backport-util-concurrent-3.1.jar:/Users/szalwinb/.m2/repository/org/codehaus/plexus/plexus-interpolation/1.11/plexus-interpolation-1.11.jar:/Users/szalwinb/.m2/repository/junit/junit/3.8.1/junit-3.8.1.jar:/Users/szalwinb/.m2/repository/org/codehaus/plexus/plexus-utils/3.0.20/plexus-utils-3.0.20.jar:/Users/szalwinb/.m2/repository/org/apache/ant/ant/1.9.4/ant-1.9.4.jar:/Users/szalwinb/.m2/repository/org/apache/ant/ant-launcher/1.9.4/ant-launcher-1.9.4.jar
[echo] plugin classpath: /Users/szalwinb/.m2/repository/org/apache/maven/plugins/maven-antrun-plugin/1.8/maven-antrun-plugin-1.8.jar:/Users/szalwinb/.m2/repository/net/sourceforge/sqlunit/5.0/sqlunit-5.0.jar:/Users/szalwinb/.m2/repository/ant-contrib/ant-contrib/20020829/ant-contrib-20020829.jar:/Users/szalwinb/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar:/Users/szalwinb/.m2/repository/org/jdom/jdom/1.1.3/jdom-1.1.3.jar:/Users/szalwinb/.m2/repository/postgresql/postgresql/8.4-701.jdbc4/postgresql-8.4-701.jdbc4.jar:/Users/szalwinb/.m2/repository/backport-util-concurrent/backport-util-concurrent/3.1/backport-util-concurrent-3.1.jar:/Users/szalwinb/.m2/repository/org/codehaus/plexus/plexus-interpolation/1.11/plexus-interpolation-1.11.jar:/Users/szalwinb/.m2/repository/junit/junit/3.8.1/junit-3.8.1.jar:/Users/szalwinb/.m2/repository/org/codehaus/plexus/plexus-utils/3.0.20/plexus-utils-3.0.20.jar:/Users/szalwinb/.m2/repository/org/apache/ant/ant/1.9.4/ant-1.9.4.jar:/Users/szalwinb/.m2/repository/org/apache/ant/ant-launcher/1.9.4/ant-launcher-1.9.4.jar
And when sqlunit task is executed, I see that the classpath only contains those artifacts found in maven.plugin.classpath.
/Users/szalwinb/.m2/repository/org/apache/maven/plugins/maven-antrun-plugin/1.8/maven-antrun-plugin-1.8.jar
/Users/szalwinb/.m2/repository/net/sourceforge/sqlunit/5.0/sqlunit-5.0.jar
/Users/szalwinb/.m2/repository/ant-contrib/ant-contrib/20020829/ant-contrib-20020829.jar
/Users/szalwinb/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar
/Users/szalwinb/.m2/repository/org/jdom/jdom/1.1.3/jdom-1.1.3.jar
/Users/szalwinb/.m2/repository/postgresql/postgresql/8.4-701.jdbc4/postgresql-8.4-701.jdbc4.jar
/Users/szalwinb/.m2/repository/backport-util-concurrent/backport-util-concurrent/3.1/backport-util-concurrent-3.1.jar
/Users/szalwinb/.m2/repository/org/codehaus/plexus/plexus-interpolation/1.11/plexus-interpolation-1.11.jar
/Users/szalwinb/.m2/repository/junit/junit/3.8.1/junit-3.8.1.jar
/Users/szalwinb/.m2/repository/org/codehaus/plexus/plexus-utils/3.0.20/plexus-utils-3.0.20.jar
/Users/szalwinb/.m2/repository/org/apache/ant/ant/1.9.4/ant-1.9.4.jar
/Users/szalwinb/.m2/repository/org/apache/ant/ant-launcher/1.9.4/ant-launcher-1.9.4.jar
I looked at the source to AntRunMojo, and I see that is is building an Ant Project and adds maven.plugin.classpath as a reference to the project.
/* set maven.plugin.classpath with plugin dependencies */
antProject.addReference( "maven.plugin.classpath", getPathFromArtifacts( pluginArtifacts, antProject ) );
I think what is happening is that the taskdef is able to resolve its class using the references added to the project, so it ignores the classpathref associated with the taskdef element. To prove out this theory, I removed the classpathref attribute from the taskdef,
<taskdef name="sqlunit" classname="net.sourceforge.sqlunit.ant.SqlunitTask"/>
And the task was still able to resolve its class. And when the classloader printed out its resources, they were the ones defined by maven.plugin.classpath.
===============
I ended up changing the build for SQLUnit so that the log4j.properties file is included in the sqlunit.jar. Everything is happy now.

Related

Use maven-antrun-plugin to unzip a file using ${finalName} or wildcard (or regex)

I'm trying to unzip a .zip - File with a build-timestamp suffix appended using the maven-antrun-plugin. The var "finalName" is set in the effective pom.xml:
<finalName>XXXXXXX-server-5.20.0-SNAPSHOT-2022_11_29_14_45</finalName>
Using plugin version 3.1.0 (also tried 3.0.0 with the same outcome) it fails:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-antrun-plugin:3.1.0:run (Unzip Server) on project XXXXXXX-server: An Ant BuildException has occured: src 'C:\Dev\XXXXXXX-maven\XXXXXXX-server\target\${finalName}' doesn't exist.
[ERROR] around Ant part ...<unzip src="C:\Dev\XXXXXXX-maven\XXXXXXX-server\target/${finalName}" dest="C:/DEV/XXXXXXX/runOnline" />... # 7:99 in C:\Dev\XXXXXXX-maven\XXXXXXX-server\target\antrun\build-main.xml
Problem is clear: the variable finalName is not substituted(aka known).
...
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>Unzip Server</id>
<phase>package</phase>
<configuration>
<target>
<delete dir="${project.exec.directory}" includeemptydirs="true" />
<mkdir dir="${project.exec.directory}" />
<echo message="unzipping Server -${project.exec.directory}" />
<unzip src="${project.build.directory}/${finalname}" dest="${project.exec.directory}" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
...
Same snippet as above using wildcard-operator * does not work either:
<unzip src="${project.build.directory}/*.zip" dest="${project.exec.directory}" />
ends up not finding the *.zip (which actually exists in that directory at antrun execution time):
An Ant BuildException has occured: src 'C:\Dev\XXXXXXX-maven\XXXXXXX-server\target\*.zip' doesn't exist.
Any suggestions without using another plugin/mechanism?
Thank you :-)

Maven antrun move not deleting source file

Developing on Windows 10 I have a Java project in Maven that has a Linux "launcher" shell script for the FooBar utility stored in the repository at src/bin/foobar.sh. It uses resource filtering to substitute in the correct executable JAR path so that what gets built is a foobar.sh script that launches the executable JAR in the same directory.
The POM uses org.apache.maven.plugins:maven-antrun-plugin:1.8 to enable the executable flag on the foobar.sh script in the target/bin directory (which has been already been copied using Maven resource filtering, with that directory path stored in the ${binOutputDirectory} property):
<chmod dir="${binOutputDirectory}" includes="**/*.sh" perm="+x" />
Then it renames the foobar.sh file to simply foobar (i.e. it removes the extension) to follow best practices for shell scripts:
<move todir="${binOutputDirectory}">
<fileset dir="${binOutputDirectory}">
<include name="**/*.sh" />
</fileset>
<mapper type="glob" from="*.sh" to="*" />
</move>
You can see e.g. globalmentor-root pom.xml at c31ae410143f86ebf2bf10467214214d87b2eb61 for the full POM source code. Actual child POMs will simply enable the AntRun operations by providing their executions an appropriate phase like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>set-shell-scripts-executable</id>
<phase>process-resources</phase>
</execution>
<execution>
<id>remove-shell-script-extensions</id>
<phase>process-resources</phase>
</execution>
</executions>
</plugin>
The essential part of that is working fine, and I wind up with a foobar file in my distributable ZIP file, with its executable flag enabled as desired. Unfortunately I also wind up with the original foobar.sh file as well, and I can see in target/bin (where the .sh extension gets removed) that both files are there as well. So it would appear that AntRun <move> is behaving as <copy>.
To see this in action, build the Guise Mummy 0.1.0 project and look in the cli/target/bin directory; you'll see that guise.sh has not been deleted.
To work around the problem, I can add an extraneous <delete> command; this will successfully remove foobar.sh. (The difference in <fileset> syntax is irrelevant; I switched only because it was more concise.)
<move todir="${binOutputDirectory}">
<fileset dir="${binOutputDirectory}" includes="**/*.sh"/>
<mapper type="glob" from="*.sh" to="*" />
</move>
<delete>
<fileset dir="${binOutputDirectory}" includes="**/*.sh"/>
</delete>
Why is AntRun <move> by itself not removing the original target/bin/foobar.sh file after it copies it to target/bin/foobar as part of the move operation?
Upgrading to org.apache.maven.plugins:maven-antrun-plugin:3.1.0 seems to have fixed the problem. When I created this question I had been using v1.8. I can only suppose that org.apache.maven.plugins:maven-antrun-plugin:1.8 is buggy.
Noticed in the pom, within the antrun goals, you are modifying permissions of the .sh script. This does not confirm if the shell script is writeable, it may be read-only:
<execution>
<id>set-shell-scripts-executable</id>
<!--
Enable execute permission for the shell scripts in `${binOutputDirectory}`.
Enable by specifying a phase (e.g. `process-resources`) in child POM.
-->
<phase>none</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<chmod dir="${binOutputDirectory}" includes="**/*.sh" perm="+x" />
</target>
</configuration>
</execution>
Try the following, apply the overwrite attribute, like so:
(overwrite overwrite existing files even if the destination files are newer)
<move todir="${binOutputDirectory}" overwrite="true">
<fileset dir="${binOutputDirectory}">
<include name="**/*.sh" />
</fileset>
<mapper type="glob" from="*.sh" to="*" />
</move>
If that does not work, also add the force attribute, like so:
(force Overwrite read-only destination files)
<move todir="${binOutputDirectory}" overwrite="true" force="true">
<fileset dir="${binOutputDirectory}">
<include name="**/*.sh" />
</fileset>
<mapper type="glob" from="*.sh" to="*" />
</move>

How to convert an ant snippet to Gradle

Hi I am completely new to Gradle. Can anyone please help me as to how I can convert this ant task into Gradle. I am trying to see if I can learn by example.
<property file="build.properties"/>
<path id="classpath">
<fileset dir="${ear.dir}/EarContent/APP-INF">
<include name="**/*.jar" />
</fileset>
</path>
<target name="clean">
<delete file="${dist.dir}/*.jar" failonerror="false"/>
<delete failonerror="false">
<fileset dir="${build.dir}">
<include name="**/*.class" />
</fileset>
</delete>
</target>
<target name="init">
<mkdir dir="${dist.dir}"/>
<mkdir dir="${build.dir}/classes"/>
</target>
<target name="jar" depends="clean, init">
<javac srcdir="${src.dir}" destdir="${build.dir}/classes" debug="on">
<classpath refid="classpath"/>
</javac>
<jar destfile="${dist.dir}/phIntegration.jar">
<fileset dir="${build.dir}/classes" />
</jar>
</target>
I'm not convinced that trying move ANT build 1-1 to Gradle is a good learning exercise, although Gradle provides good integration with ANT.
Generally speaking, the build.gradle file for your project shall like somewhat like that:
apply plugin: 'java'
dependencies {
compile fileTree(dir: 'CLASSPATH_DIR', include: ['**/*.jar'])
//if you want you can use JARS from your filesystem as a classpath
//but you probably should use Ivy or Maven dependency management systems
}
sourceSets {
main {
java 'src/main/java'
//tweak the location of your source code, by default Gradle looks for sources in `src/main/java`
}
}
Once you invoke gradle clean build it will compile your sources and create a jar file containing the sources in build/libs directory. You can change the JARS name by adding the rootProject.name='your project name' in the settings.gradle directory.
The snippet uses Java plugin and the default behaviour of Gradle. If you want you can tweak its behaviour by using Delete Task or Jar Task.
If you define properly inputs/outputs of a task the init task won't be necessary since Gradle will take care of directories recreation if they're not existent. (Default tasks do that, if you start writing your own tasks you most probably will have to take care of that by your own)

Change maven properties using Ant task

I have set a maven property in the pom.xml.
<properties>
<build.start.date>someValue</build.start.date>
</properties>
Now I have an ant task doing the following:
<loadresource property="build.start">
<url url="http://someUrl?xpath=/*/id/text()"/>
</loadresource>
<property name="build.start.date" value="${build.start}"/>
<echo>Printing Ant Value ${build.start} </echo>
<echo>Printing Maven Value ${build.start.date}</echo>
This results in:
[echo] Printing Ant Value 2013-03-15_17-53-08
[echo] Printing Maven Value 2013-03-16
But I am expecting both to print:
[echo] Printing Ant Value 2013-03-15_17-53-08
[echo] Printing Maven Value 2013-03-15_17-53-08
I tried <loadresource property="build.start.date">
and
I tried <loadresource property="${build.start.date}">
So the question is how do I set a global maven property inside ant task?
I found the solution for this one.
First of all you need to have 1.7 version of antrun plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
....
</plugin>
Then under configuration you need to have exportAntProperties to true (false by default):
<configuration>
<exportAntProperties>true</exportAntProperties>

maven -> ant -> jsmoothgen : How to provide -Djava.awt.headless=true?

I have a situation where we wrap a jar with JSmooth to get an suitable exe file.
This has traditionally been built by ant, and as part of our general mavenification the current, short-term solution has been to use maven-antrun-plugin to set a property and invoke ant.
Unfortunately this approach fails when building on Unix (as there is no X11 display available) and the solution is to invoke the JVM with -Djava.awt.headless=true. I would like to do this in my pom.xml but cannot identify where to do this.
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<phase>package</phase>
<configuration>
<target>
<!-- create one-jar and exefy it -->
<property name="maven.project.build.finalName" value="${project.build.finalName}" />
<!-- note: fails on headless Linux for now -->
<ant />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
It is ok to fork a new JVM directly but not to rely on platform specifics.
How can I do this correctly?
As far as I know, the solution without forking JVM is to use MAVEN_OPT
export MAVEN_OPTS="-Djava.awt.headless=true"
Since -D is JVM option, you had to specify it to maven directly. You cannot (once again, from what I know) pass it as internal argument (and there isn't any configuration option that allow it)
So, using MAVEN_OPT parameter become the right way to do it.
EDIT 1:
You can have a glance here using better-maven2-antrun-plugin
http://code.google.com/p/better-maven2-antrun-plugin/wiki/Usage
EDIT 2:
Can can maybe help maven-antrun developpement providing them a way to specify those parameters, like maven-compiler-plugin. This would be the best way if you really want to use pom informations.
The ant manual has a section titled "Running Ant via Java" that shows how to do just what you want. A slightly tweaked version of their example is reproduced below:
<java
classname="org.apache.tools.ant.launch.Launcher"
fork="true"
failonerror="true"
dir="${basedir}"
taskname="headless-ant"
>
<classpath>
<pathelement location="${ant.home}/lib/ant-launcher.jar"/>
</classpath>
<arg value="-buildfile"/>
<arg file="${ant.file}"/>
<arg value="-Dbasedir=${basedir}"/>
<jvmarg value="-Djava.awt.headless=true"/>
</java>
If you put that snippet in place of the <ant> element in your snippet, it should do the trick.

Resources