| package org.apache.maven.shared.invoker; |
| |
| /* |
| * 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. |
| */ |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Properties; |
| |
| import org.apache.maven.shared.invoker.InvocationRequest.CheckSumPolicy; |
| import org.apache.maven.shared.invoker.InvocationRequest.ReactorFailureBehavior; |
| import org.apache.maven.shared.utils.Os; |
| import org.apache.maven.shared.utils.StringUtils; |
| import org.apache.maven.shared.utils.cli.CommandLineException; |
| import org.apache.maven.shared.utils.cli.Commandline; |
| |
| /** |
| * <p>MavenCommandLineBuilder class.</p> |
| */ |
| public class MavenCommandLineBuilder |
| { |
| |
| private static final InvokerLogger DEFAULT_LOGGER = new SystemOutLogger(); |
| |
| private InvokerLogger logger = DEFAULT_LOGGER; |
| |
| private File baseDirectory; |
| |
| private File localRepositoryDirectory; |
| |
| private File mavenHome; |
| |
| private File mavenExecutable; |
| |
| /** |
| * <p>build.</p> |
| * |
| * @param request a {@link org.apache.maven.shared.invoker.InvocationRequest} object. |
| * @return a {@link org.apache.maven.shared.utils.cli.Commandline} object. |
| * @throws org.apache.maven.shared.invoker.CommandLineConfigurationException if any. |
| */ |
| public Commandline build( InvocationRequest request ) |
| throws CommandLineConfigurationException |
| { |
| |
| Commandline cli = new Commandline(); |
| |
| setupMavenHome( request ); |
| |
| // discover value for working directory |
| setupBaseDirectory( request ); |
| cli.setWorkingDirectory( baseDirectory ); |
| |
| checkRequiredState(); |
| |
| setupMavenExecutable( request ); |
| cli.setExecutable( mavenExecutable.getAbsolutePath() ); |
| |
| // handling for OS-level envars |
| setShellEnvironment( request, cli ); |
| |
| // interactive, offline, update-snapshots, |
| // debug/show-errors, checksum policy |
| setFlags( request, cli ); |
| |
| // failure behavior and [eventually] forced-reactor |
| // includes/excludes, etc. |
| setReactorBehavior( request, cli ); |
| |
| // local repository location |
| setLocalRepository( request, cli ); |
| |
| // pom-file handling |
| setPomLocation( request, cli ); |
| |
| setSettingsLocation( request, cli ); |
| |
| setToolchainsLocation( request, cli ); |
| |
| setProperties( request, cli ); |
| |
| setProfiles( request, cli ); |
| |
| setGoals( request, cli ); |
| |
| setThreads( request, cli ); |
| |
| setArgs( request, cli ); |
| |
| return cli; |
| } |
| |
| /** |
| * <p>checkRequiredState.</p> |
| */ |
| protected void checkRequiredState() |
| { |
| if ( logger == null ) |
| { |
| throw new IllegalStateException( "A logger instance is required." ); |
| } |
| } |
| |
| /** |
| * <p>setSettingsLocation.</p> |
| * |
| * @param request a {@link org.apache.maven.shared.invoker.InvocationRequest} object. |
| * @param cli a {@link org.apache.maven.shared.utils.cli.Commandline} object. |
| */ |
| protected void setSettingsLocation( InvocationRequest request, Commandline cli ) |
| { |
| File userSettingsFile = request.getUserSettingsFile(); |
| |
| if ( userSettingsFile != null ) |
| { |
| try |
| { |
| userSettingsFile = userSettingsFile.getCanonicalFile(); |
| } |
| catch ( IOException e ) |
| { |
| logger.debug( "Failed to canonicalize user settings path: " + userSettingsFile.getAbsolutePath() |
| + ". Using as-is.", e ); |
| } |
| |
| cli.createArg().setValue( "-s" ); |
| cli.createArg().setValue( userSettingsFile.getPath() ); |
| } |
| |
| File globalSettingsFile = request.getGlobalSettingsFile(); |
| |
| if ( globalSettingsFile != null ) |
| { |
| try |
| { |
| globalSettingsFile = globalSettingsFile.getCanonicalFile(); |
| } |
| catch ( IOException e ) |
| { |
| logger.debug( "Failed to canonicalize global settings path: " + globalSettingsFile.getAbsolutePath() |
| + ". Using as-is.", e ); |
| } |
| |
| cli.createArg().setValue( "-gs" ); |
| cli.createArg().setValue( globalSettingsFile.getPath() ); |
| } |
| |
| } |
| |
| /** |
| * <p>setToolchainsLocation.</p> |
| * |
| * @param request a {@link org.apache.maven.shared.invoker.InvocationRequest} object. |
| * @param cli a {@link org.apache.maven.shared.utils.cli.Commandline} object. |
| */ |
| protected void setToolchainsLocation( InvocationRequest request, Commandline cli ) |
| { |
| File toolchainsFile = request.getToolchainsFile(); |
| |
| if ( toolchainsFile != null ) |
| { |
| try |
| { |
| toolchainsFile = toolchainsFile.getCanonicalFile(); |
| } |
| catch ( IOException e ) |
| { |
| logger.debug( "Failed to canonicalize toolchains path: " + toolchainsFile.getAbsolutePath() |
| + ". Using as-is.", e ); |
| } |
| |
| cli.createArg().setValue( "-t" ); |
| cli.createArg().setValue( toolchainsFile.getPath() ); |
| } |
| } |
| |
| /** |
| * <p>setShellEnvironment.</p> |
| * |
| * @param request a {@link org.apache.maven.shared.invoker.InvocationRequest} object. |
| * @param cli a {@link org.apache.maven.shared.utils.cli.Commandline} object. |
| */ |
| protected void setShellEnvironment( InvocationRequest request, Commandline cli ) |
| { |
| if ( request.isShellEnvironmentInherited() ) |
| { |
| cli.addSystemEnvironment(); |
| } |
| |
| if ( request.getJavaHome() != null ) |
| { |
| cli.addEnvironment( "JAVA_HOME", request.getJavaHome().getAbsolutePath() ); |
| } |
| |
| if ( request.getMavenOpts() != null ) |
| { |
| cli.addEnvironment( "MAVEN_OPTS", request.getMavenOpts() ); |
| } |
| |
| for ( Map.Entry<String, String> entry : request.getShellEnvironments().entrySet() ) |
| { |
| cli.addEnvironment( entry.getKey(), entry.getValue() ); |
| } |
| } |
| |
| /** |
| * <p>setProfiles.</p> |
| * |
| * @param request a {@link org.apache.maven.shared.invoker.InvocationRequest} object. |
| * @param cli a {@link org.apache.maven.shared.utils.cli.Commandline} object. |
| */ |
| protected void setProfiles( InvocationRequest request, Commandline cli ) |
| { |
| List<String> profiles = request.getProfiles(); |
| |
| if ( ( profiles != null ) && !profiles.isEmpty() ) |
| { |
| cli.createArg().setValue( "-P" ); |
| cli.createArg().setValue( StringUtils.join( profiles.iterator(), "," ) ); |
| } |
| |
| } |
| |
| /** |
| * <p>setGoals.</p> |
| * |
| * @param request a {@link org.apache.maven.shared.invoker.InvocationRequest} object. |
| * @param cli a {@link org.apache.maven.shared.utils.cli.Commandline} object. |
| * @throws org.apache.maven.shared.invoker.CommandLineConfigurationException if any. |
| */ |
| protected void setGoals( InvocationRequest request, Commandline cli ) throws CommandLineConfigurationException |
| { |
| List<String> goals = request.getGoals(); |
| |
| if ( ( goals != null ) && !goals.isEmpty() ) |
| { |
| try |
| { |
| cli.createArg().setLine( StringUtils.join( goals.iterator(), " " ) ); |
| } |
| catch ( CommandLineException e ) |
| { |
| throw new CommandLineConfigurationException( "Problem setting goals", e ); |
| } |
| } |
| } |
| |
| /** |
| * <p>setProperties.</p> |
| * |
| * @param request a {@link org.apache.maven.shared.invoker.InvocationRequest} object. |
| * @param cli a {@link org.apache.maven.shared.utils.cli.Commandline} object. |
| */ |
| protected void setProperties( InvocationRequest request, Commandline cli ) |
| { |
| Properties properties = request.getProperties(); |
| |
| if ( properties != null ) |
| { |
| for ( Entry<Object, Object> entry : properties.entrySet() ) |
| { |
| String key = (String) entry.getKey(); |
| String value = (String) entry.getValue(); |
| |
| cli.createArg().setValue( "-D" ); |
| cli.createArg().setValue( key + '=' + value ); |
| } |
| } |
| } |
| |
| /** |
| * <p>setPomLocation.</p> |
| * |
| * @param request a {@link org.apache.maven.shared.invoker.InvocationRequest} object. |
| * @param cli a {@link org.apache.maven.shared.utils.cli.Commandline} object. |
| */ |
| protected void setPomLocation( InvocationRequest request, Commandline cli ) |
| { |
| File pom = request.getPomFile(); |
| String pomFilename = request.getPomFileName(); |
| |
| if ( pom == null ) |
| { |
| if ( pomFilename != null ) |
| { |
| pom = new File( baseDirectory, pomFilename ); |
| } |
| else |
| { |
| pom = new File( baseDirectory, "pom.xml" ); |
| } |
| } |
| |
| try |
| { |
| pom = pom.getCanonicalFile(); |
| } |
| catch ( IOException e ) |
| { |
| logger.debug( "Failed to canonicalize the POM path: " + pom + ". Using as-is.", e ); |
| } |
| |
| if ( pom.getParentFile().equals( baseDirectory ) ) |
| { |
| // pom in project workspace |
| if ( !"pom.xml".equals( pom.getName() ) ) |
| { |
| logger.debug( "Specified POM file is not named 'pom.xml'. " |
| + "Using the '-f' command-line option to accommodate non-standard filename..." ); |
| |
| cli.createArg().setValue( "-f" ); |
| cli.createArg().setValue( pom.getName() ); |
| } |
| } |
| else |
| { |
| cli.createArg().setValue( "-f" ); |
| cli.createArg().setValue( pom.getPath() ); |
| } |
| } |
| |
| void setupBaseDirectory( InvocationRequest request ) |
| { |
| File baseDirectoryFromRequest = null; |
| if ( request.getBaseDirectory() != null ) |
| { |
| baseDirectoryFromRequest = request.getBaseDirectory(); |
| } |
| else |
| { |
| File pomFile = request.getPomFile(); |
| if ( pomFile != null ) |
| { |
| baseDirectoryFromRequest = pomFile.getParentFile(); |
| } |
| } |
| |
| if ( baseDirectoryFromRequest != null ) |
| { |
| baseDirectory = baseDirectoryFromRequest; |
| } |
| |
| if ( baseDirectory == null ) |
| { |
| baseDirectory = new File( System.getProperty( "user.dir" ) ); |
| } |
| else if ( baseDirectory.isFile() ) |
| { |
| logger.warn( "Specified base directory (" + baseDirectory + ") is a file." |
| + " Using its parent directory..." ); |
| |
| baseDirectory = baseDirectory.getParentFile(); |
| } |
| |
| try |
| { |
| baseDirectory = baseDirectory.getCanonicalFile(); |
| } |
| catch ( IOException e ) |
| { |
| logger.debug( "Failed to canonicalize base directory: " + baseDirectory + ". Using as-is.", e ); |
| } |
| } |
| |
| /** |
| * <p>setLocalRepository.</p> |
| * |
| * @param request a {@link org.apache.maven.shared.invoker.InvocationRequest} object. |
| * @param cli a {@link org.apache.maven.shared.utils.cli.Commandline} object. |
| */ |
| protected void setLocalRepository( InvocationRequest request, Commandline cli ) |
| { |
| File localRepositoryDirectory = request.getLocalRepositoryDirectory( this.localRepositoryDirectory ); |
| |
| if ( localRepositoryDirectory != null ) |
| { |
| try |
| { |
| localRepositoryDirectory = localRepositoryDirectory.getCanonicalFile(); |
| } |
| catch ( IOException e ) |
| { |
| logger.debug( "Failed to canonicalize local repository directory: " + localRepositoryDirectory |
| + ". Using as-is.", e ); |
| } |
| |
| if ( !localRepositoryDirectory.isDirectory() ) |
| { |
| throw new IllegalArgumentException( "Local repository location: '" + localRepositoryDirectory |
| + "' is NOT a directory." ); |
| } |
| |
| cli.createArg().setValue( "-D" ); |
| cli.createArg().setValue( "maven.repo.local=" + localRepositoryDirectory.getPath() ); |
| } |
| } |
| |
| /** |
| * <p>setReactorBehavior.</p> |
| * |
| * @param request a {@link org.apache.maven.shared.invoker.InvocationRequest} object. |
| * @param cli a {@link org.apache.maven.shared.utils.cli.Commandline} object. |
| */ |
| protected void setReactorBehavior( InvocationRequest request, Commandline cli ) |
| { |
| // NOTE: The default is "fail-fast" |
| ReactorFailureBehavior failureBehavior = request.getReactorFailureBehavior(); |
| |
| if ( failureBehavior != null ) |
| { |
| if ( ReactorFailureBehavior.FailAtEnd.equals( failureBehavior ) ) |
| { |
| cli.createArg().setValue( "-" + ReactorFailureBehavior.FailAtEnd.getShortOption() ); |
| } |
| else if ( ReactorFailureBehavior.FailNever.equals( failureBehavior ) ) |
| { |
| cli.createArg().setValue( "-" + ReactorFailureBehavior.FailNever.getShortOption() ); |
| } |
| |
| } |
| |
| if ( StringUtils.isNotEmpty( request.getResumeFrom() ) ) |
| { |
| cli.createArg().setValue( "-rf" ); |
| cli.createArg().setValue( request.getResumeFrom() ); |
| } |
| |
| List<String> projectList = request.getProjects(); |
| if ( projectList != null ) |
| { |
| cli.createArg().setValue( "-pl" ); |
| cli.createArg().setValue( StringUtils.join( projectList.iterator(), "," ) ); |
| |
| if ( request.isAlsoMake() ) |
| { |
| cli.createArg().setValue( "-am" ); |
| } |
| |
| if ( request.isAlsoMakeDependents() ) |
| { |
| cli.createArg().setValue( "-amd" ); |
| } |
| } |
| } |
| |
| /** |
| * <p>setFlags.</p> |
| * |
| * @param request a {@link org.apache.maven.shared.invoker.InvocationRequest} object. |
| * @param cli a {@link org.apache.maven.shared.utils.cli.Commandline} object. |
| */ |
| protected void setFlags( InvocationRequest request, Commandline cli ) |
| { |
| if ( request.isBatchMode() ) |
| { |
| cli.createArg().setValue( "-B" ); |
| } |
| |
| if ( request.isOffline() ) |
| { |
| cli.createArg().setValue( "-o" ); |
| } |
| |
| if ( request.isUpdateSnapshots() ) |
| { |
| cli.createArg().setValue( "-U" ); |
| } |
| |
| if ( !request.isRecursive() ) |
| { |
| cli.createArg().setValue( "-N" ); |
| } |
| |
| if ( request.isDebug() ) |
| { |
| cli.createArg().setValue( "-X" ); |
| } |
| // this is superseded by -X, if it exists. |
| else if ( request.isShowErrors() ) |
| { |
| cli.createArg().setValue( "-e" ); |
| } |
| |
| CheckSumPolicy checksumPolicy = request.getGlobalChecksumPolicy(); |
| if ( CheckSumPolicy.Fail.equals( checksumPolicy ) ) |
| { |
| cli.createArg().setValue( "-C" ); |
| } |
| else if ( CheckSumPolicy.Warn.equals( checksumPolicy ) ) |
| { |
| cli.createArg().setValue( "-c" ); |
| } |
| |
| if ( request.isNonPluginUpdates() ) |
| { |
| cli.createArg().setValue( "-npu" ); |
| } |
| |
| if ( request.isShowVersion() ) |
| { |
| cli.createArg().setValue( "-V" ); |
| } |
| |
| if ( request.getBuilder() != null ) |
| { |
| cli.createArg().setValue( "-b" ); |
| cli.createArg().setValue( request.getBuilder() ); |
| } |
| |
| if ( request.isQuiet() ) |
| { |
| cli.createArg().setValue( "-q" ); |
| } |
| |
| if ( request.isNoTransferProgress() ) |
| { |
| cli.createArg().setValue( "-ntp" ); |
| } |
| } |
| |
| /** |
| * <p>setThreads.</p> |
| * |
| * @param request a {@link org.apache.maven.shared.invoker.InvocationRequest} object. |
| * @param cli a {@link org.apache.maven.shared.utils.cli.Commandline} object. |
| */ |
| protected void setThreads( InvocationRequest request, Commandline cli ) |
| { |
| String threads = request.getThreads(); |
| if ( StringUtils.isNotEmpty( threads ) ) |
| { |
| cli.createArg().setValue( "-T" ); |
| cli.createArg().setValue( threads ); |
| } |
| |
| } |
| |
| private void setArgs( InvocationRequest request, Commandline cli ) |
| { |
| for ( String arg : request.getArgs() ) |
| { |
| cli.createArg().setValue( arg ); |
| } |
| } |
| |
| private void setupMavenHome( InvocationRequest request ) |
| { |
| if ( request.getMavenHome() != null ) |
| { |
| mavenHome = request.getMavenHome(); |
| } |
| else if ( System.getProperty( "maven.home" ) != null ) |
| { |
| mavenHome = new File( System.getProperty( "maven.home" ) ); |
| } |
| |
| if ( mavenHome != null && !mavenHome.isDirectory() ) |
| { |
| File binDir = mavenHome.getParentFile(); |
| if ( binDir != null && "bin".equals( binDir.getName() ) ) |
| { |
| // ah, they specified the mvn |
| // executable instead... |
| mavenHome = binDir.getParentFile(); |
| } |
| } |
| |
| if ( mavenHome != null && !mavenHome.isDirectory() ) |
| { |
| throw new IllegalStateException( "Maven home is set to: '" + mavenHome + "' which is not a directory" ); |
| } |
| |
| logger.debug( "Using maven.home of: '" + mavenHome + "'." ); |
| } |
| |
| |
| /** |
| * <p>setupMavenExecutable.</p> |
| * |
| * @param request a Invoker request |
| * @throws org.apache.maven.shared.invoker.CommandLineConfigurationException if any. |
| */ |
| protected void setupMavenExecutable( InvocationRequest request ) |
| throws CommandLineConfigurationException |
| { |
| if ( request.getMavenExecutable() != null ) |
| { |
| mavenExecutable = request.getMavenExecutable(); |
| } |
| |
| if ( mavenExecutable == null || !mavenExecutable.isAbsolute() ) |
| { |
| String executable; |
| if ( mavenExecutable != null ) |
| { |
| executable = mavenExecutable.getPath(); |
| } |
| else |
| { |
| executable = "mvn"; |
| } |
| |
| // firs look in project directory |
| mavenExecutable = detectMavenExecutablePerOs( baseDirectory, executable ); |
| if ( mavenExecutable == null ) |
| { |
| // next maven home |
| mavenExecutable = detectMavenExecutablePerOs( mavenHome, "/bin/" + executable ); |
| } |
| |
| if ( mavenExecutable != null ) |
| { |
| try |
| { |
| mavenExecutable = mavenExecutable.getCanonicalFile(); |
| } |
| catch ( IOException e ) |
| { |
| logger.debug( "Failed to canonicalize maven executable: '" + mavenExecutable |
| + "'. Using as-is.", e ); |
| } |
| } |
| else |
| { |
| throw new CommandLineConfigurationException( |
| "Maven executable: '" + executable + "'" |
| + " not found at project dir: '" + baseDirectory + "' nor maven home: '" + mavenHome + "'" ); |
| } |
| } |
| } |
| |
| private File detectMavenExecutablePerOs( File baseDirectory, String executable ) |
| { |
| if ( Os.isFamily( Os.FAMILY_WINDOWS ) ) |
| { |
| File executableFile = new File( baseDirectory, executable + ".cmd" ); |
| if ( executableFile.isFile() ) |
| { |
| return executableFile; |
| } |
| |
| executableFile = new File( baseDirectory, executable + ".bat" ); |
| if ( executableFile.isFile() ) |
| { |
| return executableFile; |
| } |
| } |
| |
| File executableFile = new File( baseDirectory, executable ); |
| if ( executableFile.isFile() ) |
| { |
| return executableFile; |
| } |
| return null; |
| } |
| |
| /** |
| * <p>Getter for the field <code>localRepositoryDirectory</code>.</p> |
| * |
| * @return a {@link java.io.File} object. |
| */ |
| public File getLocalRepositoryDirectory() |
| { |
| return localRepositoryDirectory; |
| } |
| |
| /** |
| * <p>Setter for the field <code>localRepositoryDirectory</code>.</p> |
| * |
| * @param localRepositoryDirectory a {@link java.io.File} object. |
| */ |
| public void setLocalRepositoryDirectory( File localRepositoryDirectory ) |
| { |
| this.localRepositoryDirectory = localRepositoryDirectory; |
| } |
| |
| /** |
| * <p>Getter for the field <code>logger</code>.</p> |
| * |
| * @return a {@link org.apache.maven.shared.invoker.InvokerLogger} object. |
| */ |
| public InvokerLogger getLogger() |
| { |
| return logger; |
| } |
| |
| /** |
| * <p>Setter for the field <code>logger</code>.</p> |
| * |
| * @param logger a {@link org.apache.maven.shared.invoker.InvokerLogger} object. |
| */ |
| public void setLogger( InvokerLogger logger ) |
| { |
| this.logger = logger; |
| } |
| |
| /** |
| * <p>Getter for the field <code>mavenHome</code>.</p> |
| * |
| * @return a {@link java.io.File} object. |
| */ |
| public File getMavenHome() |
| { |
| return mavenHome; |
| } |
| |
| /** |
| * <p>Setter for the field <code>mavenHome</code>.</p> |
| * |
| * @param mavenHome a {@link java.io.File} object. |
| */ |
| public void setMavenHome( File mavenHome ) |
| { |
| this.mavenHome = mavenHome; |
| } |
| |
| /** |
| * <p>Getter for the field <code>baseDirectory</code>.</p> |
| * |
| * @return a {@link java.io.File} object. |
| */ |
| public File getBaseDirectory() |
| { |
| return baseDirectory; |
| } |
| |
| /** |
| * <p>Setter for the field <code>baseDirectory</code>.</p> |
| * |
| * @param baseDirectory a {@link java.io.File} object. |
| */ |
| public void setBaseDirectory( File baseDirectory ) |
| { |
| this.baseDirectory = baseDirectory; |
| } |
| |
| /** |
| * {@code mavenExecutable} can either be relative to ${maven.home}/bin/ or absolute |
| * |
| * @param mavenExecutable the executable |
| */ |
| public void setMavenExecutable( File mavenExecutable ) |
| { |
| this.mavenExecutable = mavenExecutable; |
| } |
| |
| /** |
| * <p>Getter for the field <code>mavenExecutable</code>.</p> |
| * |
| * @return a {@link java.io.File} object. |
| */ |
| public File getMavenExecutable() |
| { |
| return mavenExecutable; |
| } |
| |
| } |