I want to execute shell commands from Maven's pom.xml - maven-2

I want to execute Linux shell commands with Maven. Here is what I tried:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>hostname</executable>
</configuration>
</plugin>

Here's what's been working for me:
<plugin>
<artifactId>exec-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<executions>
<execution><!-- Run our version calculation script -->
<id>Version Calculation</id>
<phase>generate-sources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>${basedir}/scripts/calculate-version.sh</executable>
</configuration>
</execution>
</executions>
</plugin>

The problem here is that I don't know what is expected. With your current setup, invoking the plugin on the command line would just work:
$ mvn exec:exec
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building Q3491937
[INFO] task-segment: [exec:exec]
[INFO] ------------------------------------------------------------------------
[INFO] [exec:exec {execution: default-cli}]
[INFO] laptop
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
...
The global configuration is used, the hostname command is executed (laptop is my hostname). In other words, the plugin works as expected.
Now, if you want a plugin to get executed as part of the build, you have to bind a goal on a specific phase. For example, to bind it on compile:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<id>some-execution</id>
<phase>compile</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>hostname</executable>
</configuration>
</plugin>
And then:
$ mvn compile
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building Q3491937
[INFO] task-segment: [compile]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources {execution: default-resources}]
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/pascal/Projects/Q3491937/src/main/resources
[INFO] [compiler:compile {execution: default-compile}]
[INFO] Nothing to compile - all classes are up to date
[INFO] [exec:exec {execution: some-execution}]
[INFO] laptop
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
...
Note that you can specify a configuration inside an execution.

Solved. The problem is, executable is working in a different way in Linux. If you want to run an .sh file, you should add the exec-maven-plugin to the <plugins> section of your pom.xml file.
<plugin>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<groupId>org.codehaus.mojo</groupId>
<executions>
<execution>
<!-- Run our version calculation script -->
<id>Renaming build artifacts</id>
<phase>package</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>bash</executable>
<commandlineArgs>handleResultJars.sh</commandlineArgs>
</configuration>
</execution>
</executions>
</plugin>

2 Options:
You want to exec a command from maven without binding to any phase, you just type the command and maven runs it, you just want to maven to run something, you don't care if we are in compile/package/... Let's say I want to run npm start with maven, you can achieve it with the below:
mvn exec:exec -Pstart-node
For that you need the below maven section
<profiles>
<profile>
<id>start-node</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.2</version>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>npm</executable>
<arguments><argument>start</argument></arguments>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
You want to run an arbitrary command from maven while you are at a specific phase, for example when I'm at install phase I want to run npm install you can do that with:
mvn install
And for that to work you would need the below section:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.2</version>
<executions>
<execution>
<id>npm install (initialize)</id>
<goals>
<goal>exec</goal>
</goals>
<phase>initialize</phase>
<configuration>
<executable>npm</executable>
<arguments>
<argument>install</argument>
</arguments>
</configuration>
</execution>

Thanks! Tomer Ben David. it helped me. as I am doing pip install in demo folder as you mentioned npm install
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.2</version>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>pip</executable>
<arguments><argument>install</argument></arguments>
<workingDirectory>${project.build.directory}/Demo</workingDirectory>
</configuration>

This worked for me too. Later, I ended-up switching to the maven-antrun-plugin to avoid warnings in Eclipse. And I prefer using default plugins when possible. Example:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>get-the-hostname</id>
<phase>package</phase>
<configuration>
<target>
<exec executable="bash">
<arg value="-c"/>
<arg value="hostname"/>
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>

The accepted answer does not work in 2021 with version 3.0.0. The configuration tag inside the execution tag results in a message, "The parameter 'exectuable' is missing or invalid."
The solution was to move the configuration tag outside the executions tag.
<plugin>
<artifactId>exec-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<id>Version Calculation</id>
<executable>${basedir}/scripts/calculate-version.sh</executable>
</configuration>
</plugin>

Related

Maven Jarsigning using keystore

Have found maven to use hard for simple things like jar-signing..May be I am doing this in wrong way,Correct me.
I have genereated a keystore file and it is located in my src/main/keystore/mykey.keystore...
My POM looks like :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
<configuration>
<keystore>src/main/keystore/mykey.keystore</keystore>
<alias>aliasname</alias>
<storepass>password</storepass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
</executions>
</plugin>
when i run mvn:install ..
Executing: cmd.exe /X /C ""C:\Program Files (x86)\Java\jdk1.6.0\jre\..
\bin\jarsigner.exe" -verify S:\Test-API\testapplet\target\appletbio-0.0.1-SNAPSHOT.jar"
[info] jar is unsigned. (signatures missing or not parsable)
[INFO] jarsigner: unable to sign jar: java.util.zip.ZipException: duplicate entry:
META-INF/maven/
...
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-jar-plugin:2.3.2:sign
(default) on project
Huh..It was simple..I need to use
<phase>prepare-package</phase>
instead of
<phase>package</phase>
This SO Anwser

How to timestamp an output artifact in Maven?

I am trying to find out if Maven has some built-in plug-in that can be used to time-stamp artifacts. I created an assembly file and am using the maven-assembly plugin to create a final distribution (jars,docs,scripts, etc). I want to name this distribution file as domain_year_month_day.zip. How can I append the day portion of a timestamp to the end of the final zip file that is being produced. Thanks.
You don't need the maven-timestamp-plugin with newer versions of maven. Since 2.1'ish, Maven has provide the special property maven.build.timestamp.
You set the format in the pom properties with something like this:
<maven.build.timestamp.format>yyyy-MM-dd'T'HH.mm.ss</maven.build.timestamp.format>
And then use ${maven.build.timestamp} wherever you need a timestamp property. See http://maven.apache.org/guides/introduction/introduction-to-the-pom.html for details.
You could use the maven-timestamp-plugin to set a property (e.g. timestamp) and use it later in the final name of your assembly.
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>create-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<finalName>domain_${timestamp}</finalName>
<descriptors>
<descriptor>src/main/assembly/my-descriptor.xml</descriptor>
</descriptors>
<attach>true</attach>
</configuration>
</execution>
</executions>
</plugin>
As an alternative, you could put some Groovy code in your POM using the GMaven plugin:
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>set-custom-property</id>
<phase>initialize</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
def timestamp = new Date().format('MM_dd_yy')
project.properties.setProperty('timestamp', timestamp)
</source>
</configuration>
</execution>
<execution><!-- for demonstration purpose -->
<id>show-custom-property</id>
<phase>generate-resources</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
println project.properties['timestamp']
</source>
</configuration>
</execution>
</executions>
</plugin>
A sample output showing the property:
$ mvn generate-resources
[INFO] Scanning for projects...
[INFO]
...
[INFO] --- gmaven-plugin:1.3:execute (set-custom-property) # Q4081274 ---
[INFO]
[INFO] --- gmaven-plugin:1.3:execute (show-custom-property) # Q4081274 ---
11_02_10
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
...
And again, use this property later in the build name of your assembly.
As ${maven.build.timestamp} seems buggy in maven, the workaround is as follows:
Create a new variable (I chose "build.timestamp", here) - and, optionally, specify the format :
pom.xml
<project>
...
<properties>
...
<build.timestamp>${maven.build.timestamp}</build.timestamp>
<maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format>
<!-- default is: yyyyMMdd-HHmm -->
</properties>
<build>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>some-assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make</id>
<phase>package</phase>
<goals>
<goal>assembly</goal>
</goals>
</execution>
</executions>
</plugin>
...
Use the custom variable from anywhere:
some-assembly.xml
<?xml version="1.0"?>
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>release-${build.timestamp}</id>
<baseDirectory>/</baseDirectory>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>${project.build.directory}/${project.artifactId}-${project.version}</directory>
</fileSet>
</fileSets>
</assembly>
if you use Hudson/Jenkins you can just use the variable ${BUILD_ID} for getting sort of timestamp to any properties file u want to edit.
information to the other environment variables Hudson/Jenkins supports, take a look here:
http://wiki.hudson-ci.org/display/HUDSON/Building+a+software+project

Parent properties inside maven antrun plugin

There is a multi-module project. Inside the child I need to do some complicated stuff (integration test with deploying to application server and so on). So there is an integrationtest child, and from this module I need the root of the parent to reach other modules. I do not want to use "..". There is a property in integrationtest POM:
<properties>
<main.basedir>${project.parent.basedir}</main.basedir>
...
</properties>
And there is an antrun plugin with the following content:
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>render-parameter-sql</id>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echoproperties/>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
In the output, the main.basedir is not resolved:
main:
[echoproperties] #Ant properties
[echoproperties] #Thu Oct 28 09:32:13 CEST 2010
[echoproperties] ant.core.lib=C\:\\Users\\gaborl\\.m2\\repository\\org\\apache\\ant\\ant\\1.8.1\\ant-1.8.1.jar
...
[echoproperties] main.basedir=${project.parent.basedir}
[echoproperties] maven.dependency.antlr.antlr.jar.path=C\:\\Users\\gaborl\\.m2\\repository\\antlr\\antlr\\2.7.6\\antlr-2.7.6.jar
After becoming really angry I decided to ask you how to get around this...
I don't know exactly why the ${project.parent.basedir} is not "available" from AntRun, maybe it's just not supported (see http://jira.codehaus.org/browse/MNG-3597).
Here is an horrible workaround using gmaven:
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>set-custom-property</id>
<phase>validate</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
project.properties.setProperty('main.basedir', project.parent.basedir.toString())
</source>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>render-parameter-sql</id>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<echo>project.artifactId : ${project.artifactId}</echo>
<echo>project.parent.basedir : ${project.parent.basedir}</echo>
<echo>main.basedir : ${main.basedir}</echo>
<echo>project.basedir : ${project.basedir}</echo>
<echo>project.build.directory : ${project.build.directory}</echo>
</target>
</configuration>
</execution>
</executions>
</plugin>
I'm not proud of it, but it kinda "works" (if a string representation of the path to the parent basedir is ok for you):
$ mvn validate
[INFO] Scanning for projects...
...
[INFO] --- maven-antrun-plugin:1.6:run (render-parameter-sql) # Q4040778 ---
[INFO] Executing tasks
main:
[echo] project.artifactId : Q4040778
[echo] project.parent.basedir : ${project.parent.basedir}
[echo] main.basedir : /home/pascal/Projects/stackoverflow
[echo] project.basedir : /home/pascal/Projects/stackoverflow/Q4040778
[echo] project.build.directory : /home/pascal/Projects/stackoverflow/Q4040778/target
[INFO] Executed tasks
...
But I need to say that what you want to do (from this module I need the root of the parent to reach other modules) is a bad practice, modules should be self contained and not tightly coupled.
I do not recommend using what I posted :)

Execute Ant task with Maven

I'm trying to execute with Maven some test written using Ant tasks. I generated the files required to import the task into Maven, but I can't execute them.
My POM is defined this way:
<build>
<plugins>
<plugin>
<artifactId>maven-ant-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>generate-sources</phase>
<configuration>
<tasks>
<echo message="Hello, maven"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
I try to execute that message, but I get an error with run:
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] 'run' was specified in an execution, but not found in the plugin
But, if I run: "mvn antrun:run", I know that this can not run the task.
An if I've different targets, how do I call them from Maven? I've the pom.xml, and build.xml with the ant tasks.
Thanks.
Gonzalo
To run Ant tasks from within Maven 2, you need to use the Maven AntRun Plugin:
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
<configuration>
<tasks>
<echo message="Hello, maven"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
The Maven Ant Plugin is something else, it is used to generate build files for Ant from the POM.
Try this one..This will be on the validate phase.
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo message="Hello world" />
<echo message="${env.M2_HOME}" ></echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>

How to get Maven to run war:exploded but not war:war

I have a Maven pom that uses <packaging>war</packaging>. But actually, I don't want build the war-file, I just want all the dependent jars collected and a full deployment directory created.
So I'm running the war:exploded goal to generate the deploy directory:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<configuration>
<webappDirectory>target/${env}/deploy</webappDirectory>
<archiveClasses>true</archiveClasses>
</configuration>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
</plugin>
The trouble is, the war file still gets built. Is there a simple way of having <packaging>war</packaging> execute the war:exploded goal instead of the war:war goal?
Or is there another simple way to do this?
The solution is quite simple. You need to override the default execution of the war plugin to disable it and add your own execution (for exploded):
<pluginManagement>
<plugins>
<plugin><!-- don't pack the war -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<executions>
<execution>
<id>default-war</id>
<phase>none</phase>
</execution>
<execution>
<id>war-exploded</id>
<phase>package</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
According builtin lifecycle bindings for war packaging in package phase war:war mojo is called.
You can call previous 'prepare-package' phase - all actions will be performed and after that call mojo war:exploded
mvn prepare-package war:exploded
The results will be the same as yours but no war created.
I would like to upgrade onto #Michael Wyraz answer and just include install skip settings in case if someone executes mvn clean install build on top level of multimodule project and one of sub-module is web application.
This stands inside war module:
<profiles>
<profile>
<id>war_explode</id>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>default-war</id>
<phase>none</phase>
</execution>
<execution>
<id>war-exploded</id>
<phase>package</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<executions>
<execution>
<id>default-install</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>
Without install skip build fails as it tries to install war into .m2 folder. Error message looks like this:
[INFO] --- maven-install-plugin:2.4:install (default-install) # *** ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-install-plugin:2.4:install (default-install) on project ***: The packaging for this project did not assign a file to the build artifact -> [Help 1]
Executing mvn clean install -P war_explode with this settings (enclosed in maven profile named war_explode) it finishes build without error.
The only way I can think of to do what you want is to set use pom packaging (or create a custom packaging) and bind the required goals from the war packaging to the relevant phases of the lifecycle. If you go for pom packaging you can use define the war:war execution in a profile to allow you to package it, but you'll need to use the build-helper-maven-plugin attach-artifact goal to attach the war to the pom.
Note with this approach if you want to use any other war-specific processing it may cause you problems.
The lifecycle bindings for war packaging are listed in the Introduction to The Build Lifecycle (see the "Default Lifecycle Bindings - Packaging ejb / ejb3 / jar / par / rar / war" section).
To bind the relevant plugin executions to the pom packaging you would do as follows:
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>process-resources</id>
<phase>process-resources</phase>
<goals>
<goal>resources</goal>
</goal>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compile-plugin</artifactId>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goal>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>process-test-resources</id>
<phase>process-test-resources</phase>
<goals>
<goal>testResources</goal>
</goal>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goal>
</execution>
</executions>
</plugin>
<!-- package not wanted, install and deploy already defined for pom packaging-->
<!--define war:war execution in a profile in case it is needed-->
As far as I know (I'm still new to maven) this is not possible. The only default lifecycle you can skip is 'test'. In order to get to the deploy you have to package. You can read all about the default lifecycle order of execution here: http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference