maven calls external script on both Linux and Windows platforms - shell

I need to run an external script on both Linux and MS-Windows platforms.
Do I use the right plugin exec-maven-plugin?
Is there a more suitable plugin?
What filename should I put in <executable>....</executable>?
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>compile-jni</id>
<phase>compile</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>./compile-jni</executable>
<workingDirectory>${basedir}/src/main/cpp</workingDirectory>
</configuration>
</execution>
</executions>
</plugin>
I use the same Makefile for both platforms Linux/MS-Windows
My script compile-jni.bat:
call "%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86
bash -c "make"
My script compile-jni.sh:
#!/bin/sh
make
UPDATE:
Two colleagues have suggested alternatives:
Use a variable script.extension
change <executable>./compile-jni${script.extension}</executable> in the pom.xml
and append the variable within the command line mvn compile -Dscript.extention=.bat
or set the Visual Studio environment variables before calling maven:
call "C:\%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86
mvn compile #(the same script 'bash -c "make"' works on both platforms)
But on both solutions, Eclipse users may be stucked... I am still looking for an automatic and elegant solution...

Finally, I mixed the ideas => the <profiles> are used to set an internal variable script.extension depending on the operating system:
<profiles>
<profile>
<id>Windows</id>
<activation>
<os>
<family>Windows</family>
</os>
</activation>
<properties>
<script.extension>.bat</script.extension>
</properties>
</profile>
<profile>
<id>unix</id>
<activation>
<os>
<family>unix</family>
</os>
</activation>
<properties>
<script.extension>.sh</script.extension>
</properties>
</profile>
</profiles>
Then I use the variable to complete the script filename:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>compile-jni</id>
<phase>compile</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>./compile-jni${script.extension}</executable>
</configuration>
</execution>
</executions>
</plugin>
⚠ As noticed by Maksim for maven 3.5.4 move up the section <configuration> as shown below:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<executable>./compile-jni${script.extension}</executable>
</configuration>
<version>1.2.1</version>
<executions>
<execution>
<id>compile-jni</id>
<phase>compile</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
</plugin>
I have moved the working directory from the pom.xml to the shell script. In order to simplify maintenance, the common stuff is moved within this shell scrip. Therefore, the batch file use this shell script:
compile-jni.bat:
call "%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86
bash compile-jni.sh
compile-jni.sh:
#!/bin/sh
cd src/main/cpp
make

An example of running sh script.
This just does a chmod for the sh script. Keep in mind if you have a sh script, you should definitely do a chmod before performing other operations such as running the actual script, so having this as an example, you can do the first <execution> as below and add another <execution> to run your script.
For the batch file, you can have only one <execution> to run your script
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${org.codehaus.mojo.version}</version>
<executions>
<execution>
<id>script-chmod</id>
<phase>install</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>chmod</executable>
<arguments>
<argument>+x</argument>
<argument>yourscript.sh</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
and you would probably want to add a profile depending on which machine you are:
<profiles>
<profile>
<activation>
<os>
<family>!windows</family>
</os>
</activation>
<plugin>
<!-- add your exec-maven-plugin here -->
</plugin>
...
</profile>
</profiles>
Hope this will be a start for what you need

Related

How can I run two gmaven scripts in one pom.xml?

I want to have two scripts run from maven, one of which depends on an environment variable. I'm trying something like this:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
println "My script"
</source>
</configuration>
</execution>
</executions>
</plugin>
</build>
...
<profile>
<activation>
<property>
<name>env.MY_ENV_VAR</name>
<value>runStuff</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
println "My conditional script"
</source>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
When I run "mvn validate" to test this, I get "My script". When I set the env variable and run it again, I get "My conditional script" but not "My script". It seems that if the condition is satisfied and the second one runs, the first one will not.
I want to run the first one unconditionally and the second one only if the env variable is set. I thought of checking the env variable in the script itself but that seems problematic too, according to this question.
I'm new to maven so it's not unlikely there's a simple solution but I'm not seeing it.
I found the answer. Each execution must have a unique ID. If you don't specify an ID, you get 'default' for both. Once I gave the conditional one a non-default ID, they both run.
<build>
<plugins>
<plugin>
...
<executions>
<execution>
<id>Unconditional-script</id>
...
</execution>
</executions>
</plugin>
</build>
...
<profile>
...
<build>
<plugins>
<plugin>
...
<executions>
<execution>
<id>Conditional-script</id>
...
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>

Maven: How to print the current profile on the console?

I'm trying to print the current profile that is active running a build of a Maven Project.
I'm using the maven-antrun-plugin in order to print messages on the console, in combination with a property that refers to the current profile.
I have tried the following properties:
${project.activeProfiles[0].id}
${project.profiles[0].id}
But in both cases it prints the "string" as it is written, without resolving the variable.
This is my test:
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>current active profile: ${project.activeProfiles[0].id}</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
But this is the result that I obtain:
main:
[echo] current active profile: ${project.activeProfiles[0].id}
Any suggestion will be appreciated.
Thanks.
The maven-help-plugin offers what you need. It has an active-profiles goal.
You can add it to your pom or even call it from the command line (include it in your maven build call). The How can I tell which profiles are in effect during a build? section of the Maven profile introduction page will show you how. In short:
mvn help:active-profiles
As this does not work for you (see comments) here is another solution:
I think the active profiles (there can be more than one!) are not propagated as available variables - but properties are.
So set a custom property in the profile section and use that, like
<profiles>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<myProfile>default</myProfile>
</properties>
</profile>
<profile>
<id>debug</id>
<activation>
<property>
<name>debug</name>
</property>
</activation>
<properties>
<myProfile>debug</myProfile>
</properties>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>current active profile: ${myProfile}</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
you can add the maven-help-plugin in your pom to display always the active profile
<build>
<plugins>
<!-- display active profile in compile phase -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-help-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>show-profiles</id>
<phase>compile</phase>
<goals>
<goal>active-profiles</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
source: https://www.mkyong.com/maven/maven-profiles-example

Maven not detecting existing file

I'm writing a pom file to conditionally checkout or update a subdirectory from git. However, it always does a clean checkout. I'm doing this to wrap CI scripts around existing projects without having to change them.
Here's the code (slightly censored, and with the update ommitted):
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>standard-php-project</artifactId>
<version>1.0</version>
<properties>
<git.project>Test/Project</git.project>
<git.project.checkout.directory>${basedir}/src/php/main/${git.project}</git.project.checkout.directory>
<git.project.checkout.exists.file>${git.project.checkout.directory}/.git/index</git.project.checkout.exists.file>
</properties>
<scm>
<connection>scm:git:ssh://server/git/${git.project}</connection>
</scm>
<profiles>
<profile>
<id>scm-checkout</id>
<activation>
<file>
<missing>${git.project.checkout.exists.file}</missing>
</file>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.soebes.maven.plugins</groupId>
<artifactId>maven-echo-plugin</artifactId>
<version>0.1</version>
<executions>
<execution>
<id>echo-missing-file</id>
<phase>generate-sources</phase>
<goals>
<goal>echo</goal>
</goals>
<configuration>
<echos>
<echo>Couldn't find ${git.project.checkout.exists.file}</echo>
</echos>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
<version>1.8.1</version>
<executions>
<execution>
<id>scm-generate-sources-phase</id>
<phase>generate-sources</phase>
<goals>
<goal>checkout</goal>
</goals>
<configuration>
<checkoutDirectory>${git.project.checkout.directory}</checkoutDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<!-- And another profile for when the file exists, not shown for brevity -->
</profiles>
</project>
I've run mvn compile which tells me the file it tests for, done ls -l on the file to verify it exists, and then run again. For some reason, the test fails.
Help!
Profiles are determined prior to applying properties from the pom
<missing>${git.project.checkout.exists.file}</missing> won't work from the value in your pom.xml
If it was provided on commandline then I believe it would work
Otherwise you need to include the value directly
<missing>/src/php/main/Test/Project/.git/index</missing>
See also Maven profile by user defined property

How to "put" maven command line in pom.xml?

How can I "put" a command line parameter to be executed from pom.xml.
For example I have:
mvn clean install -Dmyparameter
And I wish It to be executed from pom.xml instead from command line.
It depends on which phase you need to use the args. It can be done on plugins by changing the configuration parameter.
<pluginManagement>
<plugin>
......
......
<artifactId>maven-release-plugin</artifactId>
<configuration>
<arguments>-Dmaven.test.skip=true -D[other arguments that u need to include]</arguments>
</configuration>
......
......
</plugin> </pluginManagement>
Same way in the sure fire plugin u can skip test and so on!!
You can try to use maven-exec-plugin:
mvn clean install exec:exec -Dexecutable=<absolute path to binary>
Also it can be bound to some phase of lifecycle to be executed in the middle of the build (without explicit call by exec:exec) and defined in profile with activation if property exists to run optionally:
<profiles>
<profile>
<id>exec</id>
<activation>
<property>
<name>executable</name>
</property>
</activation>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>exec</id>
<goals>
<goal>exec</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<executable>${executable}</executable>
</configuration>
</plugin>
</plugins>
</profile>
</profiles>

How can I set a environment variables in Maven per run?

In my project, we've created a Maven module to get the specific JBoss AS and unpacked.
Then all the test cases can be run under this Jboss AS as embedded container.
We're using jboss-ejb3-embedded-standalone to call the embedded container, however, it just find the JBOSS_HOME from environment variables and use that one to run.
Thus we have to update the JBOSS_HOME per mvn install.
I tried to do this in maven by introduce exec-maven-plugin as below:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<executable>env</executable>
<environmentVariables>
<JBOSS_HOME>
C:/Sample/embedded-container/jboss-${version.org.jboss.jbossas}
</JBOSS_HOME>
</environmentVariables>
</configuration>
<executions>
<execution>
<id>resetJbossHome</id>
<phase>integration-test</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
</plugin>
In the output of console, I can see
[INFO] --- exec-maven-plugin:1.2.1:exec (resetJbossHome) # test-embedded ---
....
JBOSS_HOME=C:/Sample/embedded-container/jboss-6.1.0.Final
....
But when launching JBOSS, it's still running the one with origin JBOSS_HOME set.
Besides, I've tried using maven-antrun-plugin too.
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>copyRelease</id>
<phase>pre-integration-test</phase>
<configuration>
<tasks>
<exec executable="env">
<env key="JBOSS_HOME" value="C:/Sample/embedded-container/jboss-${version.org.jboss.jbossas}"/>
</exec>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
It turns out the same.
Am I wrong on the configuration or there're some better way?
Take a look at the Maven profiles.
You can define one profile for testing, one for production, with different properties, such as
<profiles>
<profile>
<id>test</id>
<jboss.home>PATH TO JBOSS TEST INSTANCE</jboss.home>
</profile>
<profile>
<id>prod</id>
<jboss.home>PATH TO JBOSS PROD INSTANCE</jboss.home>
</profile>
</profiles>
And in your exec plugin :
<environmentVariables>
<JBOSS_HOME>
${jboss.home}
</JBOSS_HOME>
</environmentVariables>

Resources