package org.codehaus.mojo.setup;
/*
* 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.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.RuntimeInformation;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.codehaus.mojo.setup.SetupExecutionRequest.MergeType;
import org.codehaus.plexus.PlexusConstants;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.context.Context;
import org.codehaus.plexus.context.ContextException;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
/**
* Abstract Mojo for all setup goals
*
* @requiresProject false
* @author Robert Scholte
* @since 1.0.0
*/
public abstract class AbstractSetupMojo
extends AbstractMojo implements Contextualizable, Initializable
{
// set during contextualization
/**
* RuntimeInformation to discover the Maven version
*/
private RuntimeInformation rti;
/**
* @parameter expression="${session}"
* @readonly
* @required
*/
private MavenSession session;
/**
* Base directory of the project.
*
* @parameter expression="${basedir}" //never project.basedir, because pom is not required
* @readonly
*/
private File baseDirectory;
/**
* Location of the settingstemplate, can be an URL, a relative or absolute path to the file
*
* @parameter alias="templateFile" expression="${templateFile}"
*/
private String templateFilename;
/**
* Define how to merge. Valid values are: none, update, expand and overwrite No default value, so we can detect if
* it is set by commandline
*
* @parameter expression="${merge}"
*/
private String merge;
/**
* Specify the encoding to use when specifying a templateFile
*
* @parameter expression="${encoding}"
*/
private String encoding;
/**
* With dryRun the execution will run as normal, but the target-file won't change.
* Instead a folder will be created with the same name as the directory-name containing the target file.
* Although there will be a backup-file, this way you can check the result before really changing the file.
*
* @parameter expression="${dryRun}"
*
*/
private boolean dryRun = false;
/**
* Setup execution request to use for the setup manager
*/
private SetupExecutionRequest setupRequest = new DefaultSetupExecutionRequest();
/**
* {@inheritDoc}
* @since 1.0.0
*/
public void contextualize ( Context context ) throws ContextException
{
PlexusContainer container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
try
{
rti = (RuntimeInformation) container.lookup( RuntimeInformation.class.getName() );
}
catch ( ComponentLookupException e )
{
getLog().info( "Could not retrieve RuntimeInformation to check maven version." );
}
}
/**
* {@inheritDoc}
* @since 1.0.0
*/
@Override
public void initialize()
throws InitializationException
{
try
{
if ( !isRequiredMavenVersion( getMavenVersionRange() ) )
{
throw new InitializationException( "\nThis goal is not supported. You're using Maven "
+ rti.getApplicationVersion() + ", it must be within this range: "
+ getMavenVersionRange().toString() );
}
}
catch ( InvalidVersionSpecificationException e )
{
throw new InitializationException( e.getMessage() );
}
}
// protected getters for subclasses
/**
* @return the MavenSession
* @since 1.0.0
*/
protected MavenSession getSession()
{
return session;
}
/**
*
* @return the baseDirectory as File
* @since 1.0.0
*/
protected File getBaseDirectory()
{
return baseDirectory;
}
/**
*
* @return the template filename
* @since 1.0.0
*/
protected String getTemplateFilename()
{
return templateFilename;
}
/**
*
* @return the setup request
* @since 1.0.0
*/
protected SetupExecutionRequest getSetupRequest()
{
return setupRequest;
}
// protected abstract getters, which subclasses must provide
/**
* @return the default-template filename
* @since 1.0.0
*/
protected abstract String getDefaultTemplateFilename();
/**
*
* @return the properties filename
* @since 1.0.0
*/
protected abstract String getPropertiesFilename();
/**
*
* @return the setup manager
* @since 1.0.0
*/
protected abstract SetupManager getSetupManager();
// helper methods
/**
* Exceptionless method to check is the value is a valid URL
*
* @param value the potential URL
* @return true is it's a URL, otherwise false
*/
private boolean isUrl( String value )
{
boolean result = true;
try
{
new URL( value );
}
catch ( MalformedURLException e )
{
result = false;
}
return result;
}
/**
* The prototype is an (xml)-file which contains comments on the tags to use.
*
* @return the prototype as InputStream, since it may be part of a jar
* @throws IOException if input stream can't be resolved
* @since 1.0.0
*/
protected InputStream getPrototypeInputStream()
throws IOException
{
return getSetupManager().getPrototypeInputStream();
}
/**
* Get the templatefile, either a custom or the default template file
*
* @return resolved templateFile or null
* @since 1.0.0
*/
protected File resolveTemplateFile()
{
File result = null;
if ( StringUtils.isNotEmpty( getTemplateFilename() ) )
{
if ( isUrl( getTemplateFilename() ) )
{
try
{
result = FileUtils.toFile( new URL( getTemplateFilename() ) );
}
catch ( MalformedURLException e )
{
// nop
}
}
else
{
result = FileUtils.resolveFile( getBaseDirectory(), getTemplateFilename() );
}
}
else
{
File templateFile = new File( getBaseDirectory(), getDefaultTemplateFilename() );
if ( templateFile.exists() )
{
result = templateFile;
if ( getLog().isDebugEnabled() )
{
getLog().debug( "using " + templateFile );
}
}
}
return result;
}
/**
* {@inheritDoc}
* @since 1.0.0
*/
public void execute()
throws MojoExecutionException, MojoFailureException
{
preProcess();
try
{
File settingsTemplate = resolveTemplateFile();
if ( settingsTemplate != null || !getSetupRequest().getAdditionalProperties().isEmpty() )
{
// Using merge as String, because translation to MergeType requires a switch/case or a valueOf(), which
// might break;
getSetupRequest().setSession( getSession() )
.setTemplateFile( resolveTemplateFile() )
.setPropertyFilenames( getPropertyFiles() )
.setDryRun( dryRun )
.setEncoding( encoding );
if ( merge != null )
{
getSetupRequest().setMergeType( MergeType.valueOf( merge.toUpperCase() ) );
}
getSetupManager().process( getSetupRequest() );
}
else if ( merge == null )
{ // copy prototype as default template to baseDirectory
IOUtil.copy( getPrototypeInputStream(),
new FileWriter( FileUtils.resolveFile( getBaseDirectory(), getDefaultTemplateFilename() ) ) );
if ( getLog().isInfoEnabled() )
{
getLog().info( getDefaultTemplateFilename() + " has been created in the current directory." );
getLog().info( "Change this file for your own configuration and rerun the last maven-goal." );
getLog().info( "This way it will try to copy the file to the proper location." );
}
}
else
{
throw new MojoFailureException( "merge-property was set, but there was no template available" );
}
}
catch ( IOException e )
{
throw new MojoExecutionException( e.getMessage(), e );
}
catch ( SetupExecutionException e )
{
throw new MojoExecutionException( e.getMessage(), e );
}
postProcess();
}
/**
* Use VersionRange.createFromVersionSpec( String ) to define the range for which the goal can be used
*
* @return the versionRange
* @throws InvalidVersionSpecificationException The specification can't be converted to a range
* @since 1.0.0
*/
protected abstract VersionRange getMavenVersionRange() throws InvalidVersionSpecificationException;
/**
* Can be overridden, if you want to add extra info before processing. For instance: setup:security-settings uses
* this method to encrypt the master-password
*
* @throws MojoExecutionException possible executionException
* @throws MojoFailureException possible failureException
* @since 1.0.0
*/
protected void preProcess()
throws MojoExecutionException, MojoFailureException
{
}
/**
* Can be overridden, if you want to take actions after processing
*
* @throws MojoExecutionException possible executionException
* @throws MojoFailureException possible failureException
* @since 1.0.0
*/
protected void postProcess()
throws MojoExecutionException, MojoFailureException
{
}
/**
* Return list of propertyFiles as String, because that's how MavenFileFilter expects them
*
* @return List of propertyFilePaths or null
* @since 1.0.0
*/
protected List < String > getPropertyFiles()
{
List < String > result = null;
File propertyFile = FileUtils.resolveFile( getBaseDirectory(), getPropertiesFilename() );
if ( propertyFile.exists() )
{
result = Collections.singletonList( propertyFile.getAbsolutePath() );
}
return result;
}
/**
* During the initializingPhase we can check if the required Maven version is used.
*
* @param range the version range of Maven for which this goal is executable.
* @return true is version is within range, otherwise false.
*/
private boolean isRequiredMavenVersion( VersionRange range )
{
return range.containsVersion( rti.getApplicationVersion() );
}
}