diff --git a/pom.xml b/pom.xml index f883e71e..a19cafc0 100644 --- a/pom.xml +++ b/pom.xml @@ -125,6 +125,11 @@ maven-settings ${maven.version} + + org.apache.maven.resolver + maven-resolver-api + 1.0.3 + @@ -326,6 +331,11 @@ maven-settings provided + + org.apache.maven.resolver + maven-resolver-api + provided + diff --git a/src/main/java/org/simplify4u/plugins/ArtifactResolver.java b/src/main/java/org/simplify4u/plugins/ArtifactResolver.java index 2d73a50e..5d1722cf 100644 --- a/src/main/java/org/simplify4u/plugins/ArtifactResolver.java +++ b/src/main/java/org/simplify4u/plugins/ArtifactResolver.java @@ -17,26 +17,24 @@ package org.simplify4u.plugins; +import javax.inject.Inject; +import javax.inject.Named; + +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.function.Function; import java.util.stream.Collectors; -import javax.inject.Inject; -import javax.inject.Named; - -import static java.util.Collections.singleton; -import static java.util.Objects.requireNonNull; -import static org.simplify4u.plugins.utils.MavenCompilerUtils.extractAnnotationProcessors; import io.vavr.control.Try; +import org.apache.maven.RepositoryUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.ArtifactRepository; -import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; import org.apache.maven.artifact.resolver.ArtifactResolutionRequest; import org.apache.maven.artifact.resolver.ArtifactResolutionResult; import org.apache.maven.artifact.resolver.filter.ArtifactFilter; @@ -46,6 +44,14 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.apache.maven.repository.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.RequestTrace; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.repository.RepositoryPolicy; +import org.eclipse.aether.resolution.ArtifactRequest; +import org.eclipse.aether.resolution.ArtifactResolutionException; +import org.eclipse.aether.resolution.ArtifactResult; import org.simplify4u.plugins.skipfilters.CompositeSkipper; import org.simplify4u.plugins.skipfilters.ScopeSkipper; import org.simplify4u.plugins.skipfilters.SkipFilter; @@ -53,6 +59,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static java.util.Collections.singleton; +import static java.util.Objects.requireNonNull; +import static org.simplify4u.plugins.utils.MavenCompilerUtils.extractAnnotationProcessors; + /** * Artifact resolver for project dependencies, build plug-ins, and build plug-in dependencies. */ @@ -62,11 +72,15 @@ public class ArtifactResolver { private static final Logger LOG = LoggerFactory.getLogger(ArtifactResolver.class); private static final VersionRange SUREFIRE_PLUGIN_VERSION_RANGE = Try.of( - () -> VersionRange.createFromVersionSpec("(2.999999999,4)")) + () -> VersionRange.createFromVersionSpec("(2.999999999,4)")) .getOrElseThrow(e -> new IllegalStateException("BUG: Failed to create version range.", e)); private final RepositorySystem repositorySystem; + private final org.eclipse.aether.RepositorySystem aetherRepositorySystem; + + private final RepositorySystemSession repositorySession; + private final ArtifactRepository localRepository; private final List remoteRepositories; @@ -76,24 +90,27 @@ public class ArtifactResolver { *

* pgp signature *.asc is signature so there is'n signature for signature */ - private final List remoteRepositoriesIgnoreCheckSum; + private final List remoteRepositoriesIgnoreCheckSum; @Inject - ArtifactResolver(RepositorySystem repositorySystem, MavenSession session) { + ArtifactResolver(RepositorySystem repositorySystem, MavenSession session, + org.eclipse.aether.RepositorySystem aetherRepositorySystem) { this.repositorySystem = requireNonNull(repositorySystem); this.localRepository = requireNonNull(session.getLocalRepository()); this.remoteRepositories = requireNonNull(session.getCurrentProject().getRemoteArtifactRepositories()); - this.remoteRepositoriesIgnoreCheckSum = repositoriesIgnoreCheckSum(remoteRepositories); + this.remoteRepositoriesIgnoreCheckSum = + repositoriesIgnoreCheckSum(session.getCurrentProject().getRemoteProjectRepositories()); + this.aetherRepositorySystem = aetherRepositorySystem; + this.repositorySession = session.getRepositorySession(); } /** * Wrap remote repository with ignore check sum policy. * * @param repositories list to wrap - * * @return wrapped repository list */ - private List repositoriesIgnoreCheckSum(List repositories) { + private List repositoriesIgnoreCheckSum(List repositories) { return Optional.ofNullable(repositories) .orElse(Collections.emptyList()) @@ -102,22 +119,20 @@ private List repositoriesIgnoreCheckSum(List resolveProjectArtifacts(MavenProject project, Configuration config) throws MojoExecutionException { final LinkedHashSet allArtifacts = new LinkedHashSet<>(resolveArtifacts(project.getArtifacts(), config.dependencyFilter, null, config.verifyPomFiles, false)); @@ -231,26 +245,42 @@ private boolean matchSurefireVersion(Plugin plugin) { * Retrieves the PGP signature file that corresponds to the given Maven artifact. * * @param artifacts The artifacts for which a signatures are desired. - * * @return Map artifact to signature */ Map resolveSignatures(Collection artifacts) { - return artifacts.stream().collect(Collectors.toMap(Function.identity(), this::resolveSignature)); - } - private Artifact resolveSignature(Artifact artifact) { - final Artifact aAsc = repositorySystem.createArtifactWithClassifier( - artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), - artifact.getType(), artifact.getClassifier()); - aAsc.setArtifactHandler(new AscArtifactHandler(aAsc)); - - final ArtifactResolutionResult ascResult = request(aAsc, remoteRepositoriesIgnoreCheckSum); - if (!ascResult.isSuccess()) { - ascResult.getExceptions().forEach( - e -> LOG.debug("Failed to resolve asc {}: {}", aAsc.getId(), e.getMessage())); - } + List requestList = new ArrayList<>(); + artifacts.forEach(a -> { + String version = a.getVersion(); + if (version == null && a.getVersionRange() != null) { + version = a.getVersionRange().toString(); + } + DefaultArtifact artifact = new DefaultArtifact(a.getGroupId(), a.getArtifactId(), a.getClassifier(), + a.getArtifactHandler().getExtension() + ".asc", version); + + ArtifactRequest request = new ArtifactRequest(artifact, remoteRepositoriesIgnoreCheckSum, null); + request.setTrace(new RequestTrace(a)); + requestList.add(request); + }); + + Map result = new HashMap<>(); + + List artifactResults = + Try.of(() -> aetherRepositorySystem.resolveArtifacts(repositorySession, requestList)) + .recover(ArtifactResolutionException.class, ArtifactResolutionException::getResults) + .get(); + + artifactResults.forEach(aResult -> { + Artifact ascArtifact = RepositoryUtils.toArtifact(aResult.getArtifact()); + Artifact artifact = (Artifact) aResult.getRequest().getTrace().getData(); + if (!aResult.isResolved()) { + aResult.getExceptions().forEach( + e -> LOG.debug("Failed to resolve asc {}: {}", aResult.getRequest().getArtifact(), e.getMessage())); + } + result.put(artifact, ascArtifact); + }); - return aAsc; + return result; } /** @@ -264,7 +294,6 @@ private Artifact resolveSignature(Artifact artifact) { * resolved. * @param transitive Boolean indicating whether or not to resolve all dependencies in the transitive closure * of provided artifact. - * * @return Returns set of resolved artifacts. */ private Set resolveArtifacts(Iterable artifacts, SkipFilter artifactFilter, @@ -372,10 +401,15 @@ private ArtifactResolutionResult request(Artifact artifact, List new ArtifactResolver(null, null)) + assertThatCode(() -> new ArtifactResolver(null, null, null)) .isExactlyInstanceOf(NullPointerException.class); - assertThatCode(() -> new ArtifactResolver(null, session)) + assertThatCode(() -> new ArtifactResolver(null, session, null)) .isExactlyInstanceOf(NullPointerException.class); doThrow(new NullPointerException()).when(session).getLocalRepository(); - assertThatCode(() -> new ArtifactResolver(repositorySystem, session)) + assertThatCode(() -> new ArtifactResolver(repositorySystem, session, null)) .isExactlyInstanceOf(NullPointerException.class); doReturn(localRepository).when(session).getLocalRepository(); doThrow(new NullPointerException()).when(session).getCurrentProject(); - assertThatCode(() -> new ArtifactResolver(repositorySystem, session)) + assertThatCode(() -> new ArtifactResolver(repositorySystem, session, null)) .isExactlyInstanceOf(NullPointerException.class); } @@ -190,26 +199,27 @@ void testResolveSignaturesEmpty() throws MojoExecutionException { } @Test - void testResolveSignaturesResolved() throws MojoExecutionException { + void testResolveSignaturesResolved() throws ArtifactResolutionException { // given - when(repositorySystem.resolve(isA(ArtifactResolutionRequest.class))).thenAnswer((Answer) invocation -> { - Artifact artifact = invocation.getArgument(0).getArtifact(); - artifact.setResolved(true); - return new ArtifactResolutionResult(); - }); - - when(repositorySystem.createArtifactWithClassifier(eq("g"), eq("a"), eq("1.0"), eq("jar"), isNull())) - .thenReturn(new DefaultArtifact("g", "a", "1.0", "compile", "mock-signature-artifact", null, new DefaultArtifactHandler())); - DefaultArtifact artifact = new DefaultArtifact("g", "a", "1.0", "compile", "jar", null, new DefaultArtifactHandler()); + when(aetherRepositorySystem.resolveArtifacts(any(), any())).thenAnswer((Answer>) invocation -> { + Collection artifactsRequests = invocation.>getArgument(1); + assertThat(artifactsRequests).hasSize(1); + ArtifactRequest artifactRequest = artifactsRequests.iterator().next(); + ArtifactResult artifactResult = new ArtifactResult(artifactRequest); + org.eclipse.aether.artifact.Artifact resolvedArtifact = RepositoryUtils.toArtifact(artifact); + resolvedArtifact = resolvedArtifact.setFile(new File(".")); + artifactResult.setArtifact(resolvedArtifact); + return Collections.singletonList(artifactResult); + }); + // then Map resolved = resolver.resolveSignatures(singleton(artifact)); // then - verify(repositorySystem, times(1)).createArtifactWithClassifier( - eq("g"), eq("a"), eq("1.0"), eq("jar"), isNull()); + verify(aetherRepositorySystem).resolveArtifacts(any(), any()); assertThat(resolved) .hasSize(1) @@ -220,32 +230,43 @@ void testResolveSignaturesResolved() throws MojoExecutionException { assertThat(value.getArtifactId()).isEqualTo("a"); assertThat(value.getVersion()).isEqualTo("1.0"); assertThat(value.getClassifier()).isNull(); - assertThat(value.getType()).isEqualTo("mock-signature-artifact"); + assertThat(value.getType()).isEqualTo("jar"); + assertThat(value.isResolved()).isTrue(); } @Test - void testResolveSignaturesUnresolvedNone() throws MojoExecutionException { + void testResolveSignaturesUnresolvedNone() throws ArtifactResolutionException { // given - when(repositorySystem.resolve(isA(ArtifactResolutionRequest.class))).thenAnswer((Answer) invocation -> { - Artifact artifact = invocation.getArgument(0).getArtifact(); - artifact.setResolved(false); - ArtifactResolutionResult result = new ArtifactResolutionResult(); - result.setUnresolvedArtifacts(singletonList(artifact)); - return result; - }); + DefaultArtifact artifact = new DefaultArtifact("g", "a", "1.0", "compile", "jar", null, new DefaultArtifactHandler()); - when(repositorySystem.createArtifactWithClassifier(eq("g"), eq("a"), eq("1.0"), eq("jar"), isNull())) - .thenReturn(new DefaultArtifact("g", "a", "1.0", "compile", "mock-signature-artifact", null, new DefaultArtifactHandler())); + when(aetherRepositorySystem.resolveArtifacts(any(), any())).thenAnswer((Answer>) invocation -> { + Collection artifactsRequests = invocation.>getArgument(1); + assertThat(artifactsRequests).hasSize(1); + ArtifactRequest artifactRequest = artifactsRequests.iterator().next(); + ArtifactResult artifactResult = new ArtifactResult(artifactRequest); + org.eclipse.aether.artifact.Artifact resolvedArtifact = RepositoryUtils.toArtifact(artifact); + artifactResult.setArtifact(resolvedArtifact); + throw new ArtifactResolutionException(Collections.singletonList(artifactResult)); + }); - DefaultArtifact artifact = new DefaultArtifact("g", "a", "1.0", "compile", "jar", null, new DefaultArtifactHandler()); // when Map resolved = resolver.resolveSignatures(singleton(artifact)); // then - verify(repositorySystem, times(1)).createArtifactWithClassifier( - eq("g"), eq("a"), eq("1.0"), eq("jar"), isNull()); - assertThat(resolved).hasSize(1); + verify(aetherRepositorySystem).resolveArtifacts(any(), any()); + + assertThat(resolved) + .hasSize(1) + .containsOnlyKeys(artifact); + + Artifact value = resolved.entrySet().iterator().next().getValue(); + assertThat(value.getGroupId()).isEqualTo("g"); + assertThat(value.getArtifactId()).isEqualTo("a"); + assertThat(value.getVersion()).isEqualTo("1.0"); + assertThat(value.getClassifier()).isNull(); + assertThat(value.getType()).isEqualTo("jar"); + assertThat(value.isResolved()).isFalse(); } @ParameterizedTest