From 8ed9a1caa8890773b45c6c408a4e40acf4f4b0fd Mon Sep 17 00:00:00 2001 From: Igor Fedorenko Date: Mon, 26 Jan 2015 14:22:05 -0500 Subject: [PATCH] MNG-5767 .mvn/ for project specific jvm options and maven parameters Signed-off-by: Igor Fedorenko --- apache-maven/src/bin/mvn | 29 ++++++++- .../DefaultMavenExecutionRequest.java | 14 +++++ .../execution/MavenExecutionRequest.java | 9 +++ .../java/org/apache/maven/cli/MavenCli.java | 57 +++++++++++++++++- .../org/apache/maven/cli/MavenCliTest.java | 59 +++++++++++++++++++ .../projects/config-illegal/.mvn/maven.config | 1 + .../test/projects/config/.mvn/maven.config | 2 + 7 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 maven-embedder/src/test/projects/config-illegal/.mvn/maven.config create mode 100644 maven-embedder/src/test/projects/config/.mvn/maven.config diff --git a/apache-maven/src/bin/mvn b/apache-maven/src/bin/mvn index 1ed3024b3f..26feda4218 100755 --- a/apache-maven/src/bin/mvn +++ b/apache-maven/src/bin/mvn @@ -189,14 +189,39 @@ if $cygwin; then CLASSPATH=`cygpath --path --windows "$CLASSPATH"` fi +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + local basedir=$(pwd) + local wdir=$(pwd) + while [ "$wdir" != '/' ] ; do + wdir=$(cd $wdir/..; pwd) + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + # Provide a "standardized" way to retrieve the CLI args that will # work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$@" +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" export MAVEN_CMD_LINE_ARGS exec "$JAVACMD" \ $MAVEN_OPTS \ -classpath "${M2_HOME}"/boot/plexus-classworlds-*.jar \ "-Dclassworlds.conf=${M2_HOME}/bin/m2.conf" \ - "-Dmaven.home=${M2_HOME}" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.projectBasedir=${MAVEN_PROJECTBASEDIR}" \ ${CLASSWORLDS_LAUNCHER} "$@" diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java index d88024d390..f4439b13b8 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java +++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java @@ -93,6 +93,8 @@ public class DefaultMavenExecutionRequest // Request // ---------------------------------------------------------------------------- + private File projectBasedir; + private File basedir; private List goals; @@ -1149,4 +1151,16 @@ public class DefaultMavenExecutionRequest this.toolchains = toolchains; return this; } + + @Override + public void setProjectBaseDirectory( File directory ) + { + this.projectBasedir = directory; + } + + @Override + public File getProjectBaseDirectory() + { + return projectBasedir; + } } diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java index 2b2a1d829b..55d7ff2036 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java +++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java @@ -415,4 +415,13 @@ public interface MavenExecutionRequest */ Map> getToolchains(); + /** + * @since 3.2.6 + */ + void setProjectBaseDirectory( File file ); + + /** + * @since 3.2.6 + */ + File getProjectBaseDirectory(); } diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java index 35ccbd2794..238be22c92 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java @@ -23,8 +23,10 @@ import java.io.Console; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -92,6 +94,8 @@ import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; import org.sonatype.plexus.components.sec.dispatcher.SecUtil; import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity; +import com.google.common.base.Charsets; +import com.google.common.io.Files; import com.google.inject.AbstractModule; // TODO: push all common bits back to plexus cli and prepare for transition to Guice. We don't need 50 ways to make CLIs @@ -106,6 +110,8 @@ public class MavenCli public static final String THREADS_DEPRECATED = "maven.threads.experimental"; + public static final String PROJECT_BASEDIR = "maven.projectBasedir"; + @SuppressWarnings( "checkstyle:constantname" ) public static final String userHome = System.getProperty( "user.home" ); @@ -257,13 +263,27 @@ public class MavenCli } } - private void initialize( CliRequest cliRequest ) + void initialize( CliRequest cliRequest ) { if ( cliRequest.workingDirectory == null ) { cliRequest.workingDirectory = System.getProperty( "user.dir" ); } + if ( cliRequest.projectBaseDirectory == null ) + { + String basedirProperty = System.getProperty( PROJECT_BASEDIR ); + File basedir = basedirProperty != null ? new File( basedirProperty ) : new File( "" ); + try + { + cliRequest.projectBaseDirectory = basedir.getCanonicalFile(); + } + catch ( IOException e ) + { + cliRequest.projectBaseDirectory = basedir.getAbsoluteFile(); + } + } + // // Make sure the Maven home directory is an absolute path to save us from confusion with say drive-relative // Windows paths. @@ -276,7 +296,7 @@ public class MavenCli } } - private void cli( CliRequest cliRequest ) + void cli( CliRequest cliRequest ) throws Exception { // @@ -287,9 +307,38 @@ public class MavenCli CLIManager cliManager = new CLIManager(); + List args = new ArrayList(); + try { - cliRequest.commandLine = cliManager.parse( cliRequest.args ); + File configFile = new File( cliRequest.projectBaseDirectory, ".mvn/maven.config" ); + + if ( configFile.isFile() ) + { + for ( String arg : Files.toString( configFile, Charsets.UTF_8 ).split( "\\s+" ) ) + { + args.add( arg ); + } + + CommandLine config = cliManager.parse( args.toArray( new String[args.size()] ) ); + List unrecongized = config.getArgList(); + if ( !unrecongized.isEmpty() ) + { + throw new ParseException( "Unrecognized maven.config entries: " + unrecongized ); + } + } + } + catch ( ParseException e ) + { + System.err.println( "Unable to parse maven.config: " + e.getMessage() ); + cliManager.displayHelp( System.out ); + throw e; + } + + try + { + args.addAll( 0, Arrays.asList( cliRequest.args ) ); + cliRequest.commandLine = cliManager.parse( args.toArray( new String[args.size()] ) ); } catch ( ParseException e ) { @@ -1074,6 +1123,7 @@ public class MavenCli .setUpdateSnapshots( updateSnapshots ) // default: false .setNoSnapshotUpdates( noSnapshotUpdates ) // default: false .setGlobalChecksumPolicy( globalChecksumPolicy ) // default: warn + .setProjectBaseDirectory( cliRequest.projectBaseDirectory ) ; if ( alternatePomFile != null ) @@ -1322,6 +1372,7 @@ public class MavenCli CommandLine commandLine; ClassWorld classWorld; String workingDirectory; + File projectBaseDirectory; boolean debug; boolean quiet; boolean showErrors = true; diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java index 6e06cc5ad8..628ef205ab 100644 --- a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java +++ b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java @@ -19,16 +19,39 @@ package org.apache.maven.cli; * under the License. */ +import java.io.File; + import junit.framework.TestCase; +import org.apache.commons.cli.ParseException; +import org.apache.maven.cli.MavenCli.CliRequest; + public class MavenCliTest extends TestCase { private MavenCli cli; + private String origBasedir; + protected void setUp() { cli = new MavenCli(); + origBasedir = System.getProperty( MavenCli.PROJECT_BASEDIR ); + } + + @Override + protected void tearDown() + throws Exception + { + if ( origBasedir != null ) + { + System.setProperty( MavenCli.PROJECT_BASEDIR, origBasedir ); + } + else + { + System.getProperties().remove( MavenCli.PROJECT_BASEDIR ); + } + super.tearDown(); } public void testCalculateDegreeOfConcurrencyWithCoreMultiplier() @@ -49,4 +72,40 @@ public class MavenCliTest // carry on } } + + public void testMavenConfig() + throws Exception + { + System.setProperty( MavenCli.PROJECT_BASEDIR, new File( "src/test/projects/config" ).getCanonicalPath() ); + CliRequest request = new CliRequest( new String[0], null ); + + // read .mvn/maven.config + cli.initialize( request ); + cli.cli( request ); + assertEquals( "multithreaded", request.commandLine.getOptionValue( "builder" ) ); + assertEquals( "8", request.commandLine.getOptionValue( "threads" ) ); + + // override from command line + request = new CliRequest( new String[] { "--builder", "foobar" }, null ); + cli.cli( request ); + assertEquals( "foobar", request.commandLine.getOptionValue( "builder" ) ); + } + + public void testMavenConfigInvalid() + throws Exception + { + System.setProperty( MavenCli.PROJECT_BASEDIR, new File( "src/test/projects/config-illegal" ).getCanonicalPath() ); + CliRequest request = new CliRequest( new String[0], null ); + + cli.initialize( request ); + try + { + cli.cli( request ); + fail(); + } + catch ( ParseException expected ) + { + + } + } } diff --git a/maven-embedder/src/test/projects/config-illegal/.mvn/maven.config b/maven-embedder/src/test/projects/config-illegal/.mvn/maven.config new file mode 100644 index 0000000000..8541464a78 --- /dev/null +++ b/maven-embedder/src/test/projects/config-illegal/.mvn/maven.config @@ -0,0 +1 @@ +deploy diff --git a/maven-embedder/src/test/projects/config/.mvn/maven.config b/maven-embedder/src/test/projects/config/.mvn/maven.config new file mode 100644 index 0000000000..3d0f13b2cd --- /dev/null +++ b/maven-embedder/src/test/projects/config/.mvn/maven.config @@ -0,0 +1,2 @@ +-T8 --builder + multithreaded