MNG-5503: Fix for the issue where Maven 3.1.0 fails to resolve artifacts produced by reactor build

The general strategy is to fall back to Aether artifact type and use its notion of identity as much as possible. I have
a simple IT taken from the sample project that I will also push.
This commit is contained in:
Jason van Zyl 2013-08-20 05:54:28 -07:00
parent 2fd4d482e8
commit 11f46bd4c4
3 changed files with 132 additions and 200 deletions

View File

@ -96,7 +96,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
<version>1.5-SNAPSHOT</version>
<version>1.5</version>
</plugin>
<plugin>
<groupId>org.apache.rat</groupId>

View File

@ -19,12 +19,6 @@ package org.apache.maven;
* under the License.
*/
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.project.MavenProject;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.repository.WorkspaceReader;
import org.eclipse.aether.repository.WorkspaceRepository;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
@ -35,6 +29,13 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.project.MavenProject;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.repository.WorkspaceReader;
import org.eclipse.aether.repository.WorkspaceRepository;
import org.eclipse.aether.util.artifact.ArtifactIdUtils;
/**
* An implementation of a workspace reader that knows how to search the Maven reactor for artifacts.
*
@ -43,8 +44,6 @@ import java.util.Map;
class ReactorReader
implements WorkspaceReader
{
private static final Collection<String> JAR_LIKE_TYPES = Arrays.asList( "jar", "test-jar", "ejb-client" );
private static final Collection<String> COMPILE_PHASE_TYPES = Arrays.asList( "jar", "ejb-client" );
private Map<String, MavenProject> projectsByGAV;
@ -52,7 +51,7 @@ class ReactorReader
private Map<String, List<MavenProject>> projectsByGA;
private WorkspaceRepository repository;
public ReactorReader( Map<String, MavenProject> reactorProjects )
{
projectsByGAV = reactorProjects;
@ -73,197 +72,18 @@ class ReactorReader
projects.add( project );
}
repository = new WorkspaceRepository( "reactor", new HashSet<String>( projectsByGAV.keySet() ) );
repository = new WorkspaceRepository( "reactor", new HashSet<String>( projectsByGAV.keySet() ) );
}
private File find( MavenProject project, Artifact artifact )
//
// Public API
//
public WorkspaceRepository getRepository()
{
if ( "pom".equals( artifact.getExtension() ) )
{
return project.getFile();
}
org.apache.maven.artifact.Artifact projectArtifact = findMatchingArtifact( project, artifact );
if ( hasArtifactFileFromPackagePhase( projectArtifact ) )
{
return projectArtifact.getFile();
}
else if ( !hasBeenPackaged( project ) )
{
// fallback to loose class files only if artifacts haven't been packaged yet
// and only for plain old jars. Not war files, not ear files, not anything else.
if ( isTestArtifact( artifact ) )
{
if ( project.hasLifecyclePhase( "test-compile" ) )
{
return new File( project.getBuild().getTestOutputDirectory() );
}
}
else
{
String type = artifact.getProperty( "type", "" );
if ( project.hasLifecyclePhase( "compile" ) && COMPILE_PHASE_TYPES.contains( type ) )
{
return new File( project.getBuild().getOutputDirectory() );
}
}
}
// The fall-through indicates that the artifact cannot be found;
// for instance if package produced nothing or classifier problems.
return null;
}
private boolean hasArtifactFileFromPackagePhase( org.apache.maven.artifact.Artifact projectArtifact )
{
return projectArtifact != null && projectArtifact.getFile() != null && projectArtifact.getFile().exists();
}
private boolean hasBeenPackaged( MavenProject project )
{
return project.hasLifecyclePhase( "package" ) || project.hasLifecyclePhase( "install" )
|| project.hasLifecyclePhase( "deploy" );
}
/**
* Tries to resolve the specified artifact from the artifacts of the given project.
*
* @param project The project to try to resolve the artifact from, must not be <code>null</code>.
* @param requestedArtifact The artifact to resolve, must not be <code>null</code>.
* @return The matching artifact from the project or <code>null</code> if not found.
*
* Note that this
*/
private org.apache.maven.artifact.Artifact findMatchingArtifact( MavenProject project, Artifact requestedArtifact )
{
String requestedRepositoryConflictId = getConflictId( requestedArtifact );
org.apache.maven.artifact.Artifact mainArtifact = project.getArtifact();
if ( requestedRepositoryConflictId.equals( getConflictId( mainArtifact ) ) )
{
return mainArtifact;
}
Collection<org.apache.maven.artifact.Artifact> attachedArtifacts = project.getAttachedArtifacts();
if ( attachedArtifacts != null && !attachedArtifacts.isEmpty() )
{
for ( org.apache.maven.artifact.Artifact attachedArtifact : attachedArtifacts )
{
/*
* Don't use the conflict ids, use a customized comparison that takes various ideas into account.
*/
if ( attachedArtifactComparison ( requestedArtifact, attachedArtifact ) )
{
return attachedArtifact;
}
}
}
return null;
return repository;
}
/**
* Try to satisfy both MNG-4065 and MNG-5214. Consider jar and test-jar equivalent.
* @param requestedType
* @param artifactType
* @return
*/
private boolean attachedArtifactComparison ( Artifact requestedArtifact, org.apache.maven.artifact.Artifact attachedArtifact )
{
if ( ! requestedArtifact.getGroupId().equals ( attachedArtifact.getGroupId() ) )
{
return false;
}
if ( ! requestedArtifact.getArtifactId().equals ( attachedArtifact.getArtifactId() ) )
{
return false;
}
String requestedExtension = requestedArtifact.getExtension();
String attachedExtension = null;
if ( attachedArtifact.getArtifactHandler() != null )
{
attachedExtension = attachedArtifact.getArtifactHandler().getExtension();
}
String requestedType = requestedArtifact.getProperty ( "type", "" );
String attachedType = attachedArtifact.getType();
boolean typeOk = false;
if ( requestedExtension.equals ( attachedExtension ) )
{
// the ideal case.
typeOk = true;
}
else if ( requestedType.equals( attachedType ) )
{
typeOk = true;
}
else if ( JAR_LIKE_TYPES.contains( requestedType ) && JAR_LIKE_TYPES.contains( attachedType ) )
{
typeOk = true;
}
if ( !typeOk )
{
return false;
}
return requestedArtifact.getClassifier().equals ( attachedArtifact.getClassifier() );
}
/**
* Gets the repository conflict id of the specified artifact. Unlike the dependency conflict id, the repository
* conflict id uses the artifact file extension instead of the artifact type. Hence, the repository conflict id more
* closely reflects the identity of artifacts as perceived by a repository.
*
* @param artifact The artifact, must not be <code>null</code>.
* @return The repository conflict id, never <code>null</code>.
*/
private String getConflictId( org.apache.maven.artifact.Artifact artifact )
{
StringBuilder buffer = new StringBuilder( 128 );
buffer.append( artifact.getGroupId() );
buffer.append( ':' ).append( artifact.getArtifactId() );
if ( artifact.getArtifactHandler() != null )
{
buffer.append( ':' ).append( artifact.getArtifactHandler().getExtension() );
}
else
{
buffer.append( ':' ).append( artifact.getType() );
}
if ( artifact.hasClassifier() )
{
buffer.append( ':' ).append( artifact.getClassifier() );
}
return buffer.toString();
}
private String getConflictId( Artifact artifact )
{
StringBuilder buffer = new StringBuilder( 128 );
buffer.append( artifact.getGroupId() );
buffer.append( ':' ).append( artifact.getArtifactId() );
buffer.append( ':' ).append( artifact.getExtension() );
if ( artifact.getClassifier().length() > 0 )
{
buffer.append( ':' ).append( artifact.getClassifier() );
}
return buffer.toString();
}
/**
* Determines whether the specified artifact refers to test classes.
*
* @param artifact The artifact to check, must not be {@code null}.
* @return {@code true} if the artifact refers to test classes, {@code false} otherwise.
*/
private static boolean isTestArtifact( Artifact artifact )
{
return ( "test-jar".equals( artifact.getProperty( "type", "" ) ) )
|| ( "jar".equals( artifact.getExtension() ) && "tests".equals( artifact.getClassifier() ) );
}
public File findArtifact( Artifact artifact )
{
String projectKey = ArtifactUtils.key( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() );
@ -304,11 +124,113 @@ class ReactorReader
}
return Collections.unmodifiableList( versions );
}
public WorkspaceRepository getRepository()
}
//
// Implementation
//
private File find( MavenProject project, Artifact artifact )
{
return repository;
if ( "pom".equals( artifact.getExtension() ) )
{
return project.getFile();
}
Artifact projectArtifact = findMatchingArtifact( project, artifact );
if ( hasArtifactFileFromPackagePhase( projectArtifact ) )
{
return projectArtifact.getFile();
}
else if ( !hasBeenPackaged( project ) )
{
// fallback to loose class files only if artifacts haven't been packaged yet
// and only for plain old jars. Not war files, not ear files, not anything else.
if ( isTestArtifact( artifact ) )
{
if ( project.hasLifecyclePhase( "test-compile" ) )
{
return new File( project.getBuild().getTestOutputDirectory() );
}
}
else
{
String type = artifact.getProperty( "type", "" );
if ( project.hasLifecyclePhase( "compile" ) && COMPILE_PHASE_TYPES.contains( type ) )
{
return new File( project.getBuild().getOutputDirectory() );
}
}
}
// The fall-through indicates that the artifact cannot be found;
// for instance if package produced nothing or classifier problems.
return null;
}
private boolean hasArtifactFileFromPackagePhase( Artifact projectArtifact )
{
return projectArtifact != null && projectArtifact.getFile() != null && projectArtifact.getFile().exists();
}
private boolean hasBeenPackaged( MavenProject project )
{
return project.hasLifecyclePhase( "package" ) || project.hasLifecyclePhase( "install" )
|| project.hasLifecyclePhase( "deploy" );
}
/**
* Tries to resolve the specified artifact from the artifacts of the given project.
*
* @param project The project to try to resolve the artifact from, must not be <code>null</code>.
* @param requestedArtifact The artifact to resolve, must not be <code>null</code>.
* @return The matching artifact from the project or <code>null</code> if not found.
*
* Note that this
*/
private Artifact findMatchingArtifact( MavenProject project, Artifact requestedArtifact )
{
String requestedRepositoryConflictId = ArtifactIdUtils.toVersionlessId( requestedArtifact );
Artifact mainArtifact = RepositoryUtils.toArtifact( project.getArtifact() );
if ( requestedRepositoryConflictId.equals( ArtifactIdUtils.toVersionlessId( mainArtifact ) ) )
{
return mainArtifact;
}
for ( Artifact attachedArtifact : RepositoryUtils.toArtifacts( project.getAttachedArtifacts() ) )
{
if ( attachedArtifactComparison ( requestedArtifact, attachedArtifact ) )
{
return attachedArtifact;
}
}
return null;
}
private boolean attachedArtifactComparison( Artifact requested, Artifact attached )
{
//
// We are taking as much as we can from the DefaultArtifact.equals(). The requested artifact has no file so
// we want to remove that from the comparision.
//
return requested.getArtifactId().equals( attached.getArtifactId() ) && requested.getGroupId().equals( attached.getGroupId() )
&& requested.getVersion().equals( attached.getVersion() ) && requested.getExtension().equals( attached.getExtension() )
&& requested.getClassifier().equals( attached.getClassifier() );
}
/**
* Determines whether the specified artifact refers to test classes.
*
* @param artifact The artifact to check, must not be {@code null}.
* @return {@code true} if the artifact refers to test classes, {@code false} otherwise.
*/
private static boolean isTestArtifact( Artifact artifact )
{
return ( "test-jar".equals( artifact.getProperty( "type", "" ) ) )
|| ( "jar".equals( artifact.getExtension() ) && "tests".equals( artifact.getClassifier() ) );
}
}

View File

@ -350,4 +350,14 @@ public class RepositoryUtils
}
public static Collection<Artifact> toArtifacts(Collection<org.apache.maven.artifact.Artifact> artifactsToConvert )
{
List<Artifact> artifacts = new ArrayList<Artifact>();
for( org.apache.maven.artifact.Artifact a : artifactsToConvert )
{
artifacts.add(toArtifact(a));
}
return artifacts;
}
}