From bc138dc3ba1440e22c2d7a68fca3118879f831b7 Mon Sep 17 00:00:00 2001 From: Grzegorz Grzybek Date: Wed, 12 Apr 2023 13:05:59 +0200 Subject: [PATCH] [MNG-7741] Track missing files, plugin and parent pom dependencies (#1058) Add more information when using `-Dmaven.repo.local.recordReverseTree=true`. Signed-off-by: Grzegorz Grzybek --- https://issues.apache.org/jira/browse/MNG-7741 --- .../aether/ReverseTreeRepositoryListener.java | 161 ++++++++++++++---- .../ReverseTreeRepositoryListenerTest.java | 19 ++- 2 files changed, 145 insertions(+), 35 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListener.java b/maven-core/src/main/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListener.java index b75fdcd824..14f7378703 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListener.java +++ b/maven-core/src/main/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListener.java @@ -18,15 +18,19 @@ */ package org.apache.maven.internal.aether; +import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.List; import java.util.ListIterator; import java.util.Objects; +import org.apache.maven.model.InputLocation; +import org.apache.maven.model.Plugin; import org.eclipse.aether.AbstractRepositoryListener; import org.eclipse.aether.RepositoryEvent; import org.eclipse.aether.RepositorySystemSession; @@ -35,6 +39,10 @@ import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.collection.CollectStepData; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.ArtifactDescriptorRequest; +import org.eclipse.aether.resolution.ArtifactRequest; +import org.eclipse.aether.util.artifact.ArtifactIdUtils; import static java.util.Objects.requireNonNull; @@ -49,46 +57,132 @@ class ReverseTreeRepositoryListener extends AbstractRepositoryListener { public void artifactResolved(RepositoryEvent event) { requireNonNull(event, "event cannot be null"); - if (!isLocalRepositoryArtifact(event.getSession(), event.getArtifact())) { + if (!isLocalRepositoryArtifactOrMissing(event.getSession(), event.getArtifact())) { return; } - CollectStepData collectStepTrace = lookupCollectStepData(event.getTrace()); - if (collectStepTrace == null) { - return; + RequestTrace trace = event.getTrace(); + + CollectStepData collectStepTrace = null; + ArtifactRequest artifactRequest = null; + ArtifactDescriptorRequest artifactDescriptorRequest = null; + Plugin plugin = null; + + while (trace != null) { + Object data = trace.getData(); + if (data instanceof CollectStepData) { + collectStepTrace = (CollectStepData) data; + } else if (data instanceof ArtifactDescriptorRequest) { + artifactDescriptorRequest = (ArtifactDescriptorRequest) data; + } else if (data instanceof ArtifactRequest) { + artifactRequest = (ArtifactRequest) data; + } else if (data instanceof Plugin) { + plugin = (Plugin) data; + } + trace = trace.getParent(); } - Artifact resolvedArtifact = event.getArtifact(); - Artifact nodeArtifact = collectStepTrace.getNode().getArtifact(); + Path trackingDir; + boolean missing = event.getFile() == null; + if (missing) { + // missing artifact - let's track the path anyway + File dir = event.getSession().getLocalRepository().getBasedir(); + dir = new File( + dir, event.getSession().getLocalRepositoryManager().getPathForLocalArtifact(event.getArtifact())); + trackingDir = dir.getParentFile().toPath().resolve(".tracking"); + } else { + trackingDir = event.getFile().getParentFile().toPath().resolve(".tracking"); + } - if (isInScope(resolvedArtifact, nodeArtifact)) { - Dependency node = collectStepTrace.getNode(); - ArrayList trackingData = new ArrayList<>(); - trackingData.add(node + " (" + collectStepTrace.getContext() + ")"); - String indent = ""; - ListIterator iter = collectStepTrace - .getPath() - .listIterator(collectStepTrace.getPath().size()); - while (iter.hasPrevious()) { - DependencyNode curr = iter.previous(); + String baseName; + String ext = missing ? ".miss" : ".dep"; + Path trackingFile = null; + + String indent = ""; + ArrayList trackingData = new ArrayList<>(); + + if (collectStepTrace == null && plugin != null) { + ext = ".plugin"; + baseName = plugin.getGroupId() + "_" + plugin.getArtifactId() + "_" + plugin.getVersion(); + trackingFile = trackingDir.resolve(baseName + ext); + if (Files.exists(trackingFile)) { + return; + } + + if (event.getArtifact() != null) { + trackingData.add(indent + event.getArtifact()); indent += " "; - trackingData.add(indent + curr + " (" + collectStepTrace.getContext() + ")"); } - try { - Path trackingDir = - resolvedArtifact.getFile().getParentFile().toPath().resolve(".tracking"); - Files.createDirectories(trackingDir); - Path trackingFile = trackingDir.resolve(collectStepTrace + trackingData.add(indent + plugin.getGroupId() + ":" + plugin.getArtifactId() + ":" + plugin.getVersion()); + indent += " "; + + InputLocation location = plugin.getLocation(""); + if (location != null && location.getSource() != null) { + trackingData.add(indent + location.getSource().getModelId() + " (implicit)"); + indent += " "; + } + } else if (collectStepTrace != null) { + if (collectStepTrace.getPath().get(0).getArtifact() == null) { + return; + } + baseName = ArtifactIdUtils.toId(collectStepTrace.getPath().get(0).getArtifact()) + .replace(":", "_"); + trackingFile = trackingDir.resolve(baseName + ext); + if (Files.exists(trackingFile)) { + return; + } + + Artifact resolvedArtifact = event.getArtifact(); + Artifact nodeArtifact = collectStepTrace.getNode().getArtifact(); + + if (isInScope(resolvedArtifact, nodeArtifact) || "pom".equals(resolvedArtifact.getExtension())) { + Dependency node = collectStepTrace.getNode(); + trackingData.add(resolvedArtifact.toString()); + indent += " "; + trackingData.add(indent + node + " (" + collectStepTrace.getContext() + ")"); + ListIterator iter = collectStepTrace .getPath() - .get(0) - .getArtifact() - .toString() - .replace(":", "_")); - Files.write(trackingFile, trackingData, StandardCharsets.UTF_8); - } catch (IOException e) { - throw new UncheckedIOException(e); + .listIterator(collectStepTrace.getPath().size()); + while (iter.hasPrevious()) { + DependencyNode curr = iter.previous(); + indent += " "; + trackingData.add(indent + curr + " (" + collectStepTrace.getContext() + ")"); + } } } + + if (trackingFile == null) { + return; + } + try { + Files.createDirectories(trackingDir); + + trackingData.add(""); + if (!missing) { + if (event.getRepository() != null) { + trackingData.add("Repository: " + event.getRepository()); + } + } else { + List repositories = new ArrayList<>(); + if (artifactRequest != null && artifactRequest.getRepositories() != null) { + repositories.addAll(artifactRequest.getRepositories()); + } else if (artifactDescriptorRequest != null && artifactDescriptorRequest.getRepositories() != null) { + repositories.addAll(artifactDescriptorRequest.getRepositories()); + } + if (!repositories.isEmpty()) { + trackingData.add("Configured repositories:"); + for (RemoteRepository r : repositories) { + trackingData.add(" - " + r.getId() + " : " + r.getUrl()); + } + } else { + trackingData.add("No repositories configured"); + } + } + + Files.write(trackingFile, trackingData, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new UncheckedIOException(e); + } } /** @@ -99,10 +193,11 @@ class ReverseTreeRepositoryListener extends AbstractRepositoryListener { *

* Visible for testing. */ - static boolean isLocalRepositoryArtifact(RepositorySystemSession session, Artifact artifact) { - return artifact.getFile() - .getPath() - .startsWith(session.getLocalRepository().getBasedir().getPath()); + static boolean isLocalRepositoryArtifactOrMissing(RepositorySystemSession session, Artifact artifact) { + return artifact.getFile() == null + || artifact.getFile() + .getPath() + .startsWith(session.getLocalRepository().getBasedir().getPath()); } /** diff --git a/maven-core/src/test/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListenerTest.java b/maven-core/src/test/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListenerTest.java index 3088e29125..be028bba2f 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListenerTest.java +++ b/maven-core/src/test/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListenerTest.java @@ -52,13 +52,28 @@ public class ReverseTreeRepositoryListenerTest { when(nonLocalReposioryArtifact.getFile()).thenReturn(new File("something/completely/different")); assertThat( - ReverseTreeRepositoryListener.isLocalRepositoryArtifact(session, localRepositoryArtifact), + ReverseTreeRepositoryListener.isLocalRepositoryArtifactOrMissing(session, localRepositoryArtifact), equalTo(true)); assertThat( - ReverseTreeRepositoryListener.isLocalRepositoryArtifact(session, nonLocalReposioryArtifact), + ReverseTreeRepositoryListener.isLocalRepositoryArtifactOrMissing(session, nonLocalReposioryArtifact), equalTo(false)); } + @Test + public void isMissingArtifactTest() { + File baseDir = new File("local/repository"); + LocalRepository localRepository = new LocalRepository(baseDir); + RepositorySystemSession session = mock(RepositorySystemSession.class); + when(session.getLocalRepository()).thenReturn(localRepository); + + Artifact localRepositoryArtifact = mock(Artifact.class); + when(localRepositoryArtifact.getFile()).thenReturn(null); + + assertThat( + ReverseTreeRepositoryListener.isLocalRepositoryArtifactOrMissing(session, localRepositoryArtifact), + equalTo(true)); + } + @Test public void lookupCollectStepDataTest() { RequestTrace doesNotHaveIt =