diff --git a/pom.xml b/pom.xml index b2b968ac..6a021c9e 100644 --- a/pom.xml +++ b/pom.xml @@ -61,6 +61,12 @@ sjaranowski@apache.org Europe/Warsaw + + bmarwell + Benjamin Marwell + bmarwell@apache.org + Europe/Berlin + diff --git a/src/it/projects/mexec-323-force-java/invoker.properties b/src/it/projects/mexec-323-force-java/invoker.properties new file mode 100644 index 00000000..4d112ad0 --- /dev/null +++ b/src/it/projects/mexec-323-force-java/invoker.properties @@ -0,0 +1,3 @@ +invoker.goals = compile +invoker.debug = true +invoker.os.family = !windows diff --git a/src/it/projects/mexec-323-force-java/pom.xml b/src/it/projects/mexec-323-force-java/pom.xml new file mode 100644 index 00000000..31436bc3 --- /dev/null +++ b/src/it/projects/mexec-323-force-java/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + + org.codehaus.mojo.exec.it + parent + 0.1 + + + mexec-323 + 0.0.1-SNAPSHOT + pom + + + + + org.codehaus.mojo + exec-maven-plugin + @pom.version@ + + + compile + + exec + + + echo + true + + -- + -p + dist/emails + + src/build + + + + + + + + diff --git a/src/it/projects/mexec-323-force-java/verify.groovy b/src/it/projects/mexec-323-force-java/verify.groovy new file mode 100644 index 00000000..d58ec658 --- /dev/null +++ b/src/it/projects/mexec-323-force-java/verify.groovy @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +def log = new File( basedir, "build.log" ) +assert log.exists() +// missing dist/emails here +assert log.text.contains( "Executing command line: [echo, --, -p]" ) diff --git a/src/it/projects/mexec-323/invoker.properties b/src/it/projects/mexec-323/invoker.properties new file mode 100644 index 00000000..4d112ad0 --- /dev/null +++ b/src/it/projects/mexec-323/invoker.properties @@ -0,0 +1,3 @@ +invoker.goals = compile +invoker.debug = true +invoker.os.family = !windows diff --git a/src/it/projects/mexec-323/pom.xml b/src/it/projects/mexec-323/pom.xml new file mode 100644 index 00000000..b14d2ed1 --- /dev/null +++ b/src/it/projects/mexec-323/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + + org.codehaus.mojo.exec.it + parent + 0.1 + + + mexec-323 + 0.0.1-SNAPSHOT + pom + + + + + org.codehaus.mojo + exec-maven-plugin + @pom.version@ + + + compile + + exec + + + mkdir + + -p + dist/emails + + src/build + + + + + + + + diff --git a/src/it/projects/mexec-323/verify.groovy b/src/it/projects/mexec-323/verify.groovy new file mode 100644 index 00000000..b2f156ec --- /dev/null +++ b/src/it/projects/mexec-323/verify.groovy @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +def createdDir = new File(basedir, "src/build/dist/emails") +assert createdDir.exists() +assert createdDir.isDirectory() + +File log = new File(basedir, 'build.log') +assert log.exists() +assert log.getText().contains( "Executing command line: [mkdir, -p, dist/emails]" ) diff --git a/src/main/java/org/codehaus/mojo/exec/ExecMojo.java b/src/main/java/org/codehaus/mojo/exec/ExecMojo.java index 76450313..8b4ce310 100644 --- a/src/main/java/org/codehaus/mojo/exec/ExecMojo.java +++ b/src/main/java/org/codehaus/mojo/exec/ExecMojo.java @@ -42,6 +42,7 @@ import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; +import java.util.regex.Pattern; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.ExecuteException; @@ -83,6 +84,12 @@ public class ExecMojo extends AbstractExecMojo { + + /** + * Trying to recognize whether the given {@link #executable} might be a {@code java} binary. + */ + private static final Pattern ENDS_WITH_JAVA = Pattern.compile( "^.*java(\\.exe|\\.bin)?$", Pattern.CASE_INSENSITIVE ); + /** *

* The executable. Can be a full path or the name of the executable. In the latter case, the executable must be in @@ -313,6 +320,18 @@ public class ExecMojo @Parameter( property = "exec.longModulepath", defaultValue = "true" ) private boolean longModulepath; + /** + * Forces the plugin to recognize the given executable as java executable. This helps with {@link #longClasspath} + * and {@link #longModulepath} parameters. + * + *

You shouldn't normally be needing this unless you renamed your java binary or are executing tools + * other than {@code java} which need modulepath or classpath parameters in a separate file.

+ * + * @since 3.1.1 + */ + @Parameter (property = "exec.forceJava", defaultValue = "false" ) + private boolean forceJava; + /** * If set to true the child process executes asynchronously and build execution continues in parallel. */ @@ -727,12 +746,35 @@ boolean isResultCodeAFailure( int result ) private boolean isLongClassPathArgument( String arg ) { - return longClasspath && ( "-classpath".equals( arg ) || "-cp".equals( arg ) ); + return isJavaExec() && longClasspath && ( "-classpath".equals( arg ) || "-cp".equals( arg ) ); } private boolean isLongModulePathArgument( String arg ) { - return longModulepath && ( "--module-path".equals( arg ) || "-p".equals( arg ) ); + return isJavaExec() && longModulepath && ( "--module-path".equals( arg ) || "-p".equals( arg ) ); + } + + /** + * Returns {@code true} when a java binary is being executed. + * + * @return {@code true} when a java binary is being executed. + */ + private boolean isJavaExec() + { + if ( forceJava ) + { + return true; + } + + if ( this.executable.contains( "%JAVA_HOME" ) + || this.executable.contains( "${JAVA_HOME}" ) + || this.executable.contains( "$JAVA_HOME" ) ) + { + // also applies to *most* other tools. + return true; + } + + return ENDS_WITH_JAVA.matcher( this.executable ).matches(); } /** diff --git a/src/test/java/org/codehaus/mojo/exec/ExecMojoTest.java b/src/test/java/org/codehaus/mojo/exec/ExecMojoTest.java index 66ec7c4d..2231c7db 100644 --- a/src/test/java/org/codehaus/mojo/exec/ExecMojoTest.java +++ b/src/test/java/org/codehaus/mojo/exec/ExecMojoTest.java @@ -1,7 +1,6 @@ package org.codehaus.mojo.exec; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static java.util.Collections.emptyMap; /* * Copyright 2005 The Codehaus. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this @@ -15,7 +14,7 @@ import java.io.File; import java.io.IOException; import java.io.OutputStream; -import java.io.PrintStream; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -28,18 +27,9 @@ import org.apache.commons.exec.Executor; import org.apache.commons.exec.OS; import org.apache.maven.execution.MavenSession; -import org.apache.maven.monitor.logging.DefaultLog; import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.logging.SystemStreamLog; import org.apache.maven.plugin.testing.AbstractMojoTestCase; -import org.apache.maven.project.MavenProject; -import org.apache.maven.project.ProjectBuilder; -import org.apache.maven.project.ProjectBuildingRequest; -import org.codehaus.plexus.logging.Logger; -import org.codehaus.plexus.logging.console.ConsoleLogger; -import org.codehaus.plexus.util.StringOutputStream; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; /** * @author Jerome Lacoste @@ -129,145 +119,11 @@ public void testRunOK() * output ); } */ - /** + /* * integration test... - compile the Test class using mvn clean compile - run the test file using java, use it to * generate a file whose contains are compared to expected output */ - // public void testRunOKWithAutoComputedClasspath() - // throws MojoExecutionException, Exception - // { - // String projectName = "project1"; - // - // ExecMojo mojo = new ExecMojo(); - // - // setUpProject( projectName, mojo ); - // - // // compile project - // mojo.setExecutable( SOME_EXECUTABLE ); - // mojo.setWorkingDirectory( new File( "src/test/projects/" + projectName + "/" ) ); - // mojo.setArguments( Arrays.asList( new String[]{"clean", "compile"} ) ); - // - // mojo.execute(); - // - // mojo.getLog().info( "executed mvn clean compile" ); - // - // // the command executes the test class - // mojo.setExecutable( "java" ); - // mojo.setWorkingDirectory( (File) null ); - // Classpath classpath = new Classpath(); - // mojo.setArguments( Arrays.asList( new Object[]{"-Dproject.env1=value1", "-classpath", classpath, - // "org.codehaus.mojo.exec.test.Test", - // new File( "src/test/projects/" + projectName + "/target/exec/output.txt" ).getAbsolutePath(), "arg1", - // "arg2"} ) ); - // - // mojo.execute(); - // - // // checking the command line would involve resolving the repository - // // checkMojo( "java -cp" ); - // - // assertFileEquals( null, getTestFile( "src/test/projects/" + projectName + "/output.txt" ), - // getTestFile( "src/test/projects/" + projectName + "/target/exec/output.txt" ) ); - // - // // the command executes the test class, this time specifying the dependencies - // mojo.setExecutable( "java" ); - // mojo.setWorkingDirectory( (File) null ); - // classpath = new Classpath(); - // List dependencies = new ArrayList(); - // dependencies.add( "commons-io:commons-io" ); - // classpath.setDependencies( dependencies ); - // mojo.setArguments( Arrays.asList( new Object[]{"-Dproject.env1=value1", "-classpath", classpath, - // "org.codehaus.mojo.exec.test.Test", - // new File( "src/test/projects/" + projectName + "/target/exec/output.txt" ).getAbsolutePath(), "arg1", - // "arg2"} ) ); - // - // mojo.execute(); - // - // // checking the command line would involve resolving the repository - // // checkMojo( "java -cp" ); - // - // assertFileEquals( null, getTestFile( "src/test/projects/" + projectName + "/output.txt" ), - // getTestFile( "src/test/projects/" + projectName + "/target/exec/output.txt" ) ); - // } - - /** - * - * @param pom the pom file - * @param goal the goal to execute - * @return output from System.out during mojo execution - * @throws Exception if any exception occurs - */ - protected String execute( File pom, String goal ) - throws Exception - { - - ExecMojo mojo; - mojo = (ExecMojo) lookupMojo( goal, pom ); - - setUpProject( pom, mojo ); - - MavenProject project = (MavenProject) getVariableValueFromObject( mojo, "project" ); - - // why isn't this set up by the harness based on the default-value? TODO get to bottom of this! - // setVariableValueToObject( mojo, "includeProjectDependencies", Boolean.TRUE ); - // setVariableValueToObject( mojo, "killAfter", new Long( -1 ) ); - - assertNotNull( mojo ); - assertNotNull( project ); - - // trap System.out - PrintStream out = System.out; - StringOutputStream stringOutputStream = new StringOutputStream(); - System.setOut( new PrintStream( stringOutputStream ) ); - // ensure we don't log unnecessary stuff which would interfere with assessing success of tests - mojo.setLog( new DefaultLog( new ConsoleLogger( Logger.LEVEL_ERROR, "exec:exec" ) ) ); - - try - { - mojo.execute(); - } - catch ( Throwable e ) - { - e.printStackTrace( System.err ); - fail( e.getMessage() ); - } - finally - { - System.setOut( out ); - } - - return stringOutputStream.toString(); - } - - private void setUpProject( File pomFile, ExecMojo mojo ) - throws Exception - { - super.setUp(); - - MockitoAnnotations.initMocks( this ); - - ProjectBuildingRequest buildingRequest = mock( ProjectBuildingRequest.class ); - when( session.getProjectBuildingRequest() ).thenReturn( buildingRequest ); - - ProjectBuilder builder = lookup( ProjectBuilder.class ); - - mojo.setBasedir( File.createTempFile( "mvn-temp", "txt" ).getParentFile() ); - - MavenProject project = builder.build( pomFile, buildingRequest ).getProject(); - - // this gets the classes for these tests of this mojo (exec plugin) onto the project classpath for the test - project.getBuild().setOutputDirectory( new File( "target/test-classes" ).getAbsolutePath() ); - - mojo.setProject( project ); - - mojo.setLog( new SystemStreamLog() - { - public boolean isDebugEnabled() - { - return true; - } - } ); - } // MEXEC-12, MEXEC-72 public void testGetExecutablePath() @@ -442,6 +298,24 @@ public void testParseCommandlineOSWin() assertEquals( javaHome, args[0] ); } + + public void test_exec_receives_all_parameters() throws MojoExecutionException + { + // given + ExecMojo execMojo = new ExecMojo(); + execMojo.setExecutable( "mkdir" ); + execMojo.setArguments( Arrays.asList( "-p", "dist/mails" ) ); + execMojo.setBasedir( new File("target") ); + + // when + final CommandLine commandLine = execMojo.getExecutablePath( emptyMap(), new File( "target" ) ); + execMojo.execute(); + + // then + assertTrue( "dir should have been created", + Paths.get( "target", "dist", "mails" ).toFile().exists() ); + } + private void checkMojo( String expectedCommandLine ) { assertEquals( 1, mojo.getAmountExecutedCommandLines() );