mirror of https://github.com/apache/maven.git
PR: MNG-505
enable version ranges in resolution (only default conflict resolution - nearest suggested version, fail if over-constrained) git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@219844 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
9e661cadb3
commit
289aa0f6a5
|
@ -20,6 +20,7 @@ import org.apache.maven.artifact.handler.ArtifactHandler;
|
|||
import org.apache.maven.artifact.metadata.ArtifactMetadata;
|
||||
import org.apache.maven.artifact.repository.ArtifactRepository;
|
||||
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
@ -107,4 +108,10 @@ public interface Artifact
|
|||
void setDependencyTrail( List dependencyTrail );
|
||||
|
||||
void setScope( String scope );
|
||||
|
||||
VersionRange getVersionRange();
|
||||
|
||||
void setVersionRange( VersionRange newRange );
|
||||
|
||||
void selectVersion( String version );
|
||||
}
|
|
@ -78,9 +78,7 @@ public class DefaultArtifact
|
|||
|
||||
this.artifactId = artifactId;
|
||||
|
||||
this.versionRange = versionRange;
|
||||
|
||||
this.version = versionRange == null ? null : versionRange.getRecommendedVersion().toString();
|
||||
setVersionRange( versionRange );
|
||||
|
||||
this.artifactHandler = artifactHandler;
|
||||
|
||||
|
@ -113,7 +111,7 @@ public class DefaultArtifact
|
|||
"The type cannot be empty." );
|
||||
}
|
||||
|
||||
if ( getVersion() == null )
|
||||
if ( version == null && versionRange == null )
|
||||
{
|
||||
throw new InvalidArtifactRTException( groupId, artifactId, getVersion(), type,
|
||||
"The version cannot be empty." );
|
||||
|
@ -229,7 +227,10 @@ public class DefaultArtifact
|
|||
result = 37 * result + groupId.hashCode();
|
||||
result = 37 * result + artifactId.hashCode();
|
||||
result = 37 * result + type.hashCode();
|
||||
result = 37 * result + version.hashCode();
|
||||
if ( version != null )
|
||||
{
|
||||
result = 37 * result + version.hashCode();
|
||||
}
|
||||
result = 37 * result + ( classifier != null ? classifier.hashCode() : 0 );
|
||||
return result;
|
||||
}
|
||||
|
@ -380,4 +381,29 @@ public class DefaultArtifact
|
|||
{
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public VersionRange getVersionRange()
|
||||
{
|
||||
return versionRange;
|
||||
}
|
||||
|
||||
public final void setVersionRange( VersionRange versionRange )
|
||||
{
|
||||
this.versionRange = versionRange;
|
||||
|
||||
if ( versionRange != null && versionRange.getRecommendedVersion() != null )
|
||||
{
|
||||
this.version = versionRange.getRecommendedVersion().toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.version = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void selectVersion( String version )
|
||||
{
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
|
|||
import org.apache.maven.artifact.metadata.ResolutionGroup;
|
||||
import org.apache.maven.artifact.repository.ArtifactRepository;
|
||||
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
|
||||
import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -60,41 +62,47 @@ public class DefaultArtifactCollector
|
|||
Map resolvedArtifacts = new HashMap();
|
||||
|
||||
ResolutionNode root = new ResolutionNode( originatingArtifact, remoteRepositories );
|
||||
root.addDependencies( artifacts, remoteRepositories, filter );
|
||||
|
||||
recurse( root, resolvedArtifacts, managedVersions, localRepository, remoteRepositories, source, filter,
|
||||
artifactFactory, listeners );
|
||||
|
||||
Set set = new HashSet();
|
||||
|
||||
for ( Iterator i = resolvedArtifacts.values().iterator(); i.hasNext(); )
|
||||
try
|
||||
{
|
||||
ResolutionNode node = (ResolutionNode) i.next();
|
||||
if ( !node.equals( root ) )
|
||||
root.addDependencies( artifacts, remoteRepositories, filter );
|
||||
|
||||
recurse( root, resolvedArtifacts, managedVersions, localRepository, remoteRepositories, source, filter,
|
||||
artifactFactory, listeners );
|
||||
|
||||
Set set = new HashSet();
|
||||
|
||||
for ( Iterator i = resolvedArtifacts.values().iterator(); i.hasNext(); )
|
||||
{
|
||||
Artifact artifact = node.getArtifact();
|
||||
ResolutionNode node = (ResolutionNode) i.next();
|
||||
if ( !node.equals( root ) )
|
||||
{
|
||||
Artifact artifact = node.getArtifact();
|
||||
|
||||
artifact.setDependencyTrail( node.getDependencyTrail() );
|
||||
artifact.setDependencyTrail( node.getDependencyTrail() );
|
||||
|
||||
set.add( node );
|
||||
set.add( node );
|
||||
}
|
||||
}
|
||||
|
||||
ArtifactResolutionResult result = new ArtifactResolutionResult();
|
||||
result.setArtifactResolutionNodes( set );
|
||||
return result;
|
||||
}
|
||||
catch ( OverConstrainedVersionException e )
|
||||
{
|
||||
throw new ArtifactResolutionException( "Unable to mediate dependency", e );
|
||||
}
|
||||
|
||||
ArtifactResolutionResult result = new ArtifactResolutionResult();
|
||||
|
||||
result.setArtifactResolutionNodes( set );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void recurse( ResolutionNode node, Map resolvedArtifacts, Map managedVersions,
|
||||
ArtifactRepository localRepository, List remoteRepositories, ArtifactMetadataSource source,
|
||||
ArtifactFilter filter, ArtifactFactory artifactFactory, List listeners )
|
||||
throws CyclicDependencyException, TransitiveArtifactResolutionException
|
||||
throws CyclicDependencyException, TransitiveArtifactResolutionException, OverConstrainedVersionException
|
||||
{
|
||||
fireEvent( ResolutionListener.TEST_ARTIFACT, listeners, node );
|
||||
|
||||
// TODO: conflict resolvers, shouldn't be munging original artifact perhaps?
|
||||
// TODO: use as a conflict resolver
|
||||
Object key = node.getKey();
|
||||
if ( managedVersions.containsKey( key ) )
|
||||
{
|
||||
|
@ -116,6 +124,25 @@ public class DefaultArtifactCollector
|
|||
if ( previous != null )
|
||||
{
|
||||
// TODO: use as conflict resolver(s), chain and introduce version mediation
|
||||
VersionRange previousRange = previous.getArtifact().getVersionRange();
|
||||
VersionRange currentRange = node.getArtifact().getVersionRange();
|
||||
|
||||
if ( previousRange == null )
|
||||
{
|
||||
// version was already resolved
|
||||
node.getArtifact().setVersion( previous.getArtifact().getVersion() );
|
||||
}
|
||||
else if ( currentRange == null )
|
||||
{
|
||||
// version was already resolved
|
||||
previous.getArtifact().setVersion( node.getArtifact().getVersion() );
|
||||
}
|
||||
else
|
||||
{
|
||||
VersionRange newRange = previousRange.restrict( currentRange );
|
||||
previous.getArtifact().setVersionRange( newRange );
|
||||
node.getArtifact().setVersionRange( newRange );
|
||||
}
|
||||
|
||||
// previous one is more dominant
|
||||
if ( previous.getDepth() <= node.getDepth() )
|
||||
|
@ -145,10 +172,18 @@ public class DefaultArtifactCollector
|
|||
ResolutionNode child = (ResolutionNode) i.next();
|
||||
if ( !child.isResolved() )
|
||||
{
|
||||
Artifact artifact = child.getArtifact();
|
||||
try
|
||||
{
|
||||
ResolutionGroup rGroup = source.retrieve( child.getArtifact(), localRepository,
|
||||
remoteRepositories );
|
||||
if ( artifact.getVersion() == null )
|
||||
{
|
||||
// set the recommended version
|
||||
VersionRange versionRange = artifact.getVersionRange();
|
||||
String version = versionRange.getSelectedVersion().toString();
|
||||
artifact.selectVersion( version );
|
||||
}
|
||||
|
||||
ResolutionGroup rGroup = source.retrieve( artifact, localRepository, remoteRepositories );
|
||||
child.addDependencies( rGroup.getArtifacts(), rGroup.getResolutionRepositories(), filter );
|
||||
}
|
||||
catch ( CyclicDependencyException e )
|
||||
|
@ -162,9 +197,8 @@ public class DefaultArtifactCollector
|
|||
}
|
||||
catch ( ArtifactMetadataRetrievalException e )
|
||||
{
|
||||
child.getArtifact().setDependencyTrail( node.getDependencyTrail() );
|
||||
throw new TransitiveArtifactResolutionException( e.getMessage(), child.getArtifact(),
|
||||
remoteRepositories, e );
|
||||
artifact.setDependencyTrail( node.getDependencyTrail() );
|
||||
throw new TransitiveArtifactResolutionException( e.getMessage(), artifact, remoteRepositories, e );
|
||||
}
|
||||
|
||||
recurse( child, resolvedArtifacts, managedVersions, localRepository, remoteRepositories, source, filter,
|
||||
|
|
|
@ -1,7 +1,25 @@
|
|||
package org.apache.maven.artifact.resolver;
|
||||
|
||||
/*
|
||||
* Copyright 2001-2005 The Apache Software Foundation.
|
||||
*
|
||||
* Licensed 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 org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
|
||||
import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -14,7 +32,7 @@ public class ResolutionNode
|
|||
{
|
||||
private Artifact artifact;
|
||||
|
||||
private List children = null;
|
||||
private List children;
|
||||
|
||||
private final List parents;
|
||||
|
||||
|
@ -55,7 +73,7 @@ public class ResolutionNode
|
|||
}
|
||||
|
||||
public void addDependencies( Set artifacts, List remoteRepositories, ArtifactFilter filter )
|
||||
throws CyclicDependencyException
|
||||
throws CyclicDependencyException, OverConstrainedVersionException
|
||||
{
|
||||
children = new ArrayList( artifacts.size() );
|
||||
|
||||
|
@ -78,12 +96,22 @@ public class ResolutionNode
|
|||
}
|
||||
|
||||
public List getDependencyTrail()
|
||||
throws OverConstrainedVersionException
|
||||
{
|
||||
List path = new LinkedList();
|
||||
ResolutionNode node = this;
|
||||
while ( node != null )
|
||||
{
|
||||
path.add( 0, node.getArtifact().getId() );
|
||||
Artifact artifact = node.getArtifact();
|
||||
if ( artifact.getVersion() == null )
|
||||
{
|
||||
// set the recommended version
|
||||
VersionRange versionRange = artifact.getVersionRange();
|
||||
String version = versionRange.getSelectedVersion().toString();
|
||||
artifact.selectVersion( version );
|
||||
}
|
||||
|
||||
path.add( 0, artifact.getId() );
|
||||
node = node.parent;
|
||||
}
|
||||
return path;
|
||||
|
@ -108,7 +136,7 @@ public class ResolutionNode
|
|||
{
|
||||
this.artifact = artifact;
|
||||
}
|
||||
|
||||
|
||||
public List getRemoteRepositories()
|
||||
{
|
||||
return remoteRepositories;
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package org.apache.maven.artifact.versioning;
|
||||
|
||||
/*
|
||||
* Copyright 2001-2005 The Apache Software Foundation.
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Occurs when ranges exclude each other and no valid value remains.
|
||||
*
|
||||
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
|
||||
* @version $Id$
|
||||
*/
|
||||
public class OverConstrainedVersionException
|
||||
extends Exception
|
||||
{
|
||||
public OverConstrainedVersionException( String msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
|
@ -29,6 +29,8 @@ import java.util.List;
|
|||
*/
|
||||
public class VersionRange
|
||||
{
|
||||
private final ArtifactVersion RELEASE = new DefaultArtifactVersion( "RELEASE" );
|
||||
|
||||
private final ArtifactVersion recommendedVersion;
|
||||
|
||||
private final List restrictions;
|
||||
|
@ -382,4 +384,66 @@ public class VersionRange
|
|||
return v2;
|
||||
}
|
||||
}
|
||||
|
||||
public ArtifactVersion getSelectedVersion()
|
||||
throws OverConstrainedVersionException
|
||||
{
|
||||
ArtifactVersion version;
|
||||
if ( recommendedVersion != null )
|
||||
{
|
||||
version = recommendedVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( restrictions.size() == 0 )
|
||||
{
|
||||
throw new OverConstrainedVersionException( "The artifact has no valid ranges" );
|
||||
}
|
||||
else
|
||||
{
|
||||
Restriction restriction = (Restriction) restrictions.get( restrictions.size() - 1 );
|
||||
// TODO: how can we find the latest release before something to facilitate ) at the end?
|
||||
version = restriction.getUpperBound();
|
||||
if ( version == null )
|
||||
{
|
||||
version = RELEASE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
if ( recommendedVersion != null )
|
||||
{
|
||||
return recommendedVersion.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for ( Iterator i = restrictions.iterator(); i.hasNext(); )
|
||||
{
|
||||
Restriction r = (Restriction) i.next();
|
||||
|
||||
buf.append( r.isLowerBoundInclusive() ? "[" : "(" );
|
||||
if ( r.getLowerBound() != null )
|
||||
{
|
||||
buf.append( r.getLowerBound().toString() );
|
||||
}
|
||||
buf.append( "," );
|
||||
if ( r.getUpperBound() != null )
|
||||
{
|
||||
buf.append( r.getUpperBound().toString() );
|
||||
}
|
||||
buf.append( r.isUpperBoundInclusive() ? "]" : ")" );
|
||||
|
||||
if ( i.hasNext() )
|
||||
{
|
||||
buf.append( "," );
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,6 +135,73 @@ public class DefaultArtifactCollectorTest
|
|||
ArtifactResolutionResult res = collect( a );
|
||||
assertEquals( "Check artifact list", createSet( new Object[]{a.artifact, b.artifact, c.artifact} ),
|
||||
res.getArtifacts() );
|
||||
assertEquals( "Check version", "3.0", getArtifact( "c", res.getArtifacts() ).getVersion() );
|
||||
}
|
||||
|
||||
public void testResolveNearestWithRanges()
|
||||
throws ArtifactResolutionException
|
||||
{
|
||||
ArtifactSpec a = createArtifact( "a", "1.0" );
|
||||
ArtifactSpec b = a.addDependency( "b", "1.0" );
|
||||
ArtifactSpec c = a.addDependency( "c", "2.0" );
|
||||
|
||||
b.addDependency( "c", "[1.0,3.0]" );
|
||||
|
||||
ArtifactResolutionResult res = collect( a );
|
||||
assertEquals( "Check artifact list", createSet( new Object[]{a.artifact, b.artifact, c.artifact} ),
|
||||
res.getArtifacts() );
|
||||
assertEquals( "Check version", "2.0", getArtifact( "c", res.getArtifacts() ).getVersion() );
|
||||
}
|
||||
|
||||
public void testCompatibleRanges()
|
||||
throws ArtifactResolutionException
|
||||
{
|
||||
ArtifactSpec a = createArtifact( "a", "1.0" );
|
||||
ArtifactSpec b = a.addDependency( "b", "1.0" );
|
||||
a.addDependency( "c", "[2.0,2.5]" );
|
||||
b.addDependency( "c", "[1.0,3.0]" );
|
||||
|
||||
ArtifactResolutionResult res = collect( a );
|
||||
|
||||
ArtifactSpec c = createArtifact( "c", "2.5" );
|
||||
assertEquals( "Check artifact list", createSet( new Object[]{a.artifact, b.artifact, c.artifact} ),
|
||||
res.getArtifacts() );
|
||||
assertEquals( "Check version", "2.5", getArtifact( "c", res.getArtifacts() ).getVersion() );
|
||||
}
|
||||
|
||||
public void testIncompatibleRanges()
|
||||
throws ArtifactResolutionException
|
||||
{
|
||||
ArtifactSpec a = createArtifact( "a", "1.0" );
|
||||
ArtifactSpec b = a.addDependency( "b", "1.0" );
|
||||
a.addDependency( "c", "[2.4,3.0]" );
|
||||
|
||||
b.addDependency( "c", "[1.0,2.0]" );
|
||||
|
||||
try
|
||||
{
|
||||
ArtifactResolutionResult res = collect( a );
|
||||
fail( "Should not succeed collecting, got: " + res.getArtifacts() );
|
||||
}
|
||||
catch ( ArtifactResolutionException expected )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void testUnboundedRange()
|
||||
throws ArtifactResolutionException
|
||||
{
|
||||
ArtifactSpec a = createArtifact( "a", "1.0" );
|
||||
ArtifactSpec b = a.addDependency( "b", "1.0" );
|
||||
a.addDependency( "c", "[2.0,]" );
|
||||
b.addDependency( "c", "[1.0,]" );
|
||||
|
||||
ArtifactResolutionResult res = collect( a );
|
||||
|
||||
ArtifactSpec c = createArtifact( "c", "RELEASE" );
|
||||
assertEquals( "Check artifact list", createSet( new Object[]{a.artifact, b.artifact, c.artifact} ),
|
||||
res.getArtifacts() );
|
||||
assertEquals( "Check version", "RELEASE", getArtifact( "c", res.getArtifacts() ).getVersion() );
|
||||
}
|
||||
|
||||
public void testResolveManagedVersion()
|
||||
|
@ -303,8 +370,9 @@ public class DefaultArtifactCollectorTest
|
|||
private ArtifactSpec createArtifact( String id, String version, String scope )
|
||||
{
|
||||
ArtifactSpec spec = new ArtifactSpec();
|
||||
spec.artifact = artifactFactory.createArtifact( GROUP_ID, id, version, scope, "jar" );
|
||||
source.artifacts.put( spec.artifact.getId(), spec );
|
||||
Artifact artifact = artifactFactory.createArtifact( GROUP_ID, id, version, scope, "jar" );
|
||||
spec.artifact = artifact;
|
||||
source.artifacts.put( source.getKey( artifact ), spec );
|
||||
return spec;
|
||||
}
|
||||
|
||||
|
@ -346,7 +414,9 @@ public class DefaultArtifactCollectorTest
|
|||
List remoteRepositories )
|
||||
throws ArtifactMetadataRetrievalException
|
||||
{
|
||||
ArtifactSpec a = (ArtifactSpec) artifacts.get( artifact.getId() );
|
||||
String key = getKey( artifact );
|
||||
|
||||
ArtifactSpec a = (ArtifactSpec) artifacts.get( key );
|
||||
try
|
||||
{
|
||||
return new ResolutionGroup( createArtifacts( artifactFactory, a.dependencies, artifact.getScope(),
|
||||
|
@ -358,6 +428,11 @@ public class DefaultArtifactCollectorTest
|
|||
}
|
||||
}
|
||||
|
||||
private String getKey( Artifact artifact )
|
||||
{
|
||||
return artifact.getDependencyConflictId() + ":" + artifact.getVersionRange();
|
||||
}
|
||||
|
||||
private Set createArtifacts( ArtifactFactory artifactFactory, Set dependencies, String inheritedScope,
|
||||
ArtifactFilter dependencyFilter )
|
||||
throws InvalidVersionSpecificationException
|
||||
|
|
Loading…
Reference in New Issue