blob: 9593128476ec29147ea0705825830112f7149c9c [file] [log] [blame]
package org.apache.maven.plugins.assembly.utils;
/*
* 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 org.apache.maven.artifact.Artifact;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugins.assembly.AssemblerConfigurationSource;
import org.apache.maven.plugins.assembly.format.AssemblyFormattingException;
import org.apache.maven.plugins.assembly.model.Assembly;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.utils.Os;
import org.codehaus.plexus.interpolation.fixed.FixedStringSearchInterpolator;
import org.codehaus.plexus.interpolation.fixed.PrefixedObjectValueSource;
import org.codehaus.plexus.interpolation.fixed.PrefixedPropertiesValueSource;
import org.codehaus.plexus.interpolation.fixed.PropertiesBasedValueSource;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.StringUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import java.util.Properties;
/**
*
*/
public final class AssemblyFormatUtils
{
private AssemblyFormatUtils()
{
}
/**
* Get the full name of the distribution artifact
*
* @param assembly the assembly
* @return the distribution name
*/
public static String getDistributionName( final Assembly assembly, final AssemblerConfigurationSource configSource )
{
final String finalName = configSource.getFinalName();
final boolean appendAssemblyId = configSource.isAssemblyIdAppended();
String distributionName = finalName;
if ( appendAssemblyId )
{
distributionName = finalName + "-" + assembly.getId();
}
return distributionName;
}
@Nonnull
public static FixedStringSearchInterpolator finalNameInterpolator( String finalName )
{
final Properties specialExpressionOverrides = new Properties();
if ( finalName != null )
{
specialExpressionOverrides.setProperty( "finalName", finalName );
specialExpressionOverrides.setProperty( "build.finalName", finalName );
}
else
{
return FixedStringSearchInterpolator.empty();
}
return FixedStringSearchInterpolator.create( new PropertiesBasedValueSource( specialExpressionOverrides ) );
}
@Nonnull
public static FixedStringSearchInterpolator moduleProjectInterpolator( final MavenProject moduleProject )
{
if ( moduleProject != null )
{
return FixedStringSearchInterpolator.createWithPermittedNulls(
new PrefixedObjectValueSource( "module.", moduleProject ),
new PrefixedPropertiesValueSource( "module.properties.", moduleProject.getProperties() ),
moduleProject.getArtifact() != null
? new PrefixedObjectValueSource( "module.", moduleProject.getArtifact() )
: null );
}
else
{
return FixedStringSearchInterpolator.empty();
}
}
public static FixedStringSearchInterpolator moduleArtifactInterpolator( Artifact moduleArtifact )
{
if ( moduleArtifact != null )
{
// CHECKSTYLE_OFF: LineLength
return FixedStringSearchInterpolator.create( new PrefixedObjectValueSource( "module.", moduleArtifact ),
new PrefixedObjectValueSource( "module.",
moduleArtifact
.getArtifactHandler() ),
new PrefixedObjectValueSource( "module.handler.",
moduleArtifact
.getArtifactHandler() ) );
// CHECKSTYLE_ON: LineLength
}
else
{
return FixedStringSearchInterpolator.empty();
}
}
@Nonnull
public static FixedStringSearchInterpolator artifactProjectInterpolator( final MavenProject artifactProject )
{
if ( artifactProject != null )
{
PrefixedObjectValueSource vs = null;
if ( artifactProject.getArtifact() != null )
{
vs = new PrefixedObjectValueSource( "artifact.", artifactProject.getArtifact() );
}
return FixedStringSearchInterpolator.createWithPermittedNulls(
new PrefixedObjectValueSource( "artifact.", artifactProject ),
new PrefixedPropertiesValueSource( "artifact.properties.", artifactProject.getProperties() ), vs );
}
else
{
return FixedStringSearchInterpolator.empty();
}
}
@Nonnull
public static FixedStringSearchInterpolator artifactInterpolator( @Nonnull final Artifact artifact )
{
return FixedStringSearchInterpolator.create( new PrefixedObjectValueSource( "artifact.", artifact ),
new PrefixedObjectValueSource( "artifact.",
artifact.getArtifactHandler() ),
new PrefixedObjectValueSource( "artifact.handler.",
artifact.getArtifactHandler() ) );
}
@Nonnull
public static FixedStringSearchInterpolator classifierRules( final Artifact artifact )
{
final Properties specialRules = new Properties();
final String classifier = ProjectUtils.getClassifier( artifact );
if ( classifier != null )
{
specialRules.setProperty( "dashClassifier?", "-" + classifier );
specialRules.setProperty( "dashClassifier", "-" + classifier );
}
else
{
specialRules.setProperty( "dashClassifier?", "" );
specialRules.setProperty( "dashClassifier", "" );
}
return FixedStringSearchInterpolator.create( new PropertiesBasedValueSource( specialRules ) );
}
/**
* ORDER OF INTERPOLATION PRECEDENCE:
* <ol>
* <li>Support for special expressions, like ${finalName} (use the assembly plugin configuration not the build
* config)</li>
* <li>prefixed with "module." if moduleProject is non-null
* <ol>
* <li>MavenProject instance for module being assembled</li>
* </ol>
* </li>
* <li>prefixed with "artifact." if artifactProject is non-null
* <ol>
* <li>MavenProject instance for artifact</li>
* </ol>
* </li>
* <li>user-defined properties from the command line</li>
* <li>prefixed with "pom." or "project.", or no prefix at all
* <ol>
* <li>MavenProject instance from current build</li>
* </ol>
* </li>
* <li>properties from main project</li>
* <li>system properties, from the MavenSession instance (to support IDEs)</li>
* <li>environment variables.</li>
* </ol>
*/
public static String getOutputDirectory( final String output, final MavenProject artifactProject,
final String finalName, final AssemblerConfigurationSource configSource )
throws AssemblyFormattingException
{
return getOutputDirectory( output, finalName, configSource, moduleProjectInterpolator( null ),
artifactProjectInterpolator( artifactProject ) );
}
private static FixedStringSearchInterpolator executionPropertiesInterpolator(
AssemblerConfigurationSource configSource )
{
MavenSession session;
if ( configSource != null )
{
session = configSource.getMavenSession();
if ( session != null )
{
Properties userProperties = session.getExecutionProperties(); // this is added twice....
if ( userProperties != null )
{
return FixedStringSearchInterpolator.create( new PropertiesBasedValueSource( userProperties ) );
}
}
}
return FixedStringSearchInterpolator.empty();
}
private static FixedStringSearchInterpolator mainProjectOnlyInterpolator( MavenProject mainProject )
{
if ( mainProject != null )
{
// 5
return FixedStringSearchInterpolator.create(
new org.codehaus.plexus.interpolation.fixed.PrefixedObjectValueSource(
InterpolationConstants.PROJECT_PREFIXES, mainProject, true ) );
}
else
{
return FixedStringSearchInterpolator.empty();
}
}
/**
* ORDER OF INTERPOLATION PRECEDENCE:
* <ol>
* <li>prefixed with "module.", if moduleProject != null
* <ol>
* <li>Artifact instance for module, if moduleArtifact != null</li>
* <li>ArtifactHandler instance for module, if moduleArtifact != null</li>
* <li>MavenProject instance for module</li>
* </ol>
* </li>
* <li>prefixed with "artifact."
* <ol>
* <li>Artifact instance</li>
* <li>ArtifactHandler instance for artifact</li>
* <li>MavenProject instance for artifact</li>
* </ol>
* </li>
* <li>prefixed with "pom." or "project."
* <ol>
* <li>MavenProject instance from current build</li>
* </ol>
* </li>
* <li>no prefix, using main project instance
* <ol>
* <li>MavenProject instance from current build</li>
* </ol>
* </li>
* <li>Support for special expressions, like ${dashClassifier?}</li>
* <li>user-defined properties from the command line</li>
* <li>properties from main project</li>
* <li>system properties, from the MavenSession instance (to support IDEs)</li>
* <li>environment variables.</li>
* </ol>
*/
@Nonnull
public static String fixRelativeRefs( @Nonnull String src )
{
String value = src;
String[] separators = { "/", "\\" };
String finalSep = null;
for ( String sep : separators )
{
if ( value.endsWith( sep ) )
{
finalSep = sep;
}
if ( value.contains( "." + sep ) )
{
List<String> parts = new ArrayList<>();
parts.addAll( Arrays.asList( value.split( sep.replace( "\\", "\\\\" ) ) ) );
for ( ListIterator<String> it = parts.listIterator(); it.hasNext(); )
{
String part = it.next();
if ( ".".equals( part ) )
{
it.remove();
}
else if ( "..".equals( part ) )
{
it.remove();
if ( it.hasPrevious() )
{
it.previous();
it.remove();
}
}
}
value = StringUtils.join( parts.iterator(), sep );
}
}
if ( finalSep != null && value.length() > 0 && !value.endsWith( finalSep ) )
{
value += finalSep;
}
return value;
}
/**
* ORDER OF INTERPOLATION PRECEDENCE:
* <ol>
* <li>prefixed with "module.", if moduleProject != null
* <ol>
* <li>Artifact instance for module, if moduleArtifact != null</li>
* <li>ArtifactHandler instance for module, if moduleArtifact != null</li>
* <li>MavenProject instance for module</li>
* </ol>
* </li>
* <li>prefixed with "artifact."
* <ol>
* <li>Artifact instance</li>
* <li>ArtifactHandler instance for artifact</li>
* <li>MavenProject instance for artifact</li>
* </ol>
* </li>
* <li>prefixed with "pom." or "project."
* <ol>
* <li>MavenProject instance from current build</li>
* </ol>
* </li>
* <li>no prefix, using main project instance
* <ol>
* <li>MavenProject instance from current build</li>
* </ol>
* </li>
* <li>Support for special expressions, like ${dashClassifier?}</li>
* <li>user-defined properties from the command line</li>
* <li>properties from main project</li>
* <li>system properties, from the MavenSession instance (to support IDEs)</li>
* <li>environment variables.</li>
* </ol>
*/
public static String evaluateFileNameMapping( final String expression, @Nonnull final Artifact artifact,
@Nullable final MavenProject mainProject,
@Nullable final Artifact moduleArtifact,
@Nonnull final AssemblerConfigurationSource configSource,
FixedStringSearchInterpolator moduleProjectInterpolator,
FixedStringSearchInterpolator artifactProjectInterpolator )
throws AssemblyFormattingException
{
String value = expression;
final FixedStringSearchInterpolator interpolator =
FixedStringSearchInterpolator.create( moduleArtifactInterpolator( moduleArtifact ),
moduleProjectInterpolator, artifactInterpolator( artifact ),
artifactProjectInterpolator,
mainProjectOnlyInterpolator( mainProject ),
classifierRules( artifact ),
executionPropertiesInterpolator( configSource ),
configSource.getMainProjectInterpolator(),
configSource.getCommandLinePropsInterpolator(),
configSource.getEnvInterpolator() );
value = interpolator.interpolate( value );
value = StringUtils.replace( value, "//", "/" );
value = StringUtils.replace( value, "\\\\", "\\" );
value = fixRelativeRefs( value );
return value;
}
/**
* ORDER OF INTERPOLATION PRECEDENCE:
* <ol>
* <li>Support for special expressions, like ${finalName} (use the assembly plugin configuration not the build
* config)</li>
* <li>prefixed with "module." if moduleProject is non-null
* <ol>
* <li>MavenProject instance for module being assembled</li>
* </ol>
* </li>
* <li>prefixed with "artifact." if artifactProject is non-null
* <ol>
* <li>MavenProject instance for artifact</li>
* </ol>
* </li>
* <li>user-defined properties from the command line</li>
* <li>prefixed with "pom." or "project.", or no prefix at all
* <ol>
* <li>MavenProject instance from current build</li>
* </ol>
* </li>
* <li>properties from main project</li>
* <li>system properties, from the MavenSession instance (to support IDEs)</li>
* <li>environment variables.</li>
* </ol>
*/
public static String getOutputDirectory( final String output, final String finalName,
final AssemblerConfigurationSource configSource,
FixedStringSearchInterpolator moduleProjectIntrpolator,
FixedStringSearchInterpolator artifactProjectInterpolator )
throws AssemblyFormattingException
{
String value = output;
if ( value == null )
{
value = "";
}
final FixedStringSearchInterpolator interpolator =
FixedStringSearchInterpolator.create( finalNameInterpolator( finalName ), moduleProjectIntrpolator,
artifactProjectInterpolator,
executionPropertiesInterpolator( configSource ),
configSource.getMainProjectInterpolator(),
configSource.getCommandLinePropsInterpolator(),
configSource.getEnvInterpolator() );
value = interpolator.interpolate( value );
if ( ( value.length() > 0 ) && !value.endsWith( "/" ) && !value.endsWith( "\\" ) )
{
value += "/";
}
if ( ( value.length() > 0 ) && ( value.startsWith( "/" ) || value.startsWith( "\\" ) ) )
{
value = value.substring( 1 );
}
value = StringUtils.replace( value, "//", "/" );
value = StringUtils.replace( value, "\\\\", "\\" );
value = fixRelativeRefs( value );
return value;
}
public static void warnForPlatformSpecifics( Logger logger, String destDirectory )
{
if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
{
if ( isLinuxRootReference( destDirectory ) )
{
logger.error( "OS=Windows and the assembly descriptor contains a *nix-specific root-relative-reference"
+ " (starting with slash) " + destDirectory );
}
else if ( isWindowsPath( destDirectory ) )
{
logger.warn( "The assembly descriptor contains a *nix-specific root-relative-reference"
+ " (starting with slash). This is non-portable and will fail on windows "
+ destDirectory );
}
}
else
{
if ( isWindowsPath( destDirectory ) )
{
logger.error(
"OS=Non-Windows and the assembly descriptor contains a windows-specific directory reference"
+ " (with a drive letter) " + destDirectory );
}
else if ( isLinuxRootReference( destDirectory ) )
{
logger.warn( "The assembly descriptor contains a filesystem-root relative reference,"
+ " which is not cross platform compatible " + destDirectory );
}
}
}
static boolean isWindowsPath( String destDirectory )
{
return ( destDirectory != null && destDirectory.length() >= 2 && destDirectory.charAt( 1 ) == ':' );
}
static boolean isLinuxRootReference( String destDirectory )
{
return ( destDirectory != null && destDirectory.startsWith( "/" ) );
}
}