blob: f0330bce37263829e732c11287bdebe59f9fa7cf [file] [log] [blame]
package org.apache.maven.plugins.assembly.archive.task;
/*
* 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.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.plugins.assembly.AssemblerConfigurationSource;
import org.apache.maven.plugins.assembly.InvalidAssemblerConfigurationException;
import org.apache.maven.plugins.assembly.archive.ArchiveCreationException;
import org.apache.maven.plugins.assembly.format.AssemblyFormattingException;
import org.apache.maven.plugins.assembly.format.ReaderFormatter;
import org.apache.maven.plugins.assembly.model.DependencySet;
import org.apache.maven.plugins.assembly.model.UnpackOptions;
import org.apache.maven.plugins.assembly.utils.AssemblyFormatUtils;
import org.apache.maven.plugins.assembly.utils.FilterUtils;
import org.apache.maven.plugins.assembly.utils.TypeConversionUtils;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.project.ProjectBuildingResult;
import org.apache.maven.shared.artifact.filter.resolve.ScopeFilter;
import org.apache.maven.shared.artifact.filter.resolve.transform.ArtifactIncludeFilterTransformer;
import org.codehaus.plexus.archiver.Archiver;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.components.io.functions.InputStreamTransformer;
import org.codehaus.plexus.interpolation.fixed.FixedStringSearchInterpolator;
import org.codehaus.plexus.logging.Logger;
/**
* @version $Id$
*/
public class AddDependencySetsTask
{
private static final List<String> NON_ARCHIVE_DEPENDENCY_TYPES;
static
{
final List<String> nonArch = new ArrayList<>();
nonArch.add( "pom" );
NON_ARCHIVE_DEPENDENCY_TYPES = Collections.unmodifiableList( nonArch );
}
private final List<DependencySet> dependencySets;
private final Logger logger;
private final MavenProject project;
private final ProjectBuilder projectBuilder1;
private final Set<Artifact> resolvedArtifacts;
private MavenProject moduleProject;
private String defaultOutputDirectory;
private String defaultOutputFileNameMapping;
private Artifact moduleArtifact;
public AddDependencySetsTask( final List<DependencySet> dependencySets, final Set<Artifact> resolvedArtifacts,
final MavenProject project, ProjectBuilder projectBuilder, final Logger logger )
{
this.dependencySets = dependencySets;
this.resolvedArtifacts = resolvedArtifacts;
this.project = project;
this.projectBuilder1 = projectBuilder;
this.logger = logger;
}
public void execute( final Archiver archiver, final AssemblerConfigurationSource configSource )
throws ArchiveCreationException, AssemblyFormattingException, InvalidAssemblerConfigurationException
{
if ( ( dependencySets == null ) || dependencySets.isEmpty() )
{
logger.debug( "No dependency sets specified." );
return;
}
final List<Dependency> deps = project.getDependencies();
if ( ( deps == null ) || deps.isEmpty() )
{
logger.debug( "Project " + project.getId() + " has no dependencies. Skipping dependency set addition." );
}
for ( final DependencySet dependencySet : dependencySets )
{
addDependencySet( dependencySet, archiver, configSource );
}
}
void addDependencySet( final DependencySet dependencySet, final Archiver archiver,
final AssemblerConfigurationSource configSource )
throws AssemblyFormattingException, ArchiveCreationException, InvalidAssemblerConfigurationException
{
logger.debug( "Processing DependencySet (output=" + dependencySet.getOutputDirectory() + ")" );
if ( !dependencySet.isUseTransitiveDependencies() && dependencySet.isUseTransitiveFiltering() )
{
logger.warn( "DependencySet has nonsensical configuration: useTransitiveDependencies == false "
+ "AND useTransitiveFiltering == true. Transitive filtering flag will be ignored." );
}
final Set<Artifact> dependencyArtifacts = resolveDependencyArtifacts( dependencySet );
if ( !unpackTransformsContent( dependencySet ) && dependencyArtifacts.size() > 1 )
{
checkMultiArtifactOutputConfig( dependencySet );
}
logger.debug( "Adding " + dependencyArtifacts.size() + " dependency artifacts." );
InputStreamTransformer fileSetTransformers =
isUnpackWithOptions( dependencySet )
? ReaderFormatter.getFileSetTransformers( configSource, dependencySet.getUnpackOptions().isFiltered(),
dependencySet.getUnpackOptions().getLineEnding() )
: null;
for ( final Artifact depArtifact : dependencyArtifacts )
{
ProjectBuildingRequest pbr = getProjectBuildingRequest( configSource );
MavenProject depProject;
try
{
ProjectBuildingResult build = projectBuilder1.build( depArtifact, pbr );
depProject = build.getProject();
}
catch ( final ProjectBuildingException e )
{
logger.debug(
"Error retrieving POM of module-dependency: " + depArtifact.getId() + "; Reason: " + e.getMessage()
+ "\n\nBuilding stub project instance." );
depProject = buildProjectStub( depArtifact );
}
if ( NON_ARCHIVE_DEPENDENCY_TYPES.contains( depArtifact.getType() ) )
{
addNonArchiveDependency( depArtifact, depProject, dependencySet, archiver, configSource );
}
else
{
addNormalArtifact( dependencySet, depArtifact, depProject, archiver, configSource,
fileSetTransformers );
}
}
}
private ProjectBuildingRequest getProjectBuildingRequest( AssemblerConfigurationSource configSource )
{
return configSource.getMavenSession().getProjectBuildingRequest();
}
private boolean isUnpackWithOptions( DependencySet dependencySet )
{
return dependencySet.isUnpack() && dependencySet.getUnpackOptions() != null;
}
private boolean unpackTransformsContent( DependencySet dependencySet )
{
return isUnpackWithOptions( dependencySet ) && isContentModifyingOption( dependencySet.getUnpackOptions() );
}
private boolean isContentModifyingOption( UnpackOptions opts )
{
return ( opts.isFiltered() || opts.getLineEnding() != null );
}
private void checkMultiArtifactOutputConfig( final DependencySet dependencySet )
{
String dir = dependencySet.getOutputDirectory();
if ( dir == null )
{
dir = defaultOutputDirectory;
}
String mapping = dependencySet.getOutputFileNameMapping();
if ( mapping == null )
{
mapping = defaultOutputFileNameMapping;
}
if ( ( dir == null || !dir.contains( "${" ) ) && ( mapping == null || !mapping.contains( "${" ) ) )
{
logger.warn( "NOTE: Your assembly specifies a dependencySet that matches multiple artifacts, but "
+ "specifies a concrete output format. THIS MAY RESULT IN ONE OR MORE ARTIFACTS BEING "
+ "OBSCURED!\n\n" + "Output directory: '" + dir + "'\nOutput filename mapping: '" + mapping
+ "'" );
}
}
private void addNormalArtifact( final DependencySet dependencySet, final Artifact depArtifact,
final MavenProject depProject, final Archiver archiver,
final AssemblerConfigurationSource configSource,
InputStreamTransformer fileSetTransformers )
throws AssemblyFormattingException, ArchiveCreationException
{
logger.debug( "Adding dependency artifact " + depArtifact.getId() + "." );
String encoding = isUnpackWithOptions( dependencySet ) ? dependencySet.getUnpackOptions().getEncoding() : null;
Charset charset = encoding != null ? Charset.forName( encoding ) : null;
final AddArtifactTask task = new AddArtifactTask( depArtifact, logger, fileSetTransformers, charset );
task.setProject( depProject );
task.setModuleProject( moduleProject );
task.setModuleArtifact( moduleArtifact );
task.setOutputDirectory( dependencySet.getOutputDirectory(), defaultOutputDirectory );
task.setFileNameMapping( dependencySet.getOutputFileNameMapping(), defaultOutputFileNameMapping );
final int dirMode = TypeConversionUtils.modeToInt( dependencySet.getDirectoryMode(), logger );
if ( dirMode != -1 )
{
task.setDirectoryMode( dirMode );
}
final int fileMode = TypeConversionUtils.modeToInt( dependencySet.getFileMode(), logger );
if ( fileMode != -1 )
{
task.setFileMode( fileMode );
}
task.setUnpack( dependencySet.isUnpack() );
final UnpackOptions opts = dependencySet.getUnpackOptions();
if ( isUnpackWithOptions( dependencySet ) )
{
task.setIncludes( opts.getIncludes() );
task.setExcludes( opts.getExcludes() );
}
task.execute( archiver, configSource );
}
private MavenProject buildProjectStub( final Artifact depArtifact )
{
final Model model = new Model();
model.setGroupId( depArtifact.getGroupId() );
model.setArtifactId( depArtifact.getArtifactId() );
model.setVersion( depArtifact.getBaseVersion() );
model.setPackaging( depArtifact.getType() );
model.setDescription( "Stub for " + depArtifact.getId() );
final MavenProject project = new MavenProject( model );
project.setArtifact( depArtifact );
return project;
}
Set<Artifact> resolveDependencyArtifacts( final DependencySet dependencySet )
throws InvalidAssemblerConfigurationException
{
final Set<Artifact> dependencyArtifacts = new LinkedHashSet<>();
if ( resolvedArtifacts != null )
{
dependencyArtifacts.addAll( resolvedArtifacts );
}
if ( dependencySet.isUseProjectArtifact() )
{
final Artifact projectArtifact = project.getArtifact();
if ( ( projectArtifact != null ) && ( projectArtifact.getFile() != null ) )
{
dependencyArtifacts.add( projectArtifact );
}
else
{
logger.warn( "Cannot include project artifact: " + projectArtifact
+ "; it doesn't have an associated file or directory." );
}
}
if ( dependencySet.isUseProjectAttachments() )
{
final List<Artifact> attachments = project.getAttachedArtifacts();
if ( attachments != null )
{
for ( final Artifact attachment : attachments )
{
if ( attachment.getFile() != null )
{
dependencyArtifacts.add( attachment );
}
else
{
logger.warn(
"Cannot include attached artifact: " + project.getId() + " for project: " + project.getId()
+ "; it doesn't have an associated file or directory." );
}
}
}
}
if ( dependencySet.isUseTransitiveFiltering() )
{
logger.debug( "Filtering dependency artifacts USING transitive dependency path information." );
}
else
{
logger.debug( "Filtering dependency artifacts WITHOUT transitive dependency path information." );
}
final ScopeFilter scopeFilter = FilterUtils.newScopeFilter( dependencySet.getScope() );
final ArtifactFilter filter = new ArtifactIncludeFilterTransformer().transform( scopeFilter );
FilterUtils.filterArtifacts( dependencyArtifacts, dependencySet.getIncludes(), dependencySet.getExcludes(),
dependencySet.isUseStrictFiltering(), dependencySet.isUseTransitiveFiltering(),
logger, filter );
return dependencyArtifacts;
}
private void addNonArchiveDependency( final Artifact depArtifact, final MavenProject depProject,
final DependencySet dependencySet, final Archiver archiver,
final AssemblerConfigurationSource configSource )
throws AssemblyFormattingException, ArchiveCreationException
{
final File source = depArtifact.getFile();
String outputDirectory = dependencySet.getOutputDirectory();
FixedStringSearchInterpolator moduleProjectInterpolator =
AssemblyFormatUtils.moduleProjectInterpolator( moduleProject );
FixedStringSearchInterpolator artifactProjectInterpolator =
AssemblyFormatUtils.artifactProjectInterpolator( depProject );
outputDirectory =
AssemblyFormatUtils.getOutputDirectory( outputDirectory, depProject.getBuild().getFinalName(), configSource,
moduleProjectInterpolator, artifactProjectInterpolator );
final String destName =
AssemblyFormatUtils.evaluateFileNameMapping( dependencySet.getOutputFileNameMapping(), depArtifact,
configSource.getProject(), moduleArtifact, configSource,
moduleProjectInterpolator, artifactProjectInterpolator );
String target;
// omit the last char if ends with / or \\
if ( outputDirectory.endsWith( "/" ) || outputDirectory.endsWith( "\\" ) )
{
target = outputDirectory + destName;
}
else
{
target = outputDirectory + "/" + destName;
}
try
{
final int mode = TypeConversionUtils.modeToInt( dependencySet.getFileMode(), logger );
if ( mode > -1 )
{
archiver.addFile( source, target, mode );
}
else
{
archiver.addFile( source, target );
}
}
catch ( final ArchiverException e )
{
throw new ArchiveCreationException( "Error adding file to archive: " + e.getMessage(), e );
}
}
public List<DependencySet> getDependencySets()
{
return dependencySets;
}
public Logger getLogger()
{
return logger;
}
public void setDefaultOutputDirectory( final String defaultOutputDirectory )
{
this.defaultOutputDirectory = defaultOutputDirectory;
}
public void setDefaultOutputFileNameMapping( final String defaultOutputFileNameMapping )
{
this.defaultOutputFileNameMapping = defaultOutputFileNameMapping;
}
public void setModuleProject( final MavenProject moduleProject )
{
this.moduleProject = moduleProject;
}
public void setModuleArtifact( final Artifact moduleArtifact )
{
this.moduleArtifact = moduleArtifact;
}
}