http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java new file mode 100644 index 0000000..0d5a880 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java @@ -0,0 +1,612 @@ +package org.apache.maven.repository.internal; + +/* + * 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.commons.lang3.Validate; +import org.apache.maven.artifact.repository.metadata.Snapshot; +import org.apache.maven.artifact.repository.metadata.SnapshotVersion; +import org.apache.maven.artifact.repository.metadata.Versioning; +import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader; +import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.component.annotations.Requirement; +import org.codehaus.plexus.util.StringUtils; +import org.eclipse.aether.RepositoryCache; +import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.RepositoryEvent.EventType; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.SyncContext; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.impl.MetadataResolver; +import org.eclipse.aether.impl.RepositoryEventDispatcher; +import org.eclipse.aether.impl.SyncContextFactory; +import org.eclipse.aether.impl.VersionResolver; +import org.eclipse.aether.internal.impl.CacheUtils; +import org.eclipse.aether.metadata.DefaultMetadata; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.ArtifactRepository; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.repository.WorkspaceReader; +import org.eclipse.aether.repository.WorkspaceRepository; +import org.eclipse.aether.resolution.MetadataRequest; +import org.eclipse.aether.resolution.MetadataResult; +import org.eclipse.aether.resolution.VersionRequest; +import org.eclipse.aether.resolution.VersionResolutionException; +import org.eclipse.aether.resolution.VersionResult; +import org.eclipse.aether.spi.locator.Service; +import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.log.Logger; +import org.eclipse.aether.spi.log.LoggerFactory; +import org.eclipse.aether.spi.log.NullLoggerFactory; +import org.eclipse.aether.util.ConfigUtils; + +import javax.inject.Inject; +import javax.inject.Named; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Benjamin Bentmann + */ +@Named +@Component( role = VersionResolver.class ) +public class DefaultVersionResolver + implements VersionResolver, Service +{ + + private static final String MAVEN_METADATA_XML = "maven-metadata.xml"; + + private static final String RELEASE = "RELEASE"; + + private static final String LATEST = "LATEST"; + + private static final String SNAPSHOT = "SNAPSHOT"; + + @SuppressWarnings( "unused" ) + @Requirement( role = LoggerFactory.class ) + private Logger logger = NullLoggerFactory.LOGGER; + + @Requirement + private MetadataResolver metadataResolver; + + @Requirement + private SyncContextFactory syncContextFactory; + + @Requirement + private RepositoryEventDispatcher repositoryEventDispatcher; + + public DefaultVersionResolver() + { + // enable no-arg constructor + } + + @Inject + DefaultVersionResolver( MetadataResolver metadataResolver, SyncContextFactory syncContextFactory, + RepositoryEventDispatcher repositoryEventDispatcher, LoggerFactory loggerFactory ) + { + setMetadataResolver( metadataResolver ); + setSyncContextFactory( syncContextFactory ); + setLoggerFactory( loggerFactory ); + setRepositoryEventDispatcher( repositoryEventDispatcher ); + } + + public void initService( ServiceLocator locator ) + { + setLoggerFactory( locator.getService( LoggerFactory.class ) ); + setMetadataResolver( locator.getService( MetadataResolver.class ) ); + setSyncContextFactory( locator.getService( SyncContextFactory.class ) ); + setRepositoryEventDispatcher( locator.getService( RepositoryEventDispatcher.class ) ); + } + + public DefaultVersionResolver setLoggerFactory( LoggerFactory loggerFactory ) + { + this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() ); + return this; + } + + void setLogger( LoggerFactory loggerFactory ) + { + // plexus support + setLoggerFactory( loggerFactory ); + } + + public DefaultVersionResolver setMetadataResolver( MetadataResolver metadataResolver ) + { + this.metadataResolver = Validate.notNull( metadataResolver, "metadataResolver cannot be null" ); + return this; + } + + public DefaultVersionResolver setSyncContextFactory( SyncContextFactory syncContextFactory ) + { + this.syncContextFactory = Validate.notNull( syncContextFactory, "syncContextFactory cannot be null" ); + return this; + } + + public DefaultVersionResolver setRepositoryEventDispatcher( RepositoryEventDispatcher repositoryEventDispatcher ) + { + this.repositoryEventDispatcher = Validate.notNull( repositoryEventDispatcher, + "repositoryEventDispatcher cannot be null" ); + return this; + } + + public VersionResult resolveVersion( RepositorySystemSession session, VersionRequest request ) + throws VersionResolutionException + { + RequestTrace trace = RequestTrace.newChild( request.getTrace(), request ); + + Artifact artifact = request.getArtifact(); + + String version = artifact.getVersion(); + + VersionResult result = new VersionResult( request ); + + Key cacheKey = null; + RepositoryCache cache = session.getCache(); + if ( cache != null && !ConfigUtils.getBoolean( session, false, "aether.versionResolver.noCache" ) ) + { + cacheKey = new Key( session, request ); + + Object obj = cache.get( session, cacheKey ); + if ( obj instanceof Record ) + { + Record record = (Record) obj; + result.setVersion( record.version ); + result.setRepository( + CacheUtils.getRepository( session, request.getRepositories(), record.repoClass, record.repoId ) ); + return result; + } + } + + Metadata metadata; + + if ( RELEASE.equals( version ) ) + { + metadata = new DefaultMetadata( artifact.getGroupId(), artifact.getArtifactId(), MAVEN_METADATA_XML, + Metadata.Nature.RELEASE ); + } + else if ( LATEST.equals( version ) ) + { + metadata = new DefaultMetadata( artifact.getGroupId(), artifact.getArtifactId(), MAVEN_METADATA_XML, + Metadata.Nature.RELEASE_OR_SNAPSHOT ); + } + else if ( version.endsWith( SNAPSHOT ) ) + { + WorkspaceReader workspace = session.getWorkspaceReader(); + if ( workspace != null && workspace.findVersions( artifact ).contains( version ) ) + { + metadata = null; + result.setRepository( workspace.getRepository() ); + } + else + { + metadata = + new DefaultMetadata( artifact.getGroupId(), artifact.getArtifactId(), version, MAVEN_METADATA_XML, + Metadata.Nature.SNAPSHOT ); + } + } + else + { + metadata = null; + } + + if ( metadata == null ) + { + result.setVersion( version ); + } + else + { + List<MetadataRequest> metadataReqs = new ArrayList<>( request.getRepositories().size() ); + + metadataReqs.add( new MetadataRequest( metadata, null, request.getRequestContext() ) ); + + for ( RemoteRepository repository : request.getRepositories() ) + { + MetadataRequest metadataRequest = + new MetadataRequest( metadata, repository, request.getRequestContext() ); + metadataRequest.setDeleteLocalCopyIfMissing( true ); + metadataRequest.setFavorLocalRepository( true ); + metadataRequest.setTrace( trace ); + metadataReqs.add( metadataRequest ); + } + + List<MetadataResult> metadataResults = metadataResolver.resolveMetadata( session, metadataReqs ); + + Map<String, VersionInfo> infos = new HashMap<>(); + + for ( MetadataResult metadataResult : metadataResults ) + { + result.addException( metadataResult.getException() ); + + ArtifactRepository repository = metadataResult.getRequest().getRepository(); + if ( repository == null ) + { + repository = session.getLocalRepository(); + } + + Versioning v = readVersions( session, trace, metadataResult.getMetadata(), repository, result ); + merge( artifact, infos, v, repository ); + } + + if ( RELEASE.equals( version ) ) + { + resolve( result, infos, RELEASE ); + } + else if ( LATEST.equals( version ) ) + { + if ( !resolve( result, infos, LATEST ) ) + { + resolve( result, infos, RELEASE ); + } + + if ( result.getVersion() != null && result.getVersion().endsWith( SNAPSHOT ) ) + { + VersionRequest subRequest = new VersionRequest(); + subRequest.setArtifact( artifact.setVersion( result.getVersion() ) ); + if ( result.getRepository() instanceof RemoteRepository ) + { + RemoteRepository r = (RemoteRepository) result.getRepository(); + subRequest.setRepositories( Collections.singletonList( r ) ); + } + else + { + subRequest.setRepositories( request.getRepositories() ); + } + VersionResult subResult = resolveVersion( session, subRequest ); + result.setVersion( subResult.getVersion() ); + result.setRepository( subResult.getRepository() ); + for ( Exception exception : subResult.getExceptions() ) + { + result.addException( exception ); + } + } + } + else + { + String key = SNAPSHOT + getKey( artifact.getClassifier(), artifact.getExtension() ); + merge( infos, SNAPSHOT, key ); + if ( !resolve( result, infos, key ) ) + { + result.setVersion( version ); + } + } + + if ( StringUtils.isEmpty( result.getVersion() ) ) + { + throw new VersionResolutionException( result ); + } + } + + if ( cacheKey != null && metadata != null && isSafelyCacheable( session, artifact ) ) + { + cache.put( session, cacheKey, new Record( result.getVersion(), result.getRepository() ) ); + } + + return result; + } + + private boolean resolve( VersionResult result, Map<String, VersionInfo> infos, String key ) + { + VersionInfo info = infos.get( key ); + if ( info != null ) + { + result.setVersion( info.version ); + result.setRepository( info.repository ); + } + return info != null; + } + + private Versioning readVersions( RepositorySystemSession session, RequestTrace trace, Metadata metadata, + ArtifactRepository repository, VersionResult result ) + { + Versioning versioning = null; + + try + { + if ( metadata != null ) + { + try ( SyncContext syncContext = syncContextFactory.newInstance( session, true ) ) + { + syncContext.acquire( null, Collections.singleton( metadata ) ); + + if ( metadata.getFile() != null && metadata.getFile().exists() ) + { + try ( InputStream in = new FileInputStream( metadata.getFile() ) ) + { + org.apache.maven.artifact.repository.metadata.Metadata m = + new MetadataXpp3Reader().read( in, false ); + + versioning = m.getVersioning(); + } + } + } + } + + /* + * NOTE: Users occasionally misuse the id "local" for remote repos which screws up the metadata + * of the local repository. This is especially troublesome during snapshot resolution so we try + * to handle that gracefully. + */ + if ( versioning != null && repository instanceof LocalRepository + && versioning.getSnapshot() != null && versioning.getSnapshot().getBuildNumber() > 0 ) + { + Versioning repaired = new Versioning(); + repaired.setLastUpdated( versioning.getLastUpdated() ); + Snapshot snapshot = new Snapshot(); + snapshot.setLocalCopy( true ); + repaired.setSnapshot( snapshot ); + versioning = repaired; + + throw new IOException( "Snapshot information corrupted with remote repository data" + + ", please verify that no remote repository uses the id '" + + repository.getId() + "'" ); + } + } + catch ( Exception e ) + { + invalidMetadata( session, trace, metadata, repository, e ); + result.addException( e ); + } + + return ( versioning != null ) ? versioning : new Versioning(); + } + + private void invalidMetadata( RepositorySystemSession session, RequestTrace trace, Metadata metadata, + ArtifactRepository repository, Exception exception ) + { + RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_INVALID ); + event.setTrace( trace ); + event.setMetadata( metadata ); + event.setException( exception ); + event.setRepository( repository ); + + repositoryEventDispatcher.dispatch( event.build() ); + } + + private void merge( Artifact artifact, Map<String, VersionInfo> infos, Versioning versioning, + ArtifactRepository repository ) + { + if ( StringUtils.isNotEmpty( versioning.getRelease() ) ) + { + merge( RELEASE, infos, versioning.getLastUpdated(), versioning.getRelease(), repository ); + } + + if ( StringUtils.isNotEmpty( versioning.getLatest() ) ) + { + merge( LATEST, infos, versioning.getLastUpdated(), versioning.getLatest(), repository ); + } + + for ( SnapshotVersion sv : versioning.getSnapshotVersions() ) + { + if ( StringUtils.isNotEmpty( sv.getVersion() ) ) + { + String key = getKey( sv.getClassifier(), sv.getExtension() ); + merge( SNAPSHOT + key, infos, sv.getUpdated(), sv.getVersion(), repository ); + } + } + + Snapshot snapshot = versioning.getSnapshot(); + if ( snapshot != null && versioning.getSnapshotVersions().isEmpty() ) + { + String version = artifact.getVersion(); + if ( snapshot.getTimestamp() != null && snapshot.getBuildNumber() > 0 ) + { + String qualifier = snapshot.getTimestamp() + '-' + snapshot.getBuildNumber(); + version = version.substring( 0, version.length() - SNAPSHOT.length() ) + qualifier; + } + merge( SNAPSHOT, infos, versioning.getLastUpdated(), version, repository ); + } + } + + private void merge( String key, Map<String, VersionInfo> infos, String timestamp, String version, + ArtifactRepository repository ) + { + VersionInfo info = infos.get( key ); + if ( info == null ) + { + info = new VersionInfo( timestamp, version, repository ); + infos.put( key, info ); + } + else if ( info.isOutdated( timestamp ) ) + { + info.version = version; + info.repository = repository; + info.timestamp = timestamp; + } + } + + private void merge( Map<String, VersionInfo> infos, String srcKey, String dstKey ) + { + VersionInfo srcInfo = infos.get( srcKey ); + VersionInfo dstInfo = infos.get( dstKey ); + + if ( dstInfo == null || ( srcInfo != null && dstInfo.isOutdated( srcInfo.timestamp ) + && srcInfo.repository != dstInfo.repository ) ) + { + infos.put( dstKey, srcInfo ); + } + } + + private String getKey( String classifier, String extension ) + { + return StringUtils.clean( classifier ) + ':' + StringUtils.clean( extension ); + } + + private boolean isSafelyCacheable( RepositorySystemSession session, Artifact artifact ) + { + /* + * The workspace/reactor is in flux so we better not assume definitive information for any of its + * artifacts/projects. + */ + + WorkspaceReader workspace = session.getWorkspaceReader(); + if ( workspace == null ) + { + return true; + } + + Artifact pomArtifact = ArtifactDescriptorUtils.toPomArtifact( artifact ); + + return workspace.findArtifact( pomArtifact ) == null; + } + + private static class VersionInfo + { + + String timestamp; + + String version; + + ArtifactRepository repository; + + public VersionInfo( String timestamp, String version, ArtifactRepository repository ) + { + this.timestamp = ( timestamp != null ) ? timestamp : ""; + this.version = version; + this.repository = repository; + } + + public boolean isOutdated( String timestamp ) + { + return timestamp != null && timestamp.compareTo( this.timestamp ) > 0; + } + + } + + private static class Key + { + + private final String groupId; + + private final String artifactId; + + private final String classifier; + + private final String extension; + + private final String version; + + private final String context; + + private final File localRepo; + + private final WorkspaceRepository workspace; + + private final List<RemoteRepository> repositories; + + private final int hashCode; + + public Key( RepositorySystemSession session, VersionRequest request ) + { + Artifact artifact = request.getArtifact(); + groupId = artifact.getGroupId(); + artifactId = artifact.getArtifactId(); + classifier = artifact.getClassifier(); + extension = artifact.getExtension(); + version = artifact.getVersion(); + localRepo = session.getLocalRepository().getBasedir(); + workspace = CacheUtils.getWorkspace( session ); + repositories = new ArrayList<>( request.getRepositories().size() ); + boolean repoMan = false; + for ( RemoteRepository repository : request.getRepositories() ) + { + if ( repository.isRepositoryManager() ) + { + repoMan = true; + repositories.addAll( repository.getMirroredRepositories() ); + } + else + { + repositories.add( repository ); + } + } + context = repoMan ? request.getRequestContext() : ""; + + int hash = 17; + hash = hash * 31 + groupId.hashCode(); + hash = hash * 31 + artifactId.hashCode(); + hash = hash * 31 + classifier.hashCode(); + hash = hash * 31 + extension.hashCode(); + hash = hash * 31 + version.hashCode(); + hash = hash * 31 + localRepo.hashCode(); + hash = hash * 31 + CacheUtils.repositoriesHashCode( repositories ); + hashCode = hash; + } + + @Override + public boolean equals( Object obj ) + { + if ( obj == this ) + { + return true; + } + else if ( obj == null || !getClass().equals( obj.getClass() ) ) + { + return false; + } + + Key that = (Key) obj; + return artifactId.equals( that.artifactId ) && groupId.equals( that.groupId ) && classifier.equals( + that.classifier ) && extension.equals( that.extension ) && version.equals( that.version ) + && context.equals( that.context ) && localRepo.equals( that.localRepo ) + && CacheUtils.eq( workspace, that.workspace ) + && CacheUtils.repositoriesEquals( repositories, that.repositories ); + } + + @Override + public int hashCode() + { + return hashCode; + } + + } + + private static class Record + { + final String version; + + final String repoId; + + final Class<?> repoClass; + + public Record( String version, ArtifactRepository repository ) + { + this.version = version; + if ( repository != null ) + { + repoId = repository.getId(); + repoClass = repository.getClass(); + } + else + { + repoId = null; + repoClass = null; + } + } + } + +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadata.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadata.java new file mode 100644 index 0000000..a572010 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadata.java @@ -0,0 +1,163 @@ +package org.apache.maven.repository.internal; + +/* + * 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.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.maven.artifact.repository.metadata.Metadata; +import org.apache.maven.artifact.repository.metadata.Snapshot; +import org.apache.maven.artifact.repository.metadata.SnapshotVersion; +import org.apache.maven.artifact.repository.metadata.Versioning; +import org.eclipse.aether.artifact.Artifact; + +/** + * @author Benjamin Bentmann + */ +final class LocalSnapshotMetadata + extends MavenMetadata +{ + + private final Collection<Artifact> artifacts = new ArrayList<>(); + + private final boolean legacyFormat; + + public LocalSnapshotMetadata( Artifact artifact, boolean legacyFormat ) + { + super( createMetadata( artifact, legacyFormat ), null ); + this.legacyFormat = legacyFormat; + } + + public LocalSnapshotMetadata( Metadata metadata, File file, boolean legacyFormat ) + { + super( metadata, file ); + this.legacyFormat = legacyFormat; + } + + private static Metadata createMetadata( Artifact artifact, boolean legacyFormat ) + { + Snapshot snapshot = new Snapshot(); + snapshot.setLocalCopy( true ); + Versioning versioning = new Versioning(); + versioning.setSnapshot( snapshot ); + + Metadata metadata = new Metadata(); + metadata.setVersioning( versioning ); + metadata.setGroupId( artifact.getGroupId() ); + metadata.setArtifactId( artifact.getArtifactId() ); + metadata.setVersion( artifact.getBaseVersion() ); + + if ( !legacyFormat ) + { + metadata.setModelVersion( "1.1.0" ); + } + + return metadata; + } + + public void bind( Artifact artifact ) + { + artifacts.add( artifact ); + } + + public MavenMetadata setFile( File file ) + { + return new LocalSnapshotMetadata( metadata, file, legacyFormat ); + } + + public Object getKey() + { + return getGroupId() + ':' + getArtifactId() + ':' + getVersion(); + } + + public static Object getKey( Artifact artifact ) + { + return artifact.getGroupId() + ':' + artifact.getArtifactId() + ':' + artifact.getBaseVersion(); + } + + @Override + protected void merge( Metadata recessive ) + { + metadata.getVersioning().updateTimestamp(); + + if ( !legacyFormat ) + { + String lastUpdated = metadata.getVersioning().getLastUpdated(); + + Map<String, SnapshotVersion> versions = new LinkedHashMap<>(); + + for ( Artifact artifact : artifacts ) + { + SnapshotVersion sv = new SnapshotVersion(); + sv.setClassifier( artifact.getClassifier() ); + sv.setExtension( artifact.getExtension() ); + sv.setVersion( getVersion() ); + sv.setUpdated( lastUpdated ); + versions.put( getKey( sv.getClassifier(), sv.getExtension() ), sv ); + } + + Versioning versioning = recessive.getVersioning(); + if ( versioning != null ) + { + for ( SnapshotVersion sv : versioning.getSnapshotVersions() ) + { + String key = getKey( sv.getClassifier(), sv.getExtension() ); + if ( !versions.containsKey( key ) ) + { + versions.put( key, sv ); + } + } + } + + metadata.getVersioning().setSnapshotVersions( new ArrayList<>( versions.values() ) ); + } + + artifacts.clear(); + } + + private String getKey( String classifier, String extension ) + { + return classifier + ':' + extension; + } + + public String getGroupId() + { + return metadata.getGroupId(); + } + + public String getArtifactId() + { + return metadata.getArtifactId(); + } + + public String getVersion() + { + return metadata.getVersion(); + } + + public Nature getNature() + { + return Nature.SNAPSHOT; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator.java new file mode 100644 index 0000000..072ba66 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator.java @@ -0,0 +1,82 @@ +package org.apache.maven.repository.internal; + +/* + * 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.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.impl.MetadataGenerator; +import org.eclipse.aether.installation.InstallRequest; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.util.ConfigUtils; + +/** + * @author Benjamin Bentmann + */ +class LocalSnapshotMetadataGenerator + implements MetadataGenerator +{ + + private Map<Object, LocalSnapshotMetadata> snapshots; + + private final boolean legacyFormat; + + public LocalSnapshotMetadataGenerator( RepositorySystemSession session, InstallRequest request ) + { + legacyFormat = ConfigUtils.getBoolean( session.getConfigProperties(), false, "maven.metadata.legacy" ); + + snapshots = new LinkedHashMap<>(); + } + + public Collection<? extends Metadata> prepare( Collection<? extends Artifact> artifacts ) + { + for ( Artifact artifact : artifacts ) + { + if ( artifact.isSnapshot() ) + { + Object key = LocalSnapshotMetadata.getKey( artifact ); + LocalSnapshotMetadata snapshotMetadata = snapshots.get( key ); + if ( snapshotMetadata == null ) + { + snapshotMetadata = new LocalSnapshotMetadata( artifact, legacyFormat ); + snapshots.put( key, snapshotMetadata ); + } + snapshotMetadata.bind( artifact ); + } + } + + return Collections.emptyList(); + } + + public Artifact transformArtifact( Artifact artifact ) + { + return artifact; + } + + public Collection<? extends Metadata> finish( Collection<? extends Artifact> artifacts ) + { + return snapshots.values(); + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenAetherModule.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenAetherModule.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenAetherModule.java new file mode 100644 index 0000000..9aebb52 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenAetherModule.java @@ -0,0 +1,80 @@ +package org.apache.maven.repository.internal; + +/* + * 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.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.apache.maven.model.building.DefaultModelBuilderFactory; +import org.apache.maven.model.building.ModelBuilder; +import org.eclipse.aether.impl.AetherModule; +import org.eclipse.aether.impl.ArtifactDescriptorReader; +import org.eclipse.aether.impl.MetadataGeneratorFactory; +import org.eclipse.aether.impl.VersionRangeResolver; +import org.eclipse.aether.impl.VersionResolver; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.name.Names; + +/** + * @deprecated As of Maven Resolver 1.2, please use class {@link MavenResolverModule}. + */ +@Deprecated +public final class MavenAetherModule + extends AbstractModule +{ + + @Override + protected void configure() + { + install( new AetherModule() ); + bind( ArtifactDescriptorReader.class ) // + .to( DefaultArtifactDescriptorReader.class ).in( Singleton.class ); + bind( VersionResolver.class ) // + .to( DefaultVersionResolver.class ).in( Singleton.class ); + bind( VersionRangeResolver.class ) // + .to( DefaultVersionRangeResolver.class ).in( Singleton.class ); + bind( MetadataGeneratorFactory.class ).annotatedWith( Names.named( "snapshot" ) ) // + .to( SnapshotMetadataGeneratorFactory.class ).in( Singleton.class ); + bind( MetadataGeneratorFactory.class ).annotatedWith( Names.named( "versions" ) ) // + .to( VersionsMetadataGeneratorFactory.class ).in( Singleton.class ); + bind( ModelBuilder.class ) // + .toInstance( new DefaultModelBuilderFactory().newInstance() ); + } + + @Provides + @Singleton + Set<MetadataGeneratorFactory> provideMetadataGeneratorFactories( @Named( "snapshot" ) + MetadataGeneratorFactory snapshot, + @Named( "versions" ) + MetadataGeneratorFactory versions ) + { + Set<MetadataGeneratorFactory> factories = new HashSet<>(); + factories.add( snapshot ); + factories.add( versions ); + return Collections.unmodifiableSet( factories ); + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java new file mode 100644 index 0000000..aef44f6 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java @@ -0,0 +1,137 @@ +package org.apache.maven.repository.internal; + +/* + * 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.repository.metadata.Metadata; +import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader; +import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer; +import org.codehaus.plexus.util.ReaderFactory; +import org.codehaus.plexus.util.WriterFactory; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.metadata.AbstractMetadata; +import org.eclipse.aether.metadata.MergeableMetadata; + +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.util.Collections; +import java.util.Map; + +/** + * @author Benjamin Bentmann + */ +abstract class MavenMetadata + extends AbstractMetadata + implements MergeableMetadata +{ + + static final String MAVEN_METADATA_XML = "maven-metadata.xml"; + + private final File file; + + protected Metadata metadata; + + private boolean merged; + + protected MavenMetadata( Metadata metadata, File file ) + { + this.metadata = metadata; + this.file = file; + } + + public String getType() + { + return MAVEN_METADATA_XML; + } + + public File getFile() + { + return file; + } + + public void merge( File existing, File result ) + throws RepositoryException + { + Metadata recessive = read( existing ); + + merge( recessive ); + + write( result, metadata ); + + merged = true; + } + + public boolean isMerged() + { + return merged; + } + + protected abstract void merge( Metadata recessive ); + + static Metadata read( File metadataFile ) + throws RepositoryException + { + if ( metadataFile.length() <= 0 ) + { + return new Metadata(); + } + + try ( Reader reader = ReaderFactory.newXmlReader( metadataFile ) ) + { + return new MetadataXpp3Reader().read( reader, false ); + } + catch ( IOException e ) + { + throw new RepositoryException( "Could not read metadata " + metadataFile + ": " + e.getMessage(), e ); + } + catch ( XmlPullParserException e ) + { + throw new RepositoryException( "Could not parse metadata " + metadataFile + ": " + e.getMessage(), e ); + } + } + + private void write( File metadataFile, Metadata metadata ) + throws RepositoryException + { + metadataFile.getParentFile().mkdirs(); + try ( Writer writer = WriterFactory.newXmlWriter( metadataFile ) ) + { + new MetadataXpp3Writer().write( writer, metadata ); + } + catch ( IOException e ) + { + throw new RepositoryException( "Could not write metadata " + metadataFile + ": " + e.getMessage(), e ); + } + } + + public Map<String, String> getProperties() + { + return Collections.emptyMap(); + } + + @Override + public org.eclipse.aether.metadata.Metadata setProperties( Map<String, String> properties ) + { + return this; + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java new file mode 100644 index 0000000..8567439 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java @@ -0,0 +1,146 @@ +package org.apache.maven.repository.internal; + +/* + * 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.util.Properties; + +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.artifact.DefaultArtifactType; +import org.eclipse.aether.collection.DependencyGraphTransformer; +import org.eclipse.aether.collection.DependencyManager; +import org.eclipse.aether.collection.DependencySelector; +import org.eclipse.aether.collection.DependencyTraverser; +import org.eclipse.aether.impl.ArtifactDescriptorReader; +import org.eclipse.aether.impl.DefaultServiceLocator; +import org.eclipse.aether.impl.MetadataGeneratorFactory; +import org.eclipse.aether.impl.VersionRangeResolver; +import org.eclipse.aether.impl.VersionResolver; +import org.eclipse.aether.util.artifact.DefaultArtifactTypeRegistry; +import org.eclipse.aether.util.graph.manager.ClassicDependencyManager; +import org.eclipse.aether.util.graph.selector.AndDependencySelector; +import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector; +import org.eclipse.aether.util.graph.selector.OptionalDependencySelector; +import org.eclipse.aether.util.graph.selector.ScopeDependencySelector; +import org.eclipse.aether.util.graph.transformer.ChainedDependencyGraphTransformer; +import org.eclipse.aether.util.graph.transformer.ConflictResolver; +import org.eclipse.aether.util.graph.transformer.JavaDependencyContextRefiner; +import org.eclipse.aether.util.graph.transformer.JavaScopeDeriver; +import org.eclipse.aether.util.graph.transformer.JavaScopeSelector; +import org.eclipse.aether.util.graph.transformer.NearestVersionSelector; +import org.eclipse.aether.util.graph.transformer.SimpleOptionalitySelector; +import org.eclipse.aether.util.graph.traverser.FatArtifactTraverser; +import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy; + +/** + * A utility class to assist in setting up a Maven-like repository system. <em>Note:</em> This component is meant to + * assist those clients that employ the repository system outside of an IoC container, Maven plugins should instead + * always use regular dependency injection to acquire the repository system. + * + * @author Benjamin Bentmann + */ +public final class MavenRepositorySystemUtils +{ + + private MavenRepositorySystemUtils() + { + // hide constructor + } + + /** + * Creates a new service locator that already knows about all service implementations included in this library. To + * acquire a complete repository system, clients need to add some repository connectors for remote transfers. + * + * @return The new service locator, never {@code null}. + */ + public static DefaultServiceLocator newServiceLocator() + { + DefaultServiceLocator locator = new DefaultServiceLocator(); + locator.addService( ArtifactDescriptorReader.class, DefaultArtifactDescriptorReader.class ); + locator.addService( VersionResolver.class, DefaultVersionResolver.class ); + locator.addService( VersionRangeResolver.class, DefaultVersionRangeResolver.class ); + locator.addService( MetadataGeneratorFactory.class, SnapshotMetadataGeneratorFactory.class ); + locator.addService( MetadataGeneratorFactory.class, VersionsMetadataGeneratorFactory.class ); + return locator; + } + + /** + * Creates a new Maven-like repository system session by initializing the session with values typical for + * Maven-based resolution. In more detail, this method configures settings relevant for the processing of dependency + * graphs, most other settings remain at their generic default value. Use the various setters to further configure + * the session with authentication, mirror, proxy and other information required for your environment. + * + * @return The new repository system session, never {@code null}. + */ + public static DefaultRepositorySystemSession newSession() + { + DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(); + + DependencyTraverser depTraverser = new FatArtifactTraverser(); + session.setDependencyTraverser( depTraverser ); + + DependencyManager depManager = new ClassicDependencyManager(); + session.setDependencyManager( depManager ); + + DependencySelector depFilter = + new AndDependencySelector( new ScopeDependencySelector( "test", "provided" ), + new OptionalDependencySelector(), new ExclusionDependencySelector() ); + session.setDependencySelector( depFilter ); + + DependencyGraphTransformer transformer = + new ConflictResolver( new NearestVersionSelector(), new JavaScopeSelector(), + new SimpleOptionalitySelector(), new JavaScopeDeriver() ); + + session.setDependencyGraphTransformer( + new ChainedDependencyGraphTransformer( transformer, new JavaDependencyContextRefiner() ) ); + + DefaultArtifactTypeRegistry stereotypes = new DefaultArtifactTypeRegistry(); + stereotypes.add( new DefaultArtifactType( "pom" ) ); + stereotypes.add( new DefaultArtifactType( "maven-plugin", "jar", "", "java" ) ); + stereotypes.add( new DefaultArtifactType( "jar", "jar", "", "java" ) ); + stereotypes.add( new DefaultArtifactType( "ejb", "jar", "", "java" ) ); + stereotypes.add( new DefaultArtifactType( "ejb-client", "jar", "client", "java" ) ); + stereotypes.add( new DefaultArtifactType( "test-jar", "jar", "tests", "java" ) ); + stereotypes.add( new DefaultArtifactType( "javadoc", "jar", "javadoc", "java" ) ); + stereotypes.add( new DefaultArtifactType( "java-source", "jar", "sources", "java", false, false ) ); + stereotypes.add( new DefaultArtifactType( "war", "war", "", "java", false, true ) ); + stereotypes.add( new DefaultArtifactType( "ear", "ear", "", "java", false, true ) ); + stereotypes.add( new DefaultArtifactType( "rar", "rar", "", "java", false, true ) ); + stereotypes.add( new DefaultArtifactType( "par", "par", "", "java", false, true ) ); + session.setArtifactTypeRegistry( stereotypes ); + + session.setArtifactDescriptorPolicy( new SimpleArtifactDescriptorPolicy( true, true ) ); + + final Properties systemProperties = new Properties(); + + // MNG-5670 guard against ConcurrentModificationException + // MNG-6053 guard against key without value + Properties sysProp = System.getProperties(); + synchronized ( sysProp ) + { + systemProperties.putAll( sysProp ); + } + + session.setSystemProperties( systemProperties ); + session.setConfigProperties( systemProperties ); + + return session; + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenResolverModule.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenResolverModule.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenResolverModule.java new file mode 100644 index 0000000..070b91c --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenResolverModule.java @@ -0,0 +1,70 @@ +package org.apache.maven.repository.internal; + +/* + * 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.util.Collections; +import java.util.HashSet; +import java.util.Set; +import javax.inject.Named; +import javax.inject.Singleton; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.name.Names; +import org.apache.maven.model.building.DefaultModelBuilderFactory; +import org.apache.maven.model.building.ModelBuilder; +import org.eclipse.aether.impl.ArtifactDescriptorReader; +import org.eclipse.aether.impl.MetadataGeneratorFactory; +import org.eclipse.aether.impl.VersionRangeResolver; +import org.eclipse.aether.impl.VersionResolver; +import org.eclipse.aether.impl.guice.AetherModule; + +public final class MavenResolverModule + extends AbstractModule +{ + + @Override + protected void configure() + { + install( new AetherModule() ); + bind( ArtifactDescriptorReader.class ).to( DefaultArtifactDescriptorReader.class ).in( Singleton.class ); + bind( VersionResolver.class ).to( DefaultVersionResolver.class ).in( Singleton.class ); + bind( VersionRangeResolver.class ).to( DefaultVersionRangeResolver.class ).in( Singleton.class ); + bind( MetadataGeneratorFactory.class ).annotatedWith( Names.named( "snapshot" ) ) + .to( SnapshotMetadataGeneratorFactory.class ).in( Singleton.class ); + + bind( MetadataGeneratorFactory.class ).annotatedWith( Names.named( "versions" ) ) + .to( VersionsMetadataGeneratorFactory.class ).in( Singleton.class ); + + bind( ModelBuilder.class ).toInstance( new DefaultModelBuilderFactory().newInstance() ); + } + + @Provides + @Singleton + Set<MetadataGeneratorFactory> provideMetadataGeneratorFactories( + @Named( "snapshot" ) MetadataGeneratorFactory snapshot, + @Named( "versions" ) MetadataGeneratorFactory versions ) + { + Set<MetadataGeneratorFactory> factories = new HashSet<>( 2 ); + factories.add( snapshot ); + factories.add( versions ); + return Collections.unmodifiableSet( factories ); + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSnapshotMetadata.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSnapshotMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSnapshotMetadata.java new file mode 100644 index 0000000..e4c9a7e --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSnapshotMetadata.java @@ -0,0 +1,100 @@ +package org.apache.maven.repository.internal; + +/* + * 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.util.ArrayList; +import java.util.Collection; + +import org.apache.maven.artifact.repository.metadata.Metadata; +import org.eclipse.aether.artifact.Artifact; + +/** + * @author Hervé Boutemy + */ +abstract class MavenSnapshotMetadata + extends MavenMetadata +{ + static final String SNAPSHOT = "SNAPSHOT"; + + protected final Collection<Artifact> artifacts = new ArrayList<>(); + + protected final boolean legacyFormat; + + protected MavenSnapshotMetadata( Metadata metadata, File file, boolean legacyFormat ) + { + super( metadata, file ); + this.legacyFormat = legacyFormat; + } + + protected static Metadata createRepositoryMetadata( Artifact artifact, boolean legacyFormat ) + { + Metadata metadata = new Metadata(); + if ( !legacyFormat ) + { + metadata.setModelVersion( "1.1.0" ); + } + metadata.setGroupId( artifact.getGroupId() ); + metadata.setArtifactId( artifact.getArtifactId() ); + metadata.setVersion( artifact.getBaseVersion() ); + + return metadata; + } + + public void bind( Artifact artifact ) + { + artifacts.add( artifact ); + } + + public Object getKey() + { + return getGroupId() + ':' + getArtifactId() + ':' + getVersion(); + } + + public static Object getKey( Artifact artifact ) + { + return artifact.getGroupId() + ':' + artifact.getArtifactId() + ':' + artifact.getBaseVersion(); + } + + protected String getKey( String classifier, String extension ) + { + return classifier + ':' + extension; + } + + public String getGroupId() + { + return metadata.getGroupId(); + } + + public String getArtifactId() + { + return metadata.getArtifactId(); + } + + public String getVersion() + { + return metadata.getVersion(); + } + + public Nature getNature() + { + return Nature.SNAPSHOT; + } +} http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenWorkspaceReader.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenWorkspaceReader.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenWorkspaceReader.java new file mode 100644 index 0000000..270cf58 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenWorkspaceReader.java @@ -0,0 +1,32 @@ +package org.apache.maven.repository.internal; + +/* + * 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.model.Model; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.WorkspaceReader; + +public interface MavenWorkspaceReader + extends WorkspaceReader +{ + + Model findModel( Artifact artifact ); + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java new file mode 100644 index 0000000..c6ef3aa --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java @@ -0,0 +1,114 @@ +package org.apache.maven.repository.internal; + +/* + * 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.util.Map; + +import org.apache.commons.lang3.Validate; +import org.eclipse.aether.artifact.AbstractArtifact; +import org.eclipse.aether.artifact.Artifact; + +/** + * @author Benjamin Bentmann + */ +final class RelocatedArtifact + extends AbstractArtifact +{ + + private final Artifact artifact; + + private final String groupId; + + private final String artifactId; + + private final String version; + + public RelocatedArtifact( Artifact artifact, String groupId, String artifactId, String version ) + { + this.artifact = Validate.notNull( artifact, "artifact cannot be null" ); + // TODO Use StringUtils here + this.groupId = ( groupId != null && groupId.length() > 0 ) ? groupId : null; + this.artifactId = ( artifactId != null && artifactId.length() > 0 ) ? artifactId : null; + this.version = ( version != null && version.length() > 0 ) ? version : null; + } + + public String getGroupId() + { + if ( groupId != null ) + { + return groupId; + } + else + { + return artifact.getGroupId(); + } + } + + public String getArtifactId() + { + if ( artifactId != null ) + { + return artifactId; + } + else + { + return artifact.getArtifactId(); + } + } + + public String getVersion() + { + if ( version != null ) + { + return version; + } + else + { + return artifact.getVersion(); + } + } + + public String getClassifier() + { + return artifact.getClassifier(); + } + + public String getExtension() + { + return artifact.getExtension(); + } + + public File getFile() + { + return artifact.getFile(); + } + + public String getProperty( String key, String defaultValue ) + { + return artifact.getProperty( key, defaultValue ); + } + + public Map<String, String> getProperties() + { + return artifact.getProperties(); + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java new file mode 100644 index 0000000..1e791d8 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java @@ -0,0 +1,157 @@ +package org.apache.maven.repository.internal; + +/* + * 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.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TimeZone; + +import org.apache.maven.artifact.repository.metadata.Metadata; +import org.apache.maven.artifact.repository.metadata.Snapshot; +import org.apache.maven.artifact.repository.metadata.SnapshotVersion; +import org.apache.maven.artifact.repository.metadata.Versioning; +import org.eclipse.aether.artifact.Artifact; + +/** + * @author Benjamin Bentmann + */ +final class RemoteSnapshotMetadata + extends MavenSnapshotMetadata +{ + public static final String DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT = "yyyyMMdd.HHmmss"; + + public static final TimeZone DEFAULT_SNAPSHOT_TIME_ZONE = TimeZone.getTimeZone( "Etc/UTC" ); + + private final Map<String, SnapshotVersion> versions = new LinkedHashMap<>(); + + public RemoteSnapshotMetadata( Artifact artifact, boolean legacyFormat ) + { + super( createRepositoryMetadata( artifact, legacyFormat ), null, legacyFormat ); + } + + private RemoteSnapshotMetadata( Metadata metadata, File file, boolean legacyFormat ) + { + super( metadata, file, legacyFormat ); + } + + public MavenMetadata setFile( File file ) + { + return new RemoteSnapshotMetadata( metadata, file, legacyFormat ); + } + + public String getExpandedVersion( Artifact artifact ) + { + String key = getKey( artifact.getClassifier(), artifact.getExtension() ); + return versions.get( key ).getVersion(); + } + + @Override + protected void merge( Metadata recessive ) + { + Snapshot snapshot; + String lastUpdated; + + if ( metadata.getVersioning() == null ) + { + DateFormat utcDateFormatter = new SimpleDateFormat( DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT ); + utcDateFormatter.setCalendar( new GregorianCalendar() ); + utcDateFormatter.setTimeZone( DEFAULT_SNAPSHOT_TIME_ZONE ); + + snapshot = new Snapshot(); + snapshot.setBuildNumber( getBuildNumber( recessive ) + 1 ); + snapshot.setTimestamp( utcDateFormatter.format( new Date() ) ); + + Versioning versioning = new Versioning(); + versioning.setSnapshot( snapshot ); + versioning.setLastUpdated( snapshot.getTimestamp().replace( ".", "" ) ); + lastUpdated = versioning.getLastUpdated(); + + metadata.setVersioning( versioning ); + } + else + { + snapshot = metadata.getVersioning().getSnapshot(); + lastUpdated = metadata.getVersioning().getLastUpdated(); + } + + for ( Artifact artifact : artifacts ) + { + String version = artifact.getVersion(); + + if ( version.endsWith( SNAPSHOT ) ) + { + String qualifier = snapshot.getTimestamp() + '-' + snapshot.getBuildNumber(); + version = version.substring( 0, version.length() - SNAPSHOT.length() ) + qualifier; + } + + SnapshotVersion sv = new SnapshotVersion(); + sv.setClassifier( artifact.getClassifier() ); + sv.setExtension( artifact.getExtension() ); + sv.setVersion( version ); + sv.setUpdated( lastUpdated ); + + versions.put( getKey( sv.getClassifier(), sv.getExtension() ), sv ); + } + + artifacts.clear(); + + Versioning versioning = recessive.getVersioning(); + if ( versioning != null ) + { + for ( SnapshotVersion sv : versioning.getSnapshotVersions() ) + { + String key = getKey( sv.getClassifier(), sv.getExtension() ); + if ( !versions.containsKey( key ) ) + { + versions.put( key, sv ); + } + } + } + + if ( !legacyFormat ) + { + metadata.getVersioning().setSnapshotVersions( new ArrayList<>( versions.values() ) ); + } + } + + private static int getBuildNumber( Metadata metadata ) + { + int number = 0; + + Versioning versioning = metadata.getVersioning(); + if ( versioning != null ) + { + Snapshot snapshot = versioning.getSnapshot(); + if ( snapshot != null && snapshot.getBuildNumber() > 0 ) + { + number = snapshot.getBuildNumber(); + } + } + + return number; + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataGenerator.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataGenerator.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataGenerator.java new file mode 100644 index 0000000..8258966 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataGenerator.java @@ -0,0 +1,107 @@ +package org.apache.maven.repository.internal; + +/* + * 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.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.deployment.DeployRequest; +import org.eclipse.aether.impl.MetadataGenerator; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.util.ConfigUtils; + +/** + * @author Benjamin Bentmann + */ +class RemoteSnapshotMetadataGenerator + implements MetadataGenerator +{ + + private final Map<Object, RemoteSnapshotMetadata> snapshots; + + private final boolean legacyFormat; + + public RemoteSnapshotMetadataGenerator( RepositorySystemSession session, DeployRequest request ) + { + legacyFormat = ConfigUtils.getBoolean( session.getConfigProperties(), false, "maven.metadata.legacy" ); + + snapshots = new LinkedHashMap<>(); + + /* + * NOTE: This should be considered a quirk to support interop with Maven's legacy ArtifactDeployer which + * processes one artifact at a time and hence cannot associate the artifacts from the same project to use the + * same timestamp+buildno for the snapshot versions. Allowing the caller to pass in metadata from a previous + * deployment allows to re-establish the association between the artifacts of the same project. + */ + for ( Metadata metadata : request.getMetadata() ) + { + if ( metadata instanceof RemoteSnapshotMetadata ) + { + RemoteSnapshotMetadata snapshotMetadata = (RemoteSnapshotMetadata) metadata; + snapshots.put( snapshotMetadata.getKey(), snapshotMetadata ); + } + } + } + + public Collection<? extends Metadata> prepare( Collection<? extends Artifact> artifacts ) + { + for ( Artifact artifact : artifacts ) + { + if ( artifact.isSnapshot() ) + { + Object key = RemoteSnapshotMetadata.getKey( artifact ); + RemoteSnapshotMetadata snapshotMetadata = snapshots.get( key ); + if ( snapshotMetadata == null ) + { + snapshotMetadata = new RemoteSnapshotMetadata( artifact, legacyFormat ); + snapshots.put( key, snapshotMetadata ); + } + snapshotMetadata.bind( artifact ); + } + } + + return snapshots.values(); + } + + public Artifact transformArtifact( Artifact artifact ) + { + if ( artifact.isSnapshot() && artifact.getVersion().equals( artifact.getBaseVersion() ) ) + { + Object key = RemoteSnapshotMetadata.getKey( artifact ); + RemoteSnapshotMetadata snapshotMetadata = snapshots.get( key ); + if ( snapshotMetadata != null ) + { + artifact = artifact.setVersion( snapshotMetadata.getExpandedVersion( artifact ) ); + } + } + + return artifact; + } + + public Collection<? extends Metadata> finish( Collection<? extends Artifact> artifacts ) + { + return Collections.emptyList(); + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/SnapshotMetadataGeneratorFactory.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/SnapshotMetadataGeneratorFactory.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/SnapshotMetadataGeneratorFactory.java new file mode 100644 index 0000000..79ffaad --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/SnapshotMetadataGeneratorFactory.java @@ -0,0 +1,52 @@ +package org.apache.maven.repository.internal; + +/* + * 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.codehaus.plexus.component.annotations.Component; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.deployment.DeployRequest; +import org.eclipse.aether.impl.MetadataGenerator; +import org.eclipse.aether.impl.MetadataGeneratorFactory; +import org.eclipse.aether.installation.InstallRequest; + +/** + * @author Benjamin Bentmann + */ +@Component( role = MetadataGeneratorFactory.class, hint = "snapshot" ) +public class SnapshotMetadataGeneratorFactory + implements MetadataGeneratorFactory +{ + + public MetadataGenerator newInstance( RepositorySystemSession session, InstallRequest request ) + { + return new LocalSnapshotMetadataGenerator( session, request ); + } + + public MetadataGenerator newInstance( RepositorySystemSession session, DeployRequest request ) + { + return new RemoteSnapshotMetadataGenerator( session, request ); + } + + public float getPriority() + { + return 10; + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionRangeResultFilter.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionRangeResultFilter.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionRangeResultFilter.java new file mode 100644 index 0000000..64e1dbb --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionRangeResultFilter.java @@ -0,0 +1,45 @@ +package org.apache.maven.repository.internal; + +/* + * 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.eclipse.aether.resolution.VersionRangeResolutionException; +import org.eclipse.aether.resolution.VersionRangeResult; + +/** + * Filters the resolved versions provided by {@link VersionRangeResult#getVersions()}. + * + * @author barthel + * @since 3.4.0 + */ +public interface VersionRangeResultFilter +{ + + /** + * + * @param versionRangeResult The version range result, must not be {@code null} + * @return A filtered version range result, never {@code null} + * @throws VersionRangeResolutionException If the requested range could not be parsed. Note that an empty range does + * not raise an exception. + * @see VersionRangeResult#getVersions() + */ + VersionRangeResult filterVersionRangeResult( VersionRangeResult versionRangeResult ) + throws VersionRangeResolutionException; + +} http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadata.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadata.java new file mode 100644 index 0000000..f5e13be --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadata.java @@ -0,0 +1,133 @@ +package org.apache.maven.repository.internal; + +/* + * 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.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; + +import org.apache.maven.artifact.repository.metadata.Metadata; +import org.apache.maven.artifact.repository.metadata.Versioning; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.ArtifactProperties; + +/** + * @author Benjamin Bentmann + */ +final class VersionsMetadata + extends MavenMetadata +{ + + private final Artifact artifact; + + public VersionsMetadata( Artifact artifact ) + { + super( createRepositoryMetadata( artifact ), null ); + this.artifact = artifact; + } + + public VersionsMetadata( Artifact artifact, File file ) + { + super( createRepositoryMetadata( artifact ), file ); + this.artifact = artifact; + } + + private static Metadata createRepositoryMetadata( Artifact artifact ) + { + Metadata metadata = new Metadata(); + metadata.setGroupId( artifact.getGroupId() ); + metadata.setArtifactId( artifact.getArtifactId() ); + + Versioning versioning = new Versioning(); + versioning.addVersion( artifact.getBaseVersion() ); + if ( !artifact.isSnapshot() ) + { + versioning.setRelease( artifact.getBaseVersion() ); + } + if ( "maven-plugin".equals( artifact.getProperty( ArtifactProperties.TYPE, "" ) ) ) + { + versioning.setLatest( artifact.getBaseVersion() ); + } + + metadata.setVersioning( versioning ); + + return metadata; + } + + @Override + protected void merge( Metadata recessive ) + { + Versioning versioning = metadata.getVersioning(); + versioning.updateTimestamp(); + + if ( recessive.getVersioning() != null ) + { + if ( versioning.getLatest() == null ) + { + versioning.setLatest( recessive.getVersioning().getLatest() ); + } + if ( versioning.getRelease() == null ) + { + versioning.setRelease( recessive.getVersioning().getRelease() ); + } + + Collection<String> versions = new LinkedHashSet<>( recessive.getVersioning().getVersions() ); + versions.addAll( versioning.getVersions() ); + versioning.setVersions( new ArrayList<>( versions ) ); + } + } + + public Object getKey() + { + return getGroupId() + ':' + getArtifactId(); + } + + public static Object getKey( Artifact artifact ) + { + return artifact.getGroupId() + ':' + artifact.getArtifactId(); + } + + public MavenMetadata setFile( File file ) + { + return new VersionsMetadata( artifact, file ); + } + + public String getGroupId() + { + return artifact.getGroupId(); + } + + public String getArtifactId() + { + return artifact.getArtifactId(); + } + + public String getVersion() + { + return ""; + } + + public Nature getNature() + { + return artifact.isSnapshot() ? Nature.RELEASE_OR_SNAPSHOT : Nature.RELEASE; + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGenerator.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGenerator.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGenerator.java new file mode 100644 index 0000000..5173001 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGenerator.java @@ -0,0 +1,108 @@ +package org.apache.maven.repository.internal; + +/* + * 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.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.deployment.DeployRequest; +import org.eclipse.aether.impl.MetadataGenerator; +import org.eclipse.aether.installation.InstallRequest; +import org.eclipse.aether.metadata.Metadata; + +/** + * @author Benjamin Bentmann + */ +class VersionsMetadataGenerator + implements MetadataGenerator +{ + + private Map<Object, VersionsMetadata> versions; + + private Map<Object, VersionsMetadata> processedVersions; + + public VersionsMetadataGenerator( RepositorySystemSession session, InstallRequest request ) + { + this( session, request.getMetadata() ); + } + + public VersionsMetadataGenerator( RepositorySystemSession session, DeployRequest request ) + { + this( session, request.getMetadata() ); + } + + private VersionsMetadataGenerator( RepositorySystemSession session, Collection<? extends Metadata> metadatas ) + { + versions = new LinkedHashMap<>(); + processedVersions = new LinkedHashMap<>(); + + /* + * NOTE: This should be considered a quirk to support interop with Maven's legacy ArtifactDeployer which + * processes one artifact at a time and hence cannot associate the artifacts from the same project to use the + * same version index. Allowing the caller to pass in metadata from a previous deployment allows to re-establish + * the association between the artifacts of the same project. + */ + for ( Iterator<? extends Metadata> it = metadatas.iterator(); it.hasNext(); ) + { + Metadata metadata = it.next(); + if ( metadata instanceof VersionsMetadata ) + { + it.remove(); + VersionsMetadata versionsMetadata = (VersionsMetadata) metadata; + processedVersions.put( versionsMetadata.getKey(), versionsMetadata ); + } + } + } + + public Collection<? extends Metadata> prepare( Collection<? extends Artifact> artifacts ) + { + return Collections.emptyList(); + } + + public Artifact transformArtifact( Artifact artifact ) + { + return artifact; + } + + public Collection<? extends Metadata> finish( Collection<? extends Artifact> artifacts ) + { + for ( Artifact artifact : artifacts ) + { + Object key = VersionsMetadata.getKey( artifact ); + if ( processedVersions.get( key ) == null ) + { + VersionsMetadata versionsMetadata = versions.get( key ); + if ( versionsMetadata == null ) + { + versionsMetadata = new VersionsMetadata( artifact ); + versions.put( key, versionsMetadata ); + } + } + } + + return versions.values(); + } + +} http://git-wip-us.apache.org/repos/asf/maven/blob/58554032/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGeneratorFactory.java ---------------------------------------------------------------------- diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGeneratorFactory.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGeneratorFactory.java new file mode 100644 index 0000000..47ef360 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGeneratorFactory.java @@ -0,0 +1,52 @@ +package org.apache.maven.repository.internal; + +/* + * 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.codehaus.plexus.component.annotations.Component; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.deployment.DeployRequest; +import org.eclipse.aether.impl.MetadataGenerator; +import org.eclipse.aether.impl.MetadataGeneratorFactory; +import org.eclipse.aether.installation.InstallRequest; + +/** + * @author Benjamin Bentmann + */ +@Component( role = MetadataGeneratorFactory.class, hint = "versions" ) +public class VersionsMetadataGeneratorFactory + implements MetadataGeneratorFactory +{ + + public MetadataGenerator newInstance( RepositorySystemSession session, InstallRequest request ) + { + return new VersionsMetadataGenerator( session, request ); + } + + public MetadataGenerator newInstance( RepositorySystemSession session, DeployRequest request ) + { + return new VersionsMetadataGenerator( session, request ); + } + + public float getPriority() + { + return 5; + } + +}