blob: 9438a651863df15cb9459fc6a57f590f1bf8280e [file] [log] [blame]
package org.apache.maven.artifact.resolver;
/*
* 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 org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.manager.WagonManager;
import org.apache.maven.artifact.metadata.ArtifactMetadata;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.metadata.Metadata;
import org.apache.maven.artifact.repository.metadata.Snapshot;
import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
import org.apache.maven.artifact.repository.metadata.Versioning;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.resolver.conflict.ConflictResolver;
import org.apache.maven.artifact.transform.ArtifactTransformationManager;
import org.apache.maven.wagon.ResourceDoesNotExistException;
import org.apache.maven.wagon.TransferFailedException;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.util.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author Jason van Zyl
* @plexus.component
*/
public class DefaultArtifactResolver
extends AbstractLogEnabled
implements ArtifactResolver
{
// ----------------------------------------------------------------------
// Components
// ----------------------------------------------------------------------
/** @plexus.requirement */
private WagonManager wagonManager;
/** @plexus.requirement */
private ArtifactTransformationManager transformationManager;
/** @plexus.requirement */
protected ArtifactFactory artifactFactory;
/** @plexus.requirement */
private ArtifactCollector artifactCollector;
// ----------------------------------------------------------------------
// Implementation
// ----------------------------------------------------------------------
public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
ArtifactRepository localRepository )
throws ArtifactResolutionException, ArtifactNotFoundException
{
resolve( artifact, remoteRepositories, localRepository, false );
}
public void resolveAlways( Artifact artifact, List<ArtifactRepository> remoteRepositories,
ArtifactRepository localRepository )
throws ArtifactResolutionException, ArtifactNotFoundException
{
resolve( artifact, remoteRepositories, localRepository, true );
}
private void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
ArtifactRepository localRepository, boolean force )
throws ArtifactResolutionException, ArtifactNotFoundException
{
if ( artifact == null )
{
return;
}
if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
{
File systemFile = artifact.getFile();
if ( systemFile == null )
{
throw new ArtifactNotFoundException( "System artifact: " + artifact + " has no file attached", artifact );
}
if ( !systemFile.exists() )
{
throw new ArtifactNotFoundException( "System artifact: " + artifact + " not found in path: "
+ systemFile, artifact );
}
if ( !systemFile.isFile() )
{
throw new ArtifactNotFoundException( "System artifact: " + artifact + " is not a file: " + systemFile,
artifact );
}
artifact.setResolved( true );
}
else if ( !artifact.isResolved() )
{
// ----------------------------------------------------------------------
// Check for the existence of the artifact in the specified local
// ArtifactRepository. If it is present then simply return as the
// request for resolution has been satisfied.
// ----------------------------------------------------------------------
String localPath = localRepository.pathOf( artifact );
artifact.setFile( new File( localRepository.getBasedir(), localPath ) );
transformationManager.transformForResolve( artifact, remoteRepositories, localRepository );
boolean localCopy = isLocalCopy( artifact );
File destination = artifact.getFile();
boolean resolved = false;
if ( !wagonManager.isOnline() )
{
if ( !destination.exists() )
{
throw new ArtifactNotFoundException( "System is offline.", artifact );
}
}
// There are three conditions in which we'll go after the artifact here:
// 1. the force flag is set.
// 2. the artifact's file doesn't exist (this would be true for release or snapshot artifacts)
// 3. the artifact is a snapshot and is not a locally installed snapshot
// TODO: Should it matter whether it's a locally installed snapshot??
else if ( force || !destination.exists() || ( artifact.isSnapshot() && !localCopy ) )
{
try
{
if ( artifact.getRepository() != null )
{
// the transformations discovered the artifact - so use it exclusively
wagonManager.getArtifact( artifact, artifact.getRepository(), force );
}
else
{
wagonManager.getArtifact( artifact, remoteRepositories, force );
}
if ( !artifact.isResolved() && !destination.exists() )
{
throw new ArtifactResolutionException(
"Failed to resolve artifact, possibly due to a repository list that is not appropriately equipped for this artifact's metadata.",
artifact, getMirroredRepositories( remoteRepositories ) );
}
}
catch ( ResourceDoesNotExistException e )
{
throw new ArtifactNotFoundException( e.getMessage(), artifact,
getMirroredRepositories( remoteRepositories ), e );
}
catch ( TransferFailedException e )
{
throw new ArtifactResolutionException( e.getMessage(), artifact,
getMirroredRepositories( remoteRepositories ), e );
}
resolved = true;
}
if ( destination.exists() )
{
// locally resolved...no need to hit the remote repo.
artifact.setResolved( true );
}
if ( artifact.isSnapshot() && !artifact.getBaseVersion().equals( artifact.getVersion() ) )
{
String version = artifact.getVersion();
artifact.selectVersion( artifact.getBaseVersion() );
File copy = new File( localRepository.getBasedir(), localRepository.pathOf( artifact ) );
if ( resolved || !copy.exists() )
{
// recopy file if it was reresolved, or doesn't exist.
try
{
FileUtils.copyFile( destination, copy );
copy.setLastModified( destination.lastModified() );
}
catch ( IOException e )
{
throw new ArtifactResolutionException( "Unable to copy resolved artifact for local use: "
+ e.getMessage(), artifact, getMirroredRepositories( remoteRepositories ), e );
}
}
artifact.setFile( copy );
artifact.selectVersion( version );
}
}
}
private boolean isLocalCopy( Artifact artifact )
{
boolean localCopy = false;
for ( ArtifactMetadata m : artifact.getMetadataList() )
{
if ( m instanceof SnapshotArtifactRepositoryMetadata )
{
SnapshotArtifactRepositoryMetadata snapshotMetadata = (SnapshotArtifactRepositoryMetadata) m;
Metadata metadata = snapshotMetadata.getMetadata();
if ( metadata != null )
{
Versioning versioning = metadata.getVersioning();
if ( versioning != null )
{
Snapshot snapshot = versioning.getSnapshot();
if ( snapshot != null )
{
// TODO is it possible to have more than one SnapshotArtifactRepositoryMetadata
localCopy = snapshot.isLocalCopy();
}
}
}
}
}
return localCopy;
}
public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
ArtifactRepository localRepository,
List<ArtifactRepository> remoteRepositories,
ArtifactMetadataSource source, ArtifactFilter filter )
throws ArtifactResolutionException, ArtifactNotFoundException
{
return resolveTransitively( artifacts, originatingArtifact, Collections.EMPTY_MAP, localRepository,
remoteRepositories, source, filter );
}
public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
Map managedVersions, ArtifactRepository localRepository,
List<ArtifactRepository> remoteRepositories,
ArtifactMetadataSource source )
throws ArtifactResolutionException, ArtifactNotFoundException
{
return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
remoteRepositories, source, null );
}
public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
Map managedVersions, ArtifactRepository localRepository,
List<ArtifactRepository> remoteRepositories,
ArtifactMetadataSource source, ArtifactFilter filter )
throws ArtifactResolutionException, ArtifactNotFoundException
{
return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
remoteRepositories, source, filter, null );
}
public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
List<ArtifactRepository> remoteRepositories,
ArtifactRepository localRepository,
ArtifactMetadataSource source )
throws ArtifactResolutionException, ArtifactNotFoundException
{
return resolveTransitively( artifacts, originatingArtifact, localRepository, remoteRepositories, source, null );
}
public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
List<ArtifactRepository> remoteRepositories,
ArtifactRepository localRepository,
ArtifactMetadataSource source,
List<ResolutionListener> listeners )
throws ArtifactResolutionException, ArtifactNotFoundException
{
return resolveTransitively( artifacts, originatingArtifact,
Collections.EMPTY_MAP, localRepository, remoteRepositories, source, null, listeners );
}
public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
Map managedVersions, ArtifactRepository localRepository,
List<ArtifactRepository> remoteRepositories,
ArtifactMetadataSource source, ArtifactFilter filter,
List<ResolutionListener> listeners )
throws ArtifactResolutionException, ArtifactNotFoundException
{
return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
remoteRepositories, source, filter, listeners, null );
}
public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
Map managedVersions, ArtifactRepository localRepository,
List<ArtifactRepository> remoteRepositories,
ArtifactMetadataSource source, ArtifactFilter filter,
List<ResolutionListener> listeners,
List<ConflictResolver> conflictResolvers )
throws ArtifactResolutionException, ArtifactNotFoundException
{
if ( listeners == null )
{
// TODO: this is simplistic.
listeners = new ArrayList<ResolutionListener>();
if ( getLogger().isDebugEnabled() )
{
listeners.add( new DebugResolutionListener( getLogger() ) );
}
listeners.add( new WarningResolutionListener( getLogger() ) );
}
ArtifactResolutionResult result;
result =
artifactCollector.collect( artifacts, originatingArtifact, managedVersions, localRepository,
remoteRepositories, source, filter, listeners, conflictResolvers );
// We have collected all the problems so let's mimic the way the old code worked and just blow up right here.
// That's right lets just let it rip right here and send a big incomprehensible blob of text at unsuspecting
// users. Bad dog!
// Metadata cannot be found
if ( result.hasMetadataResolutionExceptions() )
{
throw result.getMetadataResolutionException( 0 );
}
// Metadata cannot be retrieved
// Cyclic Dependency Error
if ( result.hasCircularDependencyExceptions() )
{
throw result.getCircularDependencyException( 0 );
}
// Version Range Violation
if ( result.hasVersionRangeViolations() )
{
throw result.getVersionRangeViolation( 0 );
}
List<Artifact> resolvedArtifacts = new ArrayList<Artifact>();
List<Artifact> missingArtifacts = new ArrayList<Artifact>();
for ( ResolutionNode node : result.getArtifactResolutionNodes() )
{
try
{
resolve( node.getArtifact(), node.getRemoteRepositories(), localRepository );
resolvedArtifacts.add( node.getArtifact() );
}
catch ( ArtifactNotFoundException anfe )
{
getLogger().debug( anfe.getMessage(), anfe );
missingArtifacts.add( node.getArtifact() );
}
}
if ( missingArtifacts.size() > 0 )
{
throw new MultipleArtifactsNotFoundException( originatingArtifact, resolvedArtifacts, missingArtifacts,
getMirroredRepositories( remoteRepositories ) );
}
return result;
}
private List<ArtifactRepository> getMirroredRepositories( List<ArtifactRepository> remoteRepositories )
{
Map<String, ArtifactRepository> repos = new HashMap<String, ArtifactRepository>();
for ( ArtifactRepository repository : remoteRepositories )
{
ArtifactRepository repo = wagonManager.getMirrorRepository( repository );
repos.put( repo.getId(), repo );
}
return new ArrayList<ArtifactRepository>( repos.values() );
}
// ------------------------------------------------------------------------
//
// ------------------------------------------------------------------------
public ArtifactResolutionResult resolve( ArtifactResolutionRequest request )
{
Artifact originatingArtifact = request.getArtifact();
Set<Artifact> artifacts = request.getArtifactDependencies();
Map managedVersions = request.getManagedVersionMap();
ArtifactRepository localRepository = request.getLocalRepository();
List<ArtifactRepository> remoteRepositories = request.getRemoteRepostories();
ArtifactMetadataSource source = request.getMetadataSource();
List<ResolutionListener> listeners = request.getListeners();
ArtifactFilter filter = request.getFilter();
// This is an attempt to get the metadata for the artifacts we are ultimately trying to resolve.
// We still
ArtifactResolutionResult result =
artifactCollector.collect( artifacts, originatingArtifact, managedVersions, localRepository,
remoteRepositories, source, filter, listeners );
// Let's grab all the repositories that were gleaned. This we should know up front. I'm not sure
// what the metadata source is doing. Repositories in POMs are deadly.
result.setRepositories( remoteRepositories );
// We have metadata retrieval problems, or there are cycles that have been detected
// so we give this back to the calling code and let them deal with this information
// appropriately.
if ( result.hasMetadataResolutionExceptions() || result.hasVersionRangeViolations() )
{
return result;
}
for ( ResolutionNode node : result.getArtifactResolutionNodes() )
{
try
{
resolve( node.getArtifact(), node.getRemoteRepositories(), localRepository );
}
catch ( ArtifactNotFoundException anfe )
{
// These are cases where the artifact just isn't present in any of the remote repositories
// because it wasn't deployed, or it was deployed in the wrong place.
result.addMissingArtifact( node.getArtifact() );
}
catch ( ArtifactResolutionException e )
{
// This is really a wagon TransferFailedException so something went wrong after we successfully
// retrieved the metadata.
result.addErrorArtifactException( e );
}
}
return result;
}
}