org.codehaus.mojo.flatten.FlattenMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of flatten-maven-plugin Show documentation
Show all versions of flatten-maven-plugin Show documentation
Plugin to generate flattened POM (reduced and resolved information required for consumers of maven repositories) and to use (install, sign, deploy) it instead of original pom.xml.
/*
* 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.
*/
package org.codehaus.mojo.flatten;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Activation;
import org.apache.maven.model.Build;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.Profile;
import org.apache.maven.model.Repository;
import org.apache.maven.model.RepositoryPolicy;
import org.apache.maven.model.building.DefaultModelBuilder;
import org.apache.maven.model.building.DefaultModelBuilderFactory;
import org.apache.maven.model.building.DefaultModelBuildingRequest;
import org.apache.maven.model.building.ModelBuildingException;
import org.apache.maven.model.building.ModelBuildingRequest;
import org.apache.maven.model.building.ModelBuildingResult;
import org.apache.maven.model.building.ModelProblemCollector;
import org.apache.maven.model.interpolation.ModelInterpolator;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.apache.maven.model.profile.ProfileActivationContext;
import org.apache.maven.model.profile.ProfileInjector;
import org.apache.maven.model.profile.ProfileSelector;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.codehaus.mojo.flatten.model.resolution.FlattenModelResolver;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.ext.DefaultHandler2;
/**
* This MOJO realizes the goal flatten
that generates the flattened POM and {@link #isUpdatePomFile()
* potentially updates the POM file} so that the current {@link MavenProject}'s {@link MavenProject#getFile() file}
* points to the flattened POM instead of the original pom.xml
file.
* The flattened POM is a reduced version of the original POM with the focus to contain only the important information
* for consuming it. Therefore information that is only required for maintenance by developers and to build the project
* artifact(s) are stripped.
* Starting from here we specify how the flattened POM is created from the original POM and its project:
*
*
* Element
* Transformation
* Note
*
*
* {@link Model#getModelVersion() modelVersion}
* Fixed to "4.0.0"
* New maven versions will once be able to evolve the model version without incompatibility to older versions if
* flattened POMs get deployed.
*
*
* {@link Model#getGroupId() groupId}
* {@link Model#getArtifactId() artifactId}
* {@link Model#getVersion() version}
* {@link Model#getPackaging() packaging}
*
* resolved
* copied to the flattened POM but with inheritance from {@link Model#getParent() parent} as well as with all
* variables and defaults resolved. These elements are technically required for consumption.
*
*
* {@link Model#getLicenses() licenses}
*
* resolved
* copied to the flattened POM but with inheritance from {@link Model#getParent() parent} as well as with all
* variables and defaults resolved. The licenses would not be required in flattened POM. However, they make sense for
* publication and deployment and are important for consumers of your artifact.
*
*
* {@link Model#getDependencies() dependencies}
* resolved specially
* flattened POM contains the actual dependencies of the project. Test dependencies are removed. Variables and
* {@link Model#getDependencyManagement() dependencyManagement} is resolved to get fixed dependency attributes
* (especially {@link Dependency#getVersion() version}). If {@link #isEmbedBuildProfileDependencies()
* embedBuildProfileDependencies} is set to true
, then also build-time driven {@link Profile}s will be
* evaluated and may add {@link Dependency dependencies}. For further details see {@link Profile}s below.
*
*
* {@link Model#getProfiles() profiles}
* resolved specially
* only the {@link Activation} and the {@link Dependency dependencies} of a {@link Profile} are copied to the
* flattened POM. If you set the parameter {@link #isEmbedBuildProfileDependencies() embedBuildProfileDependencies} to
* true
then only profiles {@link Activation activated} by {@link Activation#getJdk() JDK} or
* {@link Activation#getOs() OS} will be added to the flattened POM while the other profiles are triggered by the
* current build setup and if activated their impact on dependencies is embedded into the resulting flattened POM.
*
*
* {@link Model#getName() name}
* {@link Model#getDescription() description}
* {@link Model#getUrl() url}
* {@link Model#getInceptionYear() inceptionYear}
* {@link Model#getOrganization() organization}
* {@link Model#getScm() scm}
* {@link Model#getDevelopers() developers}
* {@link Model#getContributors() contributors}
* {@link Model#getMailingLists() mailingLists}
* {@link Model#getPluginRepositories() pluginRepositories}
* {@link Model#getIssueManagement() issueManagement}
* {@link Model#getCiManagement() ciManagement}
* {@link Model#getDistributionManagement() distributionManagement}
*
* configurable
* Will be stripped from the flattened POM by default. You can configure all of the listed elements inside
* pomElements
that should be kept in the flattened POM (e.g. {@literal
* }). For common use-cases there are
* predefined modes available via the parameter flattenMode
that should be used in preference.
*
*
* {@link Model#getPrerequisites() prerequisites}
* configurable
* Like above but by default NOT removed if packaging is "maven-plugin".
*
*
* {@link Model#getRepositories() repositories}
* configurable
* Like two above but by default NOT removed. If you want have it removed, you need to use the parameter
* pomElements
and configure the child element repositories
with value flatten
.
*
*
* {@link Model#getParent() parent}
* {@link Model#getBuild() build}
* {@link Model#getDependencyManagement() dependencyManagement}
* {@link Model#getProperties() properties}
* {@link Model#getModules() modules}
* {@link Model#getReporting() reporting}
* configurable
* These elements should typically be completely stripped from the flattened POM. However for ultimate flexibility
* (e.g. if you only want to resolve variables in a POM with packaging pom) you can also configure to keep these
* elements. We strictly recommend to use this feature with extreme care and only if packaging is pom (for
* "Bill of Materials"). In the latter case you configure the parameter flattenMode
to the value
* bom
.
*
*
*
* @author Joerg Hohwiller (hohwille at users.sourceforge.net)
*/
@SuppressWarnings( "deprecation" )
@Mojo( name = "flatten", requiresProject = true, requiresDirectInvocation = false, executionStrategy = "once-per-session", requiresDependencyCollection = ResolutionScope.RUNTIME )
public class FlattenMojo
extends AbstractFlattenMojo
{
/**
* The Maven Project.
*/
@Parameter( defaultValue = "${project}", readonly = true, required = true )
private MavenProject project;
/**
* The flag to indicate if the generated flattened POM shall be set as POM file to the current project. By default
* this is only done for projects with packaging other than pom
. You may want to also do this for
* pom
packages projects by setting this parameter to true
or you can use
* false
in order to only generate the flattened POM but never set it as POM file.
*/
@Parameter( property = "updatePomFile" )
private Boolean updatePomFile;
/** The {@link ArtifactRepository} required to resolve POM using {@link #modelBuilder}. */
@Parameter( defaultValue = "${localRepository}", readonly = true, required = true )
private ArtifactRepository localRepository;
/**
* Profiles activated by OS or JDK are valid ways to have different dependencies per environment. However, profiles
* activated by property of file are less clear. When setting this parameter to true
, the latter
* dependencies will be written as direct dependencies of the project. This is not how Maven2 and Maven3
* handles dependencies. When keeping this property false
, all profiles will stay in the
* flattened-pom.
*/
@Parameter( defaultValue = "false" )
private Boolean embedBuildProfileDependencies;
/**
* The {@link MojoExecution} used to get access to the raw configuration of {@link #pomElements} as empty tags are
* mapped to null.
*/
@Parameter( defaultValue = "${mojo}", readonly = true, required = true )
private MojoExecution mojoExecution;
/**
* The {@link Model} that defines how to handle additional POM elements. Please use flattenMode
in
* preference if possible. This parameter is only for ultimate flexibility.
*/
@Parameter( required = false )
private FlattenDescriptor pomElements;
/** The {@link FlattenMode} */
@Parameter( required = false )
private FlattenMode flattenMode;
/** The ArtifactFactory required to resolve POM using {@link #modelBuilder}. */
// Neither ArtifactFactory nor DefaultArtifactFactory tells what to use instead
@Component
private ArtifactFactory artifactFactory;
/** The {@link ModelInterpolator} used to resolve variables. */
@Component( role = ModelInterpolator.class )
private ModelInterpolator modelInterpolator;
/** The {@link MavenSession} used to get user properties. */
@Component
private MavenSession session;
/**
* The constructor.
*/
public FlattenMojo()
{
super();
}
/**
* {@inheritDoc}
*/
public void execute()
throws MojoExecutionException, MojoFailureException
{
getLog().info( "Generating flattened POM of project " + this.project.getId() + "..." );
File originalPomFile = this.project.getFile();
Model flattenedPom = createFlattenedPom( originalPomFile );
String headerComment = extractHeaderComment( originalPomFile );
File flattenedPomFile = getFlattenedPomFile();
writePom( flattenedPom, flattenedPomFile, headerComment );
if ( isUpdatePomFile() )
{
this.project.setFile( flattenedPomFile );
}
}
/**
* This method extracts the XML header comment if available.
*
* @param xmlFile is the XML {@link File} to parse.
* @return the XML comment between the XML header declaration and the root tag or null
if NOT
* available.
* @throws MojoExecutionException if anything goes wrong.
*/
protected String extractHeaderComment( File xmlFile )
throws MojoExecutionException
{
try
{
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
SaxHeaderCommentHandler handler = new SaxHeaderCommentHandler();
parser.setProperty( "http://xml.org/sax/properties/lexical-handler", handler );
parser.parse( xmlFile, handler );
return handler.getHeaderComment();
}
catch ( Exception e )
{
throw new MojoExecutionException( "Failed to parse XML from " + xmlFile, e );
}
}
/**
* Writes the given POM {@link Model} to the given {@link File}.
*
* @param pom the {@link Model} of the POM to write.
* @param pomFile the {@link File} where to write the given POM will be written to. {@link File#getParentFile()
* Parent directories} are {@link File#mkdirs() created} automatically.
* @param headerComment is the content of a potential XML comment at the top of the XML (after XML declaration and
* before root tag). May be null
if not present and to be omitted in target POM.
* @throws MojoExecutionException if the operation failed (e.g. due to an {@link IOException}).
*/
protected void writePom( Model pom, File pomFile, String headerComment )
throws MojoExecutionException
{
File parentFile = pomFile.getParentFile();
if ( !parentFile.exists() )
{
boolean success = parentFile.mkdirs();
if ( !success )
{
throw new MojoExecutionException( "Failed to create directory " + pomFile.getParent() );
}
}
// MavenXpp3Writer could internally add the comment but does not expose such feature to API!
// Instead we have to write POM XML to String and do post processing on that :(
MavenXpp3Writer pomWriter = new MavenXpp3Writer();
StringWriter stringWriter = new StringWriter( 4096 );
try
{
pomWriter.write( stringWriter, pom );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Internal I/O error!", e );
}
StringBuffer buffer = stringWriter.getBuffer();
if ( !StringUtils.isEmpty( headerComment ) )
{
int projectStartIndex = buffer.indexOf( "= 0 )
{
buffer.insert( projectStartIndex, "\n" );
}
else
{
getLog().warn( "POM XML post-processing failed: no project tag found!" );
}
}
writeStringToFile( buffer.toString(), pomFile, pom.getModelEncoding() );
}
/**
* Writes the given data
to the given file
using the specified encoding
.
*
* @param data is the {@link String} to write.
* @param file is the {@link File} to write to.
* @param encoding is the encoding to use for writing the file.
* @throws MojoExecutionException if anything goes wrong.
*/
protected void writeStringToFile( String data, File file, String encoding )
throws MojoExecutionException
{
OutputStream outStream = null;
Writer writer = null;
try
{
outStream = new FileOutputStream( file );
writer = new OutputStreamWriter( outStream, encoding );
writer.write( data );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Failed to write to " + file, e );
}
finally
{
// resource-handling not perfectly solved but we do not want to require java 1.7
// and this is not a server application.
IOUtil.close( writer );
IOUtil.close( outStream );
}
}
/**
* This method creates the flattened POM what is the main task of this plugin.
*
* @param pomFile is the name of the original POM file to read and transform.
* @return the {@link Model} of the flattened POM.
* @throws MojoExecutionException if anything goes wrong (e.g. POM can not be processed).
* @throws MojoFailureException if anything goes wrong (logical error).
*/
protected Model createFlattenedPom( File pomFile )
throws MojoExecutionException, MojoFailureException
{
ModelBuildingRequest buildingRequest = createModelBuildingRequest( pomFile );
Model effectivePom = createEffectivePom( buildingRequest, isEmbedBuildProfileDependencies() );
Model flattenedPom = new Model();
// keep original encoding (we could also normalize to UTF-8 here)
String modelEncoding = effectivePom.getModelEncoding();
if ( StringUtils.isEmpty( modelEncoding ) )
{
modelEncoding = "UTF-8";
}
flattenedPom.setModelEncoding( modelEncoding );
Model cleanPom = createCleanPom( effectivePom );
FlattenDescriptor descriptor = getFlattenDescriptor();
Model originalPom = this.project.getOriginalModel();
Model resolvedPom = this.project.getModel();
Model interpolatedPom = createResolvedPom( buildingRequest );
// copy the configured additional POM elements...
for ( PomProperty> property : PomProperty.getPomProperties() )
{
if ( property.isElement() )
{
Model sourceModel = getSourceModel( descriptor, property, effectivePom, originalPom, resolvedPom,
interpolatedPom, cleanPom );
if ( sourceModel == null )
{
if ( property.isRequired() )
{
throw new MojoFailureException( "Property " + property.getName()
+ " is required and can not be removed!" );
}
}
else
{
property.copy( sourceModel, flattenedPom );
}
}
}
return flattenedPom;
}
private Model createResolvedPom( ModelBuildingRequest buildingRequest )
{
LoggingModelProblemCollector problems = new LoggingModelProblemCollector( getLog() );
Model originalModel = this.project.getOriginalModel().clone();
return this.modelInterpolator.interpolateModel( originalModel, this.project.getModel().getProjectDirectory(),
buildingRequest, problems );
}
/**
* This method creates the clean POM as a {@link Model} where to copy elements from that shall be
* {@link ElementHandling#flatten flattened}. Will be mainly empty but contains some the minimum elements that have
* to be kept in flattened POM.
*
* @param effectivePom is the effective POM.
* @return the clean POM.
*/
protected Model createCleanPom( Model effectivePom )
{
Model cleanPom = new Model();
cleanPom.setGroupId( effectivePom.getGroupId() );
cleanPom.setArtifactId( effectivePom.getArtifactId() );
cleanPom.setVersion( effectivePom.getVersion() );
cleanPom.setPackaging( effectivePom.getPackaging() );
cleanPom.setLicenses( effectivePom.getLicenses() );
// fixed to 4.0.0 forever :)
cleanPom.setModelVersion( "4.0.0" );
// plugins with extensions must stay
Build build = effectivePom.getBuild();
if ( build != null )
{
for ( Plugin plugin : build.getPlugins() )
{
if ( plugin.isExtensions() )
{
Build cleanBuild = cleanPom.getBuild();
if ( cleanBuild == null )
{
cleanBuild = new Build();
cleanPom.setBuild( cleanBuild );
}
Plugin cleanPlugin = new Plugin();
cleanPlugin.setGroupId( plugin.getGroupId() );
cleanPlugin.setArtifactId( plugin.getArtifactId() );
cleanPlugin.setVersion( plugin.getVersion() );
cleanPlugin.setExtensions( true );
cleanBuild.addPlugin( cleanPlugin );
}
}
}
// transform profiles...
for ( Profile profile : effectivePom.getProfiles() )
{
if ( !isEmbedBuildProfileDependencies() || !isBuildTimeDriven( profile.getActivation() ) )
{
if ( !isEmpty( profile.getDependencies() ) || !isEmpty( profile.getRepositories() ) )
{
Profile strippedProfile = new Profile();
strippedProfile.setId( profile.getId() );
strippedProfile.setActivation( profile.getActivation() );
strippedProfile.setDependencies( profile.getDependencies() );
strippedProfile.setRepositories( profile.getRepositories() );
cleanPom.addProfile( strippedProfile );
}
}
}
// transform dependencies...
List dependencies = createFlattenedDependencies( effectivePom );
cleanPom.setDependencies( dependencies );
return cleanPom;
}
private Model getSourceModel( FlattenDescriptor descriptor, PomProperty> property, Model effectivePom,
Model originalPom, Model resolvedPom, Model interpolatedPom, Model cleanPom )
{
ElementHandling handling = descriptor.getHandling( property );
getLog().debug( "Property " + property.getName() + " will be handled using " + handling
+ " in flattened POM." );
switch ( handling )
{
case expand:
return effectivePom;
case keep:
return originalPom;
case resolve:
return resolvedPom;
case interpolate:
return interpolatedPom;
case flatten:
return cleanPom;
case remove:
return null;
default:
throw new IllegalStateException( handling.toString() );
}
}
/**
* Creates a flattened {@link List} of {@link Repository} elements where those from super-POM are omitted.
*
* @param repositories is the {@link List} of {@link Repository} elements. May be null
.
* @return the flattened {@link List} of {@link Repository} elements or null
if null
was
* given.
*/
protected static List createFlattenedRepositories( List repositories )
{
if ( repositories != null )
{
List flattenedRepositories = new ArrayList( repositories.size() );
for ( Repository repo : repositories )
{
// filter inherited repository section from super POM (see MOJO-2042)...
if ( !isCentralRepositoryFromSuperPom( repo ) )
{
flattenedRepositories.add( repo );
}
}
return flattenedRepositories;
}
return repositories;
}
private FlattenDescriptor getFlattenDescriptor()
throws MojoFailureException
{
FlattenDescriptor descriptor = this.pomElements;
if ( descriptor == null )
{
FlattenMode mode = this.flattenMode;
if ( mode == null )
{
mode = FlattenMode.defaults;
}
else if ( this.flattenMode == FlattenMode.minimum )
{
getLog().warn( "FlattenMode " + FlattenMode.minimum + " is deprecated!" );
}
descriptor = mode.getDescriptor();
if ( "maven-plugin".equals( this.project.getPackaging() ) )
{
descriptor.setPrerequisites( ElementHandling.expand );
}
}
else
{
if ( descriptor.isEmpty() )
{
// legacy approach...
// Can't use Model itself as empty elements are never null, so you can't recognize if it was set or not
Xpp3Dom rawDescriptor = this.mojoExecution.getConfiguration().getChild( "pomElements" );
descriptor = new FlattenDescriptor( rawDescriptor );
}
if ( this.flattenMode != null )
{
descriptor = descriptor.merge( this.flattenMode.getDescriptor() );
}
}
return descriptor;
}
/**
* This method determines if the given {@link Repository} section is identical to what is defined from the super
* POM.
*
* @param repo is the {@link Repository} section to check.
* @return true
if maven central default configuration, false
otherwise.
*/
private static boolean isCentralRepositoryFromSuperPom( Repository repo )
{
if ( repo != null )
{
if ( "central".equals( repo.getId() ) )
{
RepositoryPolicy snapshots = repo.getSnapshots();
if ( ( snapshots != null ) && !snapshots.isEnabled() )
{
return true;
}
}
}
return false;
}
private ModelBuildingRequest createModelBuildingRequest( File pomFile )
{
FlattenModelResolver resolver = new FlattenModelResolver( this.localRepository, this.artifactFactory );
Properties userProperties = this.session.getUserProperties();
ModelBuildingRequest buildingRequest =
new DefaultModelBuildingRequest().setUserProperties( userProperties ).setSystemProperties( System.getProperties() ).setPomFile( pomFile ).setModelResolver( resolver );
return buildingRequest;
}
/**
* Creates the effective POM for the given pomFile
trying its best to match the core maven behaviour.
*
* @return the parsed and calculated effective POM.
* @throws MojoExecutionException if anything goes wrong.
*/
protected static Model createEffectivePom( ModelBuildingRequest buildingRequest,
final boolean embedBuildProfileDependencies )
throws MojoExecutionException
{
ModelBuildingResult buildingResult;
try
{
ProfileInjector profileInjector = new ProfileInjector()
{
public void injectProfile( Model model, Profile profile, ModelBuildingRequest request,
ModelProblemCollector problems )
{
// do nothing
}
};
ProfileSelector profileSelector = new ProfileSelector()
{
public List getActiveProfiles( Collection profiles, ProfileActivationContext context,
ModelProblemCollector problems )
{
List activeProfiles = new ArrayList( profiles.size() );
for ( Profile profile : profiles )
{
Activation activation = profile.getActivation();
if ( !embedBuildProfileDependencies || isBuildTimeDriven( activation ) )
{
activeProfiles.add( profile );
}
}
return activeProfiles;
}
};
DefaultModelBuilder defaultModelBuilder = new DefaultModelBuilderFactory().newInstance();
defaultModelBuilder.setProfileInjector( profileInjector ).setProfileSelector( profileSelector );
buildingResult = defaultModelBuilder.build( buildingRequest );
}
catch ( ModelBuildingException e )
{
throw new MojoExecutionException( e.getMessage(), e );
}
Model effectivePom = buildingResult.getEffectiveModel();
// LoggingModelProblemCollector problems = new LoggingModelProblemCollector( getLog() );
// Model interpolatedModel =
// this.modelInterpolator.interpolateModel( this.project.getOriginalModel(),
// effectivePom.getProjectDirectory(), buildingRequest, problems );
// remove Repositories from super POM (central)
effectivePom.setRepositories( createFlattenedRepositories( effectivePom.getRepositories() ) );
return effectivePom;
}
/**
* Null-safe check for {@link Collection#isEmpty()}.
*
* @param collection is the {@link Collection} to test. May be null
.
* @return true
if null
or {@link Collection#isEmpty() empty}, false
* otherwise.
*/
private boolean isEmpty( Collection> collection )
{
if ( collection == null )
{
return true;
}
return collection.isEmpty();
}
/**
* @return true
if build-dependent profiles (triggered by OS or JDK) should be evaluated and their
* effect (variables and dependencies) are resolved and embedded into the flattened POM while the profile
* itself is stripped. Otherwise if false
the profiles will remain untouched.
*/
public boolean isEmbedBuildProfileDependencies()
{
return this.embedBuildProfileDependencies.booleanValue();
}
/**
* @param activation is the {@link Activation} of a {@link Profile}.
* @return true
if the given {@link Activation} is build-time driven, false
otherwise (if
* it is triggered by OS or JDK).
*/
protected static boolean isBuildTimeDriven( Activation activation )
{
if ( activation == null )
{
return true;
}
if ( StringUtils.isEmpty( activation.getJdk() ) && ( activation.getOs() == null ) )
{
return true;
}
return false;
}
/**
* Creates the {@link List} of {@link Dependency dependencies} for the flattened POM. These are all resolved
* {@link Dependency dependencies} except for those added from {@link Profile profiles}.
*
* @param effectiveModel is the effective POM {@link Model} to process.
* @return the {@link List} of {@link Dependency dependencies}.
*/
protected List createFlattenedDependencies( Model effectiveModel )
{
List flattenedDependencies = new ArrayList();
// resolve all direct and inherited dependencies...
createFlattenedDependencies( effectiveModel, flattenedDependencies );
if ( isEmbedBuildProfileDependencies() )
{
Model projectModel = this.project.getModel();
Dependencies modelDependencies = new Dependencies();
modelDependencies.addAll( projectModel.getDependencies() );
for ( Profile profile : projectModel.getProfiles() )
{
// build-time driven activation (by property or file)?
if ( isBuildTimeDriven( profile.getActivation() ) )
{
List profileDependencies = profile.getDependencies();
for ( Dependency profileDependency : profileDependencies )
{
if ( modelDependencies.contains( profileDependency ) )
{
// our assumption here is that the profileDependency has been added to model because of
// this build-time driven profile. Therefore we need to add it to the flattened POM.
// Non build-time driven profiles will remain in the flattened POM with their dependencies
// and
// allow dynamic dependencies due to OS or JDK.
flattenedDependencies.add( profileDependency );
}
}
}
}
getLog().debug( "Resolved " + flattenedDependencies.size() + " dependency/-ies for flattened POM." );
}
return flattenedDependencies;
}
/**
* Collects the resolved {@link Dependency dependencies} from the given effectiveModel
.
*
* @param effectiveModel is the effective POM {@link Model} to process.
* @param flattenedDependencies is the {@link List} where to add the collected {@link Dependency dependencies}.
*/
protected void createFlattenedDependencies( Model effectiveModel, List flattenedDependencies )
{
getLog().debug( "Resolving dependencies of " + effectiveModel.getId() );
// this.project.getDependencies() already contains the inherited dependencies but also those from profiles
// List projectDependencies = currentProject.getOriginalModel().getDependencies();
List projectDependencies = effectiveModel.getDependencies();
for ( Dependency projectDependency : projectDependencies )
{
Dependency flattenedDependency = createFlattenedDependency( projectDependency );
if ( flattenedDependency != null )
{
flattenedDependencies.add( flattenedDependency );
}
}
}
/**
* @param projectDependency is the project {@link Dependency}.
* @return the flattened {@link Dependency} or null
if the given {@link Dependency} is NOT relevant for
* flattened POM.
*/
protected Dependency createFlattenedDependency( Dependency projectDependency )
{
return "test".equals( projectDependency.getScope() ) ? null : projectDependency;
}
/**
* @return true
if the generated flattened POM shall be {@link MavenProject#setFile(java.io.File) set}
* as POM artifact of the {@link MavenProject}, false
otherwise.
*/
public boolean isUpdatePomFile()
{
if ( this.updatePomFile == null )
{
if ( this.flattenMode == FlattenMode.bom )
{
return true;
}
return !this.project.getPackaging().equals( "pom" );
}
else
{
return this.updatePomFile.booleanValue();
}
}
/**
* This class is a simple SAX handler that extracts the first comment located before the root tag in an XML
* document.
*/
private class SaxHeaderCommentHandler
extends DefaultHandler2
{
/** true
if root tag has already been visited, false
otherwise. */
private boolean rootTagSeen;
/** @see #getHeaderComment() */
private String headerComment;
/**
* The constructor.
*/
public SaxHeaderCommentHandler()
{
super();
this.rootTagSeen = false;
}
/**
* @return the XML comment from the header of the document or null
if not present.
*/
public String getHeaderComment()
{
return this.headerComment;
}
/**
* {@inheritDoc}
*/
@Override
public void comment( char[] ch, int start, int length )
throws SAXException
{
if ( !this.rootTagSeen )
{
if ( this.headerComment == null )
{
this.headerComment = new String( ch, start, length );
}
else
{
getLog().warn( "Ignoring multiple XML header comment!" );
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void startElement( String uri, String localName, String qName, Attributes atts )
throws SAXException
{
this.rootTagSeen = true;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy