blob: bbfb62fa70864407362ffa70b75c40698a8c080d [file] [log] [blame]
/*
* 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.apache.maven.mae.project;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.apache.maven.RepositoryUtils;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.mae.project.key.FullProjectKey;
import org.apache.maven.mae.project.session.ProjectToolsSession;
import org.apache.maven.mae.project.session.SessionInjector;
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
import org.apache.maven.model.building.ModelProblem;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
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.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.util.Os;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.sonatype.aether.RepositorySystem;
import org.sonatype.aether.artifact.Artifact;
import org.sonatype.aether.resolution.ArtifactRequest;
import org.sonatype.aether.resolution.ArtifactResolutionException;
import org.sonatype.aether.resolution.ArtifactResult;
@Component( role = ProjectLoader.class )
public class DefaultProjectLoader
implements ProjectLoader
{
private static final Logger LOGGER = Logger.getLogger( DefaultProjectLoader.class );
@Requirement
private RepositorySystem aetherRepositorySystem;
@Requirement
private org.apache.maven.repository.RepositorySystem mavenRepositorySystem;
@Requirement
private ProjectBuilder projectBuilder;
@Requirement
private SessionInjector sessionInjector;
@Override
public List<MavenProject> buildReactorProjectInstances( final ProjectToolsSession session, final boolean recursive,
final File... rootPoms )
throws ProjectToolsException
{
sessionInjector.getRemoteRepositories( session );
final ProjectBuildingRequest pbr = sessionInjector.getProjectBuildingRequest( session );
try
{
final List<File> pomFiles = Arrays.asList( rootPoms );
final List<ProjectBuildingResult> results = projectBuilder.build( pomFiles, recursive, pbr );
final List<MavenProject> projects = new ArrayList<MavenProject>( results.size() );
for ( final ProjectBuildingResult result : results )
{
final MavenProject project = result.getProject();
project.setRemoteArtifactRepositories( session.getRemoteArtifactRepositories() );
projects.add( project );
}
session.setReactorProjects( projects );
if ( LOGGER.isDebugEnabled() )
{
LOGGER.debug( "Adding projects to dependency graph:\n\t"
+ StringUtils.join( projects.iterator(), "\n\t" ) );
}
addProjects( session, projects );
return projects;
}
catch ( final ProjectBuildingException e )
{
final List<ProjectBuildingResult> results = e.getResults();
final StringBuilder sb = new StringBuilder();
if ( results == null )
{
sb.append( "Cannot build reactor project instances for root-POM: " ).append( rootPoms );
final StringWriter sWriter = new StringWriter();
final PrintWriter pWriter = new PrintWriter( sWriter );
e.printStackTrace( pWriter );
sb.append( "\n" ).append( sWriter );
}
else
{
int i = 0;
for ( final ProjectBuildingResult result : results )
{
StringBuilder builder = new StringBuilder();
final List<ModelProblem> problems = result.getProblems();
if ( problems != null && !problems.isEmpty() )
{
builder.append( "\n" ).append( result.getProjectId() );
for ( final ModelProblem problem : problems )
{
builder.append( "\n\t" ).append( ( ++i ) ).append( " " ).append( problem.getMessage() ).append( "\n\t\t" ).append( problem.getSource() ).append( "@" ).append( problem.getLineNumber() ).append( ":"
+ problem.getColumnNumber() );
if ( problem.getException() != null )
{
final StringWriter sWriter = new StringWriter();
final PrintWriter pWriter = new PrintWriter( sWriter );
problem.getException().printStackTrace( pWriter );
builder.append( "\n" ).append( sWriter );
}
}
}
sb.append( builder );
}
}
throw new ProjectToolsException( "Failed to build project instance. \n\n%s", e, sb );
}
}
private void addProjects( final ProjectToolsSession session, final MavenProject... projects )
{
if ( projects == null || projects.length == 0 )
{
return;
}
addProjects( session, Arrays.asList( projects ) );
}
private void addProjects( final ProjectToolsSession session, final List<MavenProject> projects )
{
for ( final MavenProject project : projects )
{
final LinkedList<Artifact> parentage = new LinkedList<Artifact>();
MavenProject parent = project;
while ( parent != null )
{
final org.apache.maven.artifact.Artifact pomArtifact =
mavenRepositorySystem.createArtifact( project.getGroupId(), project.getArtifactId(),
project.getVersion(), "pom" );
final Artifact aetherPomArtifact = RepositoryUtils.toArtifact( pomArtifact );
parentage.addFirst( aetherPomArtifact );
parent = parent.getParent();
}
Artifact current = parentage.removeFirst();
while ( !parentage.isEmpty() )
{
final Artifact next = parentage.getFirst();
// This is WEIRD, but the parent POM is actually a dependency of the current one,
// since it's required in order to build the current project...
if ( LOGGER.isDebugEnabled() )
{
LOGGER.debug( "Marking parent POM: " + current + " as dependency of POM: " + next );
}
session.connectProjectHierarchy( next, true, current, true );
if ( !parentage.isEmpty() )
{
current = parentage.removeFirst();
}
}
}
}
@Override
public MavenProject buildProjectInstance( final File pomFile, final ProjectToolsSession session )
throws ProjectToolsException
{
sessionInjector.getRemoteRepositories( session );
final ProjectBuildingRequest pbr = sessionInjector.getProjectBuildingRequest( session );
try
{
final ProjectBuildingResult result = projectBuilder.build( pomFile, pbr );
final MavenProject project = result.getProject();
project.setRemoteArtifactRepositories( session.getRemoteArtifactRepositories() );
addProjects( session, project );
return project;
}
catch ( final ProjectBuildingException e )
{
// logger.error( "Failed to build MavenProject instances from POM files for sorting: " + e.getMessage(), e
// );
final List<ProjectBuildingResult> results = e.getResults();
final StringBuilder sb = new StringBuilder();
if ( results == null )
{
sb.append( "Cannot build project instance for: " ).append( pomFile );
final StringWriter sWriter = new StringWriter();
final PrintWriter pWriter = new PrintWriter( sWriter );
e.printStackTrace( pWriter );
sb.append( "\n" ).append( sWriter );
}
else
{
int i = 0;
for ( final ProjectBuildingResult result : results )
{
final List<ModelProblem> problems = result.getProblems();
for ( final ModelProblem problem : problems )
{
sb.append( problem.getMessage() ).append( "\n\t" ).append( problem.getSource() ).append( "@" ).append( problem.getLineNumber() ).append( ":"
+ problem.getColumnNumber() );
if ( problem.getException() != null )
{
final StringWriter sWriter = new StringWriter();
final PrintWriter pWriter = new PrintWriter( sWriter );
problem.getException().printStackTrace( pWriter );
sb.append( "\n" ).append( sWriter );
}
sb.append( ( ++i ) ).append( " " ).append( sb );
}
}
}
throw new ProjectToolsException( "Failed to build project instance. \n\n%s", e, sb );
}
}
@Override
public MavenProject buildProjectInstance( final FullProjectKey key, final ProjectToolsSession session )
throws ProjectToolsException
{
return buildProjectInstance( key.getGroupId(), key.getArtifactId(), key.getVersion(), session );
}
@Override
public MavenProject buildProjectInstance( final String groupId, final String artifactId, final String version,
final ProjectToolsSession session )
throws ProjectToolsException
{
final ProjectBuildingRequest req = sessionInjector.getProjectBuildingRequest( session );
try
{
final org.apache.maven.artifact.Artifact pomArtifact =
mavenRepositorySystem.createArtifact( groupId, artifactId, version, "pom" );
final Artifact aetherPomArtifact = RepositoryUtils.toArtifact( pomArtifact );
final ArtifactRequest artifactRequest =
new ArtifactRequest( aetherPomArtifact, sessionInjector.getRemoteRepositories( session ), "project" );
final ArtifactResult artifactResult =
aetherRepositorySystem.resolveArtifact( req.getRepositorySession(), artifactRequest );
final File pomFile = artifactResult.getArtifact().getFile();
final ProjectBuildingResult result = projectBuilder.build( pomFile, req );
final MavenProject project = result.getProject();
project.setRemoteArtifactRepositories( session.getRemoteArtifactRepositories() );
project.setFile( pomFile );
addProjects( session, project );
return project;
}
catch ( final ProjectBuildingException e )
{
// logger.error( "Failed to build MavenProject instances from POM files for sorting: " + e.getMessage(), e
// );
final List<ProjectBuildingResult> results = e.getResults();
final StringBuilder sb = new StringBuilder();
int i = 0;
if ( results == null )
{
sb.append( "Cannot build project instance for: " ).append( groupId ).append( ':' ).append( artifactId ).append( ':' ).append( version );
final StringWriter sWriter = new StringWriter();
final PrintWriter pWriter = new PrintWriter( sWriter );
e.printStackTrace( pWriter );
sb.append( "\n" ).append( sWriter );
}
else
{
for ( final ProjectBuildingResult result : results )
{
final List<ModelProblem> problems = result.getProblems();
for ( final ModelProblem problem : problems )
{
sb.append( problem.getMessage() ).append( "\n\t" ).append( problem.getSource() ).append( "@" ).append( problem.getLineNumber() ).append( ":"
+ problem.getColumnNumber() );
if ( problem.getException() != null )
{
final StringWriter sWriter = new StringWriter();
final PrintWriter pWriter = new PrintWriter( sWriter );
problem.getException().printStackTrace( pWriter );
sb.append( "\n" ).append( sWriter );
}
sb.append( ( ++i ) ).append( " " ).append( sb );
}
}
}
throw new ProjectToolsException( "Failed to build project instance. \n\n%s", e, sb );
}
catch ( final ArtifactResolutionException e )
{
throw new ProjectToolsException( "Failed to resolve POM: %s:%s:%s\nReason: %s", e, groupId, artifactId,
version, e.getMessage() );
}
}
@Override
public Set<String> retrieveReactorProjectIds( final File rootPom )
throws ProjectToolsException
{
if ( LOGGER.isInfoEnabled() )
{
if ( LOGGER.isDebugEnabled() )
{
LOGGER.debug( "Finding projectIds contained within reactor for: " + rootPom );
}
}
final Map<File, Model> models = new LinkedHashMap<File, Model>();
readReactorModels( rootPom, rootPom, models );
final Set<String> projectIds = new HashSet<String>( models.size() );
for ( final Model model : models.values() )
{
String groupId = model.getGroupId();
final String artifactId = model.getArtifactId();
String version = model.getVersion();
String packaging = model.getPackaging();
if ( packaging == null )
{
packaging = "jar";
}
if ( groupId == null || version == null )
{
final Parent parent = model.getParent();
if ( parent != null )
{
if ( groupId == null )
{
groupId = parent.getGroupId();
}
if ( version == null )
{
version = parent.getVersion();
}
}
else
{
LOGGER.warn( String.format( "Invalid POM: %s", model.getId() ) );
continue;
}
}
final String key = ArtifactUtils.key( groupId, artifactId, version );
if ( LOGGER.isInfoEnabled() )
{
if ( LOGGER.isDebugEnabled() )
{
LOGGER.debug( "Found: " + key );
}
}
projectIds.add( key );
}
return projectIds;
}
private void readReactorModels( final File topPom, final File pom, final Map<File, Model> models )
throws ProjectToolsException
{
final Model model = readModel( pom );
models.put( pom, model );
if ( model.getModules() != null && !model.getModules().isEmpty() )
{
final File basedir = pom.getParentFile();
final List<File> moduleFiles = new ArrayList<File>();
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 = new File( moduleFile, "pom.xml" );
}
if ( !moduleFile.isFile() )
{
LOGGER.warn( String.format( "In reactor of: %s: Child module %s of %s does not exist.", topPom,
moduleFile, pom ) );
continue;
}
if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
{
// we don't canonicalize on unix to avoid interfering with symlinks
try
{
moduleFile = moduleFile.getCanonicalFile();
}
catch ( final IOException e )
{
moduleFile = moduleFile.getAbsoluteFile();
}
}
else
{
moduleFile = new File( moduleFile.toURI().normalize() );
}
moduleFiles.add( moduleFile );
readReactorModels( topPom, moduleFile, models );
}
}
}
private Model readModel( final File pom )
throws ProjectToolsException
{
Reader reader = null;
try
{
reader = ReaderFactory.newPlatformReader( pom );
return new MavenXpp3Reader().read( reader, false );
}
catch ( final IOException e )
{
LOGGER.error( String.format( "Failed to read POM: %s.\nReason: %s", pom, e.getMessage() ), e );
throw new ProjectToolsException( "Failed to read POM: %s. Reason: %s", e, pom.getAbsolutePath(),
e.getMessage() );
}
catch ( final XmlPullParserException e )
{
LOGGER.error( String.format( "Failed to read POM: %s.\nReason: %s", pom, e.getMessage() ), e );
throw new ProjectToolsException( "Failed to read POM: %s. Reason: %s", e, pom.getAbsolutePath(),
e.getMessage() );
}
finally
{
IOUtils.closeQuietly( reader );
}
}
}