Maven antrun move not deleting source file - maven

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>

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 regular expression to match file is not working

I have two files test-200-12-30-2990 and test-project-200-12-30-2990 I am unziping it to corresponding folders. Second task is not working. I want to select the file 'test-200-12-30-2990'
Below is the ant build.xml. I am using maven ant plugin inside pom
<mkdir dir="/testdir"/>
<unzip dest="src/main/resources/testdir">
<fileset dir="src/main/resources">
<include name="**/test-project*.zip"/>
</fileset>
</unzip>
</target>
<mkdir dir="/test-projectdir"/>
<unzip dest="src/main/resources/test-projectdir">
<fileset dir="src/main/resources">
<include name="**/test[1-9].zip"/>
</fileset>
</unzip>
</target>
I'm not quite sure how inclusion might work in Maven, but maybe we could solve this problem with a simple expression that you already have, something maybe similar to:
test-[0-9-]+
Then, the include might look like:
test-[0-9-]+\.zip
**/test-[0-9-]+\.zip
If escaping . might be unnecessary, then we can just use:
**/test-[0-9-]+.zip
DEMO
Reference
Include xml files in maven project

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

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.

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.

Apache Ant JAR Task: not finding properties

How exactly should I specify the location of all the properties files inside the ant manifest?
My jar is not working because it can't find the log4j, Spring, etc properties.
These files are all contained within a folder called "server-config" that sits at the same level as the source code, ie:
META-INF
com
server-config
Essentially, I want to know what I need to add to the Class-Path property for the jar to be aware of all these properties files inside the server-config folder.
Here's my current task:
<jar destfile="${root.home}/onejar/build/main/main.jar" basedir="${build.home}">
<manifest>
<attribute name="Class-Path" value=".;server-config" />
</manifest>
<include name="com/mycompany/client/*"/>
<include name="com/mycompany/portable/util/*"/>
<include name="com/mycompany/request/*"/>
<include name="com/mycompany/model/*"/>
<include name="com/mycompany/controller/*"/>
<include name="com/mycompany/helpers/*"/>
<include name="server-config/*"/>
</jar>
I've tried a few things and none of them are working, I keep on getting errors due to the file not being found.
Any help would be greatly appreciated!
You can remove the entire <manifest... part - that's not what the Class-Path manifest attribute does. It's for things external to the JAR.
The line <include name="server-config/*"/> should work - if the server-config directory exists inside your ${build.home} directory. You probably need a task to copy them there - you mention that the source code sits at the same level, but you don't mention where they are compiled to.
An example -
<mkdir dir="${build.dir}/server-config"
<copy todir="${build.dir}/server-config">
<fileset dir="${src.dir}/server-config">
<include name="*"/>
</fileset>
</copy>

Resources