blob: 74b19fd0d6ce23ad5a3ab6d43909276c233a6272 [file] [log] [blame]
package org.apache.maven.plugins.wrapper;
/*
* 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.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import org.apache.maven.Maven;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.settings.Mirror;
import org.apache.maven.settings.Settings;
import org.codehaus.plexus.archiver.UnArchiver;
import org.codehaus.plexus.components.io.fileselectors.FileInfo;
import org.codehaus.plexus.components.io.fileselectors.FileSelector;
import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
/**
* Unpacks the maven-wrapper distribution files to the current project source tree.
*
* @author Robert Scholte
* @since 3.0.0
*/
@Mojo( name = "wrapper", aggregator = true, requiresDirectInvocation = true )
public class WrapperMojo extends AbstractMojo
{
private static final String MVNW_REPOURL = "MVNW_REPOURL";
private static final String DEFAULT_REPOURL = "https://repo.maven.apache.org/maven2";
// CONFIGURATION PARAMETERS
/**
* The version of Maven to require, default value is the Runtime version of Maven.
* Can be any valid release above 2.0.9
*/
@Parameter( property = "maven" )
private String mavenVersion;
/**
* Options are:
* <dl>
* <dt>script</dt>
* <dd>only mvnw scripts</dd>
* <dt>bin (default)</dt>
* <dd>precompiled and packaged code</dd>
* <dt>source</dt>
* <dd>Java source code, will be compiled on the fly</dd>
* </dl>
*
* Value will be used as classifier of the downloaded file
*/
@Parameter( defaultValue = "bin", property = "type" )
private String distributionType;
/**
* Include <code>mvnwDebug*</code> scripts?
*/
@Parameter( defaultValue = "false", property = "includeDebug" )
private boolean includeDebugScript;
// READONLY PARAMETERS
@Parameter( defaultValue = "${session}", readonly = true, required = true )
private MavenSession session;
@Parameter( defaultValue = "${settings}", readonly = true, required = true )
private Settings settings;
// Waiting for org.codehaus.plexus.component.configurator.converters.basic.PathConverter
@Parameter( defaultValue = "${project.basedir}", readonly = true, required = true )
private File basedir;
// CONSTANTS
private static final String WRAPPER_DISTRIBUTION_GROUP_ID = "org.apache.maven.wrapper";
private static final String WRAPPER_DISTRIBUTION_ARTIFACT_ID = "maven-wrapper-distribution";
private static final String WRAPPER_DISTRIBUTION_EXTENSION = "zip";
// COMPONENTS
@Inject
private RepositorySystem repositorySystem;
@Inject
private Map<String, UnArchiver> unarchivers;
@Override
public void execute()
throws MojoExecutionException
{
String wrapperVersion = getVersion( null, this.getClass(), "org.apache.maven.plugins/maven-wrapper-plugin" );
Artifact artifact = downloadWrapperDistribution( wrapperVersion );
try
{
unpack( artifact, basedir.toPath() );
getLog().info( "Unpacked " + buffer().strong( distributionType ) + " type wrapper distribution "
+ artifact );
}
catch ( IOException e )
{
throw new MojoExecutionException( e.getMessage(), e );
}
mavenVersion = getVersion( mavenVersion, Maven.class, "org.apache.maven/maven-core" );
try
{
replaceProperties( wrapperVersion, Files.createDirectories( basedir.toPath().resolve( ".mvn/wrapper" ) ) );
}
catch ( IOException e )
{
throw new MojoExecutionException( "can't create maven-wrapper.properties", e );
}
}
private Artifact downloadWrapperDistribution( String wrapperVersion ) throws MojoExecutionException
{
Artifact artifact = repositorySystem.createArtifactWithClassifier(
WRAPPER_DISTRIBUTION_GROUP_ID,
WRAPPER_DISTRIBUTION_ARTIFACT_ID,
wrapperVersion,
WRAPPER_DISTRIBUTION_EXTENSION,
distributionType );
MavenExecutionRequest executionRequest = session.getRequest();
ArtifactResolutionRequest resolutionRequest = new ArtifactResolutionRequest()
.setArtifact( artifact )
.setLocalRepository( session.getLocalRepository() )
.setRemoteRepositories( session.getCurrentProject().getPluginArtifactRepositories() )
.setOffline( executionRequest.isOffline() )
.setForceUpdate( executionRequest.isUpdateSnapshots() );
ArtifactResolutionResult resolveResult = repositorySystem.resolve( resolutionRequest );
if ( !resolveResult.isSuccess() )
{
if ( executionRequest.isShowErrors() )
{
for ( Exception e : resolveResult.getExceptions() )
{
getLog().error( e.getMessage(), e );
}
}
throw new MojoExecutionException( "artifact: " + artifact + " not resolved." );
}
return artifact;
}
private void unpack( Artifact artifact, Path targetFolder ) throws IOException
{
targetFolder = Files.createDirectories( targetFolder );
UnArchiver unarchiver = unarchivers.get( WRAPPER_DISTRIBUTION_EXTENSION );
unarchiver.setDestDirectory( targetFolder.toFile() );
unarchiver.setSourceFile( artifact.getFile() );
if ( !includeDebugScript )
{
unarchiver.setFileSelectors( new FileSelector[] { new FileSelector()
{
public boolean isSelected( @Nonnull
FileInfo fileInfo )
throws IOException
{
return !fileInfo.getName().contains( "Debug" );
}
} } );
}
unarchiver.extract();
}
/**
* As long as the content only contains the license and the distributionUrl, we can simply replace it.
* No need to look for other properties, restore them, respecting comments, etc.
*
* @param wrapperVersion the wrapper version
* @param targetFolder the folder containing the wrapper.properties
* @throws IOException if writing fails
*/
private void replaceProperties( String wrapperVersion, Path targetFolder ) throws IOException
{
String repoUrl = getRepoUrl();
String distributionUrl =
repoUrl + "/org/apache/maven/apache-maven/" + mavenVersion + "/apache-maven-" + mavenVersion + "-bin.zip";
String wrapperUrl = repoUrl + "/org/apache/maven/wrapper/maven-wrapper/" + wrapperVersion
+ "/maven-wrapper-" + wrapperVersion + ".jar";
Path wrapperPropertiesFile = targetFolder.resolve( "maven-wrapper.properties" );
getLog().info( "Configuring .mvn/wrapper/maven-wrapper.properties to use "
+ buffer().strong( "Maven " + mavenVersion ) + " and download from " + repoUrl );
final String license = "# Licensed to the Apache Software Foundation (ASF) under one%n"
+ "# or more contributor license agreements. See the NOTICE file%n"
+ "# distributed with this work for additional information%n"
+ "# regarding copyright ownership. The ASF licenses this file%n"
+ "# to you under the Apache License, Version 2.0 (the%n"
+ "# \"License\"); you may not use this file except in compliance%n"
+ "# with the License. You may obtain a copy of the License at%n"
+ "#%n"
+ "# https://www.apache.org/licenses/LICENSE-2.0%n"
+ "#%n"
+ "# Unless required by applicable law or agreed to in writing,%n"
+ "# software distributed under the License is distributed on an%n"
+ "# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY%n"
+ "# KIND, either express or implied. See the License for the%n"
+ "# specific language governing permissions and limitations%n"
+ "# under the License.%n";
try ( BufferedWriter out = Files.newBufferedWriter( wrapperPropertiesFile, StandardCharsets.UTF_8 ) )
{
out.append( String.format( Locale.ROOT, license ) );
out.append( "distributionUrl=" + distributionUrl + System.lineSeparator() );
out.append( "wrapperUrl=" + wrapperUrl + System.lineSeparator() );
}
}
private String getVersion( String defaultVersion, Class<?> clazz, String path )
{
String version = defaultVersion;
if ( version == null )
{
Properties props = new Properties();
try ( InputStream is =
clazz.getResourceAsStream( "/META-INF/maven/" + path + "/pom.properties" ) )
{
props.load( is );
version = props.getProperty( "version" );
}
catch ( IOException e )
{
// noop
}
}
return version;
}
/**
* Determine the repository URL to download Wrapper and Maven from.
*/
private String getRepoUrl()
{
// default
String repoUrl = DEFAULT_REPOURL;
// adapt to also support MVNW_REPOURL as supported by mvnw scripts from maven-wrapper
String mvnwRepoUrl = System.getenv( MVNW_REPOURL );
if ( mvnwRepoUrl != null && !mvnwRepoUrl.isEmpty() )
{
repoUrl = mvnwRepoUrl;
getLog().debug( "Using repo URL from " + MVNW_REPOURL + " environment variable." );
}
// otherwise mirror from settings
else if ( settings.getMirrors() != null && settings.getMirrors().size() > 0 )
{
for ( Mirror current : settings.getMirrors() )
{
if ( "*".equals( current.getMirrorOf() ) )
{
repoUrl = current.getUrl();
break;
}
}
getLog().debug( "Using repo URL from * mirror in settings file." );
}
getLog().debug( "Determined repo URL to use as " + repoUrl );
return repoUrl;
}
}