org.apache.maven.project.DefaultProjectBuilder Maven / Gradle / Ivy
The newest version!
package org.apache.maven.project;
/*
* 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.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.maven.RepositoryUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.LegacyLocalRepositoryManager;
import org.apache.maven.model.Build;
import org.apache.maven.model.Model;
import org.apache.maven.model.Profile;
import org.apache.maven.model.building.DefaultModelBuildingRequest;
import org.apache.maven.model.building.DefaultModelProblem;
import org.apache.maven.model.building.FileModelSource;
import org.apache.maven.model.building.ModelBuilder;
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.ModelProblem;
import org.apache.maven.model.building.ModelProcessor;
import org.apache.maven.model.building.ModelSource;
import org.apache.maven.model.building.StringModelSource;
import org.apache.maven.model.resolution.ModelResolver;
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.repository.internal.ArtifactDescriptorUtils;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.Os;
import org.codehaus.plexus.util.StringUtils;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.RequestTrace;
import org.eclipse.aether.impl.RemoteRepositoryManager;
import org.eclipse.aether.repository.LocalRepositoryManager;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.WorkspaceRepository;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResult;
/**
*/
@Component( role = ProjectBuilder.class )
public class DefaultProjectBuilder
implements ProjectBuilder
{
@Requirement
private Logger logger;
@Requirement
private ModelBuilder modelBuilder;
@Requirement
private ModelProcessor modelProcessor;
@Requirement
private ProjectBuildingHelper projectBuildingHelper;
@Requirement
private RepositorySystem repositorySystem;
@Requirement
private org.eclipse.aether.RepositorySystem repoSystem;
@Requirement
private RemoteRepositoryManager repositoryManager;
@Requirement
private ProjectDependenciesResolver dependencyResolver;
// ----------------------------------------------------------------------
// MavenProjectBuilder Implementation
// ----------------------------------------------------------------------
public ProjectBuildingResult build( File pomFile, ProjectBuildingRequest request )
throws ProjectBuildingException
{
return build( pomFile, new FileModelSource( pomFile ), new InternalConfig( request, null ) );
}
public ProjectBuildingResult build( ModelSource modelSource, ProjectBuildingRequest request )
throws ProjectBuildingException
{
return build( null, modelSource, new InternalConfig( request, null ) );
}
private ProjectBuildingResult build( File pomFile, ModelSource modelSource, InternalConfig config )
throws ProjectBuildingException
{
ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
try
{
ProjectBuildingRequest configuration = config.request;
MavenProject project = configuration.getProject();
List modelProblems = null;
Throwable error = null;
if ( project == null )
{
ModelBuildingRequest request = getModelBuildingRequest( config );
project = new MavenProject( repositorySystem, this, configuration, logger );
DefaultModelBuildingListener listener =
new DefaultModelBuildingListener( project, projectBuildingHelper, configuration );
request.setModelBuildingListener( listener );
request.setPomFile( pomFile );
request.setModelSource( modelSource );
request.setLocationTracking( true );
ModelBuildingResult result;
try
{
result = modelBuilder.build( request );
}
catch ( ModelBuildingException e )
{
result = e.getResult();
if ( result == null || result.getEffectiveModel() == null )
{
throw new ProjectBuildingException( e.getModelId(), e.getMessage(), pomFile, e );
}
// validation error, continue project building and delay failing to help IDEs
error = e;
}
modelProblems = result.getProblems();
initProject( project, Collections. emptyMap(), result,
new HashMap() );
}
else if ( configuration.isResolveDependencies() )
{
projectBuildingHelper.selectProjectRealm( project );
}
DependencyResolutionResult resolutionResult = null;
if ( configuration.isResolveDependencies() )
{
resolutionResult = resolveDependencies( project, config.session );
}
ProjectBuildingResult result = new DefaultProjectBuildingResult( project, modelProblems, resolutionResult );
if ( error != null )
{
ProjectBuildingException e = new ProjectBuildingException( Arrays.asList( result ) );
e.initCause( error );
throw e;
}
return result;
}
finally
{
Thread.currentThread().setContextClassLoader( oldContextClassLoader );
}
}
private DependencyResolutionResult resolveDependencies( MavenProject project, RepositorySystemSession session )
{
DependencyResolutionResult resolutionResult = null;
try
{
DefaultDependencyResolutionRequest resolution = new DefaultDependencyResolutionRequest( project, session );
resolutionResult = dependencyResolver.resolve( resolution );
}
catch ( DependencyResolutionException e )
{
resolutionResult = e.getResult();
}
Set artifacts = new LinkedHashSet();
if ( resolutionResult.getDependencyGraph() != null )
{
RepositoryUtils.toArtifacts( artifacts, resolutionResult.getDependencyGraph().getChildren(),
Collections.singletonList( project.getArtifact().getId() ), null );
// Maven 2.x quirk: an artifact always points at the local repo, regardless whether resolved or not
LocalRepositoryManager lrm = session.getLocalRepositoryManager();
for ( Artifact artifact : artifacts )
{
if ( !artifact.isResolved() )
{
String path = lrm.getPathForLocalArtifact( RepositoryUtils.toArtifact( artifact ) );
artifact.setFile( new File( lrm.getRepository().getBasedir(), path ) );
}
}
}
project.setResolvedArtifacts( artifacts );
project.setArtifacts( artifacts );
return resolutionResult;
}
private List getProfileIds( List profiles )
{
List ids = new ArrayList( profiles.size() );
for ( Profile profile : profiles )
{
ids.add( profile.getId() );
}
return ids;
}
private ModelBuildingRequest getModelBuildingRequest( InternalConfig config )
{
ProjectBuildingRequest configuration = config.request;
ModelBuildingRequest request = new DefaultModelBuildingRequest();
RequestTrace trace = RequestTrace.newChild( null, configuration ).newChild( request );
ModelResolver resolver =
new ProjectModelResolver( config.session, trace, repoSystem, repositoryManager, config.repositories,
configuration.getRepositoryMerging(), config.modelPool );
request.setValidationLevel( configuration.getValidationLevel() );
request.setProcessPlugins( configuration.isProcessPlugins() );
request.setProfiles( configuration.getProfiles() );
request.setActiveProfileIds( configuration.getActiveProfileIds() );
request.setInactiveProfileIds( configuration.getInactiveProfileIds() );
request.setSystemProperties( configuration.getSystemProperties() );
request.setUserProperties( configuration.getUserProperties() );
request.setBuildStartTime( configuration.getBuildStartTime() );
request.setModelResolver( resolver );
request.setModelCache( new ReactorModelCache() );
return request;
}
public ProjectBuildingResult build( Artifact artifact, ProjectBuildingRequest request )
throws ProjectBuildingException
{
return build( artifact, false, request );
}
public ProjectBuildingResult build( Artifact artifact, boolean allowStubModel, ProjectBuildingRequest request )
throws ProjectBuildingException
{
org.eclipse.aether.artifact.Artifact pomArtifact = RepositoryUtils.toArtifact( artifact );
pomArtifact = ArtifactDescriptorUtils.toPomArtifact( pomArtifact );
InternalConfig config = new InternalConfig( request, null );
boolean localProject;
try
{
ArtifactRequest pomRequest = new ArtifactRequest();
pomRequest.setArtifact( pomArtifact );
pomRequest.setRepositories( config.repositories );
ArtifactResult pomResult = repoSystem.resolveArtifact( config.session, pomRequest );
pomArtifact = pomResult.getArtifact();
localProject = pomResult.getRepository() instanceof WorkspaceRepository;
}
catch ( org.eclipse.aether.resolution.ArtifactResolutionException e )
{
if ( e.getResults().get( 0 ).isMissing() && allowStubModel )
{
return build( null, createStubModelSource( artifact ), config );
}
throw new ProjectBuildingException( artifact.getId(),
"Error resolving project artifact: " + e.getMessage(), e );
}
File pomFile = pomArtifact.getFile();
if ( "pom".equals( artifact.getType() ) )
{
artifact.selectVersion( pomArtifact.getVersion() );
artifact.setFile( pomFile );
artifact.setResolved( true );
}
return build( localProject ? pomFile : null, new FileModelSource( pomFile ), config );
}
private ModelSource createStubModelSource( Artifact artifact )
{
StringBuilder buffer = new StringBuilder( 1024 );
buffer.append( "" );
buffer.append( "" );
buffer.append( "4.0.0 " );
buffer.append( "" ).append( artifact.getGroupId() ).append( " " );
buffer.append( "" ).append( artifact.getArtifactId() ).append( " " );
buffer.append( "" ).append( artifact.getBaseVersion() ).append( " " );
buffer.append( "" ).append( artifact.getType() ).append( " " );
buffer.append( " " );
return new StringModelSource( buffer, artifact.getId() );
}
public List build( List pomFiles, boolean recursive, ProjectBuildingRequest request )
throws ProjectBuildingException
{
List results = new ArrayList();
List interimResults = new ArrayList();
ReactorModelPool modelPool = new ReactorModelPool();
InternalConfig config = new InternalConfig( request, modelPool );
Map projectIndex = new HashMap( 256 );
boolean noErrors =
build( results, interimResults, projectIndex, pomFiles, new LinkedHashSet(), true, recursive, config );
populateReactorModelPool( modelPool, interimResults );
ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
try
{
noErrors =
build( results, new ArrayList(), projectIndex, interimResults, request,
new HashMap() ) && noErrors;
}
finally
{
Thread.currentThread().setContextClassLoader( oldContextClassLoader );
}
if ( !noErrors )
{
throw new ProjectBuildingException( results );
}
return results;
}
private boolean build( List results, List interimResults,
Map projectIndex, List pomFiles, Set aggregatorFiles,
boolean isRoot, boolean recursive, InternalConfig config )
{
boolean noErrors = true;
for ( File pomFile : pomFiles )
{
aggregatorFiles.add( pomFile );
if ( !build( results, interimResults, projectIndex, pomFile, aggregatorFiles, isRoot, recursive, config ) )
{
noErrors = false;
}
aggregatorFiles.remove( pomFile );
}
return noErrors;
}
private boolean build( List results, List interimResults,
Map projectIndex, File pomFile, Set aggregatorFiles,
boolean isRoot, boolean recursive, InternalConfig config )
{
boolean noErrors = true;
ModelBuildingRequest request = getModelBuildingRequest( config );
MavenProject project = new MavenProject( repositorySystem, this, config.request, logger );
request.setPomFile( pomFile );
request.setTwoPhaseBuilding( true );
request.setLocationTracking( true );
DefaultModelBuildingListener listener =
new DefaultModelBuildingListener( project, projectBuildingHelper, config.request );
request.setModelBuildingListener( listener );
try
{
ModelBuildingResult result = modelBuilder.build( request );
Model model = result.getEffectiveModel();
projectIndex.put( result.getModelIds().get( 0 ), project );
InterimResult interimResult = new InterimResult( pomFile, request, result, listener, isRoot );
interimResults.add( interimResult );
if ( recursive && !model.getModules().isEmpty() )
{
File basedir = pomFile.getParentFile();
List moduleFiles = new ArrayList();
for ( String module : model.getModules() )
{
if ( StringUtils.isEmpty( module ) )
{
continue;
}
module = module.replace( '\\', File.separatorChar ).replace( '/', File.separatorChar );
File moduleFile = new File( basedir, module );
if ( moduleFile.isDirectory() )
{
moduleFile = modelProcessor.locatePom( moduleFile );
}
if ( !moduleFile.isFile() )
{
ModelProblem problem =
new DefaultModelProblem( "Child module " + moduleFile + " of " + pomFile
+ " does not exist", ModelProblem.Severity.ERROR, ModelProblem.Version.BASE, model, -1, -1, null );
result.getProblems().add( problem );
noErrors = false;
continue;
}
if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
{
// we don't canonicalize on unix to avoid interfering with symlinks
try
{
moduleFile = moduleFile.getCanonicalFile();
}
catch ( IOException e )
{
moduleFile = moduleFile.getAbsoluteFile();
}
}
else
{
moduleFile = new File( moduleFile.toURI().normalize() );
}
if ( aggregatorFiles.contains( moduleFile ) )
{
StringBuilder buffer = new StringBuilder( 256 );
for ( File aggregatorFile : aggregatorFiles )
{
buffer.append( aggregatorFile ).append( " -> " );
}
buffer.append( moduleFile );
ModelProblem problem =
new DefaultModelProblem( "Child module " + moduleFile + " of " + pomFile
+ " forms aggregation cycle " + buffer, ModelProblem.Severity.ERROR, ModelProblem.Version.BASE, model, -1, -1,
null );
result.getProblems().add( problem );
noErrors = false;
continue;
}
moduleFiles.add( moduleFile );
}
interimResult.modules = new ArrayList();
if ( !build( results, interimResult.modules, projectIndex, moduleFiles, aggregatorFiles, false,
recursive, config ) )
{
noErrors = false;
}
}
}
catch ( ModelBuildingException e )
{
results.add( new DefaultProjectBuildingResult( e.getModelId(), pomFile, e.getProblems() ) );
noErrors = false;
}
return noErrors;
}
static class InterimResult
{
File pomFile;
ModelBuildingRequest request;
ModelBuildingResult result;
DefaultModelBuildingListener listener;
boolean root;
List modules = Collections.emptyList();
InterimResult( File pomFile, ModelBuildingRequest request, ModelBuildingResult result,
DefaultModelBuildingListener listener, boolean root )
{
this.pomFile = pomFile;
this.request = request;
this.result = result;
this.listener = listener;
this.root = root;
}
}
private void populateReactorModelPool( ReactorModelPool reactorModelPool, List interimResults )
{
for ( InterimResult interimResult : interimResults )
{
Model model = interimResult.result.getEffectiveModel();
reactorModelPool.put( model.getGroupId(), model.getArtifactId(), model.getVersion(), model.getPomFile() );
populateReactorModelPool( reactorModelPool, interimResult.modules );
}
}
private boolean build( List results, List projects,
Map projectIndex, List interimResults,
ProjectBuildingRequest request, Map profilesXmls )
{
boolean noErrors = true;
for ( InterimResult interimResult : interimResults )
{
try
{
ModelBuildingResult result = modelBuilder.build( interimResult.request, interimResult.result );
MavenProject project = interimResult.listener.getProject();
initProject( project, projectIndex, result, profilesXmls );
List modules = new ArrayList();
noErrors =
build( results, modules, projectIndex, interimResult.modules, request, profilesXmls ) && noErrors;
projects.addAll( modules );
projects.add( project );
project.setExecutionRoot( interimResult.root );
project.setCollectedProjects( modules );
results.add( new DefaultProjectBuildingResult( project, result.getProblems(), null ) );
}
catch ( ModelBuildingException e )
{
results.add( new DefaultProjectBuildingResult( e.getModelId(), interimResult.pomFile, e.getProblems() ) );
noErrors = false;
}
}
return noErrors;
}
private void initProject( MavenProject project, Map projects, ModelBuildingResult result,
Map profilesXmls )
{
Model model = result.getEffectiveModel();
project.setModel( model );
project.setOriginalModel( result.getRawModel() );
project.setFile( model.getPomFile() );
File parentPomFile = result.getRawModel( result.getModelIds().get( 1 ) ).getPomFile();
project.setParentFile( parentPomFile );
project.setParent( projects.get( result.getModelIds().get( 1 ) ) );
Artifact projectArtifact =
repositorySystem.createArtifact( project.getGroupId(), project.getArtifactId(), project.getVersion(), null,
project.getPackaging() );
project.setArtifact( projectArtifact );
if ( project.getFile() != null )
{
Build build = project.getBuild();
project.addScriptSourceRoot( build.getScriptSourceDirectory() );
project.addCompileSourceRoot( build.getSourceDirectory() );
project.addTestCompileSourceRoot( build.getTestSourceDirectory() );
}
List activeProfiles = new ArrayList();
activeProfiles.addAll( result.getActivePomProfiles( result.getModelIds().get( 0 ) ) );
activeProfiles.addAll( result.getActiveExternalProfiles() );
project.setActiveProfiles( activeProfiles );
project.setInjectedProfileIds( "external", getProfileIds( result.getActiveExternalProfiles() ) );
for ( String modelId : result.getModelIds() )
{
project.setInjectedProfileIds( modelId, getProfileIds( result.getActivePomProfiles( modelId ) ) );
}
String modelId = findProfilesXml( result, profilesXmls );
if ( modelId != null )
{
ModelProblem problem =
new DefaultModelProblem( "Detected profiles.xml alongside " + modelId
+ ", this file is no longer supported and was ignored" + ", please use the settings.xml instead",
ModelProblem.Severity.WARNING, ModelProblem.Version.V30, model, -1, -1, null );
result.getProblems().add( problem );
}
}
private String findProfilesXml( ModelBuildingResult result, Map profilesXmls )
{
for ( String modelId : result.getModelIds() )
{
Model model = result.getRawModel( modelId );
File basedir = model.getProjectDirectory();
if ( basedir == null )
{
break;
}
Boolean profilesXml = profilesXmls.get( basedir );
if ( profilesXml == null )
{
profilesXml = Boolean.valueOf( new File( basedir, "profiles.xml" ).exists() );
profilesXmls.put( basedir, profilesXml );
}
if ( profilesXml.booleanValue() )
{
return modelId;
}
}
return null;
}
class InternalConfig
{
public final ProjectBuildingRequest request;
public final RepositorySystemSession session;
public final List repositories;
public final ReactorModelPool modelPool;
InternalConfig( ProjectBuildingRequest request, ReactorModelPool modelPool )
{
this.request = request;
this.modelPool = modelPool;
session =
LegacyLocalRepositoryManager.overlay( request.getLocalRepository(), request.getRepositorySession(),
repoSystem );
repositories = RepositoryUtils.toRepos( request.getRemoteRepositories() );
}
}
}