From 7421d07439c5d2a180001eba0f25d5e2fbe5423c Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 21 Dec 2022 11:29:22 +0100 Subject: [PATCH 01/19] [MNG-7629] Change reactor reader to copy packaged artifacts and reuse them across builds if needed --- .../java/org/apache/maven/DefaultMaven.java | 14 +- .../java/org/apache/maven/ReactorReader.java | 183 ++++++++++++++---- 2 files changed, 154 insertions(+), 43 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java index c6658d2f3909..e1880ecae4b0 100644 --- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java +++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java @@ -242,6 +242,13 @@ private MavenExecutionResult doExecute( return addExceptionToResult(result, e); } + try { + WorkspaceReader reactorReader = container.lookup(WorkspaceReader.class, ReactorReader.HINT); + repoSession.setWorkspaceReader(reactorReader); + } catch (ComponentLookupException e) { + return addExceptionToResult(result, e); + } + eventCatapult.fire(ExecutionEvent.Type.ProjectDiscoveryStarted, session, null); Result graphResult = buildGraph(session); @@ -332,12 +339,13 @@ private MavenExecutionResult doExecute( private void setupWorkspaceReader(MavenSession session, DefaultRepositorySystemSession repoSession) throws ComponentLookupException { // Desired order of precedence for workspace readers before querying the local artifact repositories - List workspaceReaders = new ArrayList(); + List workspaceReaders = new ArrayList<>(); // 1) Reactor workspace reader - workspaceReaders.add(container.lookup(WorkspaceReader.class, ReactorReader.HINT)); + WorkspaceReader reactorReader = container.lookup(WorkspaceReader.class, ReactorReader.HINT); + workspaceReaders.add(reactorReader); // 2) Repository system session-scoped workspace reader WorkspaceReader repoWorkspaceReader = repoSession.getWorkspaceReader(); - if (repoWorkspaceReader != null) { + if (repoWorkspaceReader != null && repoWorkspaceReader != reactorReader) { workspaceReaders.add(repoWorkspaceReader); } // 3) .. n) Project-scoped workspace readers diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 7e6551f4031e..74f0a714331e 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -20,41 +20,34 @@ import javax.inject.Inject; import javax.inject.Named; +import javax.inject.Singleton; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Function; +import java.nio.file.StandardCopyOption; +import java.util.*; import java.util.function.Predicate; -import java.util.stream.Collectors; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Stream; -import org.apache.maven.artifact.ArtifactUtils; +import org.apache.maven.eventspy.EventSpy; +import org.apache.maven.execution.ExecutionEvent; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Model; import org.apache.maven.project.MavenProject; +import org.apache.maven.project.artifact.ProjectArtifact; import org.apache.maven.repository.internal.MavenWorkspaceReader; +import org.codehaus.plexus.PlexusContainer; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.repository.WorkspaceRepository; import org.eclipse.aether.util.artifact.ArtifactIdUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static java.util.function.Function.identity; -import static java.util.stream.Collectors.groupingBy; -import static java.util.stream.Collectors.toMap; - /** * An implementation of a workspace reader that knows how to search the Maven reactor for artifacts, either as packaged * jar if it has been built, or only compile output directory if packaging hasn't happened yet. @@ -72,24 +65,13 @@ class ReactorReader implements MavenWorkspaceReader { private static final Logger LOGGER = LoggerFactory.getLogger(ReactorReader.class); private final MavenSession session; - private final Map projectsByGAV; - private final Map> projectsByGA; private final WorkspaceRepository repository; - - private Function projectIntoKey = - s -> ArtifactUtils.key(s.getGroupId(), s.getArtifactId(), s.getVersion()); - - private Function projectIntoVersionlessKey = - s -> ArtifactUtils.versionlessKey(s.getGroupId(), s.getArtifactId()); + private Map>> projects; @Inject ReactorReader(MavenSession session) { this.session = session; - this.projectsByGAV = session.getAllProjects().stream().collect(toMap(projectIntoKey, identity())); - - this.projectsByGA = projectsByGAV.values().stream().collect(groupingBy(projectIntoVersionlessKey)); - - repository = new WorkspaceRepository("reactor", new HashSet<>(projectsByGAV.keySet())); + this.repository = new WorkspaceRepository("reactor", null); } // @@ -101,9 +83,7 @@ public WorkspaceRepository getRepository() { } public File findArtifact(Artifact artifact) { - String projectKey = ArtifactUtils.key(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()); - - MavenProject project = projectsByGAV.get(projectKey); + MavenProject project = getProject(artifact); if (project != null) { File file = find(project, artifact); @@ -117,18 +97,32 @@ public File findArtifact(Artifact artifact) { } public List findVersions(Artifact artifact) { - String key = ArtifactUtils.versionlessKey(artifact.getGroupId(), artifact.getArtifactId()); - - return Optional.ofNullable(projectsByGA.get(key)).orElse(Collections.emptyList()).stream() - .filter(s -> Objects.nonNull(find(s, artifact))) - .map(MavenProject::getVersion) - .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); + List versions = new ArrayList<>(); + String artifactId = artifact.getArtifactId(); + String groupId = artifact.getGroupId(); + Path repo = getProjectLocalRepo().resolve(groupId).resolve(artifactId); + String classifier = artifact.getClassifier(); + String extension = artifact.getExtension(); + Pattern pattern = Pattern.compile("\\Q" + artifactId + "\\E-(.*)" + + (classifier != null ? "-\\Q" + classifier + "\\E" : "") + + (extension != null ? "." + extension : "")); + try (Stream paths = Files.list(repo)) { + paths.forEach(p -> { + String filename = p.getFileName().toString(); + Matcher matcher = pattern.matcher(filename); + if (matcher.matches()) { + versions.add(matcher.group(1)); + } + }); + } catch (IOException e) { + // ignore + } + return Collections.unmodifiableList(versions); } @Override public Model findModel(Artifact artifact) { - String projectKey = ArtifactUtils.key(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()); - MavenProject project = projectsByGAV.get(projectKey); + MavenProject project = getProject(artifact); return project == null ? null : project.getModel(); } @@ -196,6 +190,10 @@ private File determinePreviouslyPackagedArtifactFile(MavenProject project, Artif if (artifact == null) { return null; } + File file = find(artifact); + if (file != null) { + return file; + } String fileName = String.format("%s.%s", project.getBuild().getFinalName(), artifact.getExtension()); return new File(project.getBuild().getDirectory(), fileName); @@ -324,4 +322,109 @@ private static boolean isTestArtifact(Artifact artifact) { return ("test-jar".equals(artifact.getProperty("type", ""))) || ("jar".equals(artifact.getExtension()) && "tests".equals(artifact.getClassifier())); } + + private File find(Artifact artifact) { + Path target = getArtifactPath(artifact); + return Files.isRegularFile(target) ? target.toFile() : null; + } + + public void processProject(MavenProject project) { + List artifacts = new ArrayList<>(); + + artifacts.add(RepositoryUtils.toArtifact(new ProjectArtifact(project))); + if (!"pom".equals(project.getPackaging())) { + org.apache.maven.artifact.Artifact mavenMainArtifact = project.getArtifact(); + artifacts.add(RepositoryUtils.toArtifact(mavenMainArtifact)); + } + for (org.apache.maven.artifact.Artifact attached : project.getAttachedArtifacts()) { + artifacts.add(RepositoryUtils.toArtifact(attached)); + } + + for (Artifact artifact : artifacts) { + if (artifact.getFile() != null && artifact.getFile().isFile()) { + Path target = getArtifactPath(artifact); + try { + LOGGER.debug("Copying {} to project local repository", artifact); + Files.createDirectories(target.getParent()); + Files.copy(artifact.getFile().toPath(), target, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + LOGGER.warn("Error while copying artifact to project local repository", e); + } + } + } + } + + private Path getArtifactPath(Artifact artifact) { + String groupId = artifact.getGroupId(); + String artifactId = artifact.getArtifactId(); + String version = artifact.getBaseVersion(); + String classifier = artifact.getClassifier(); + String extension = artifact.getExtension(); + Path repo = getProjectLocalRepo(); + return repo.resolve(groupId) + .resolve(artifactId) + .resolve(artifactId + + "-" + version + + (classifier != null && !classifier.isEmpty() ? "-" + classifier : "") + + (extension != null && !extension.isEmpty() ? "." + extension : "")); + } + + private Path getProjectLocalRepo() { + Path root = session.getRequest().getMultiModuleProjectDirectory().toPath(); + return root.resolve("target").resolve("project-local-repo"); + } + + private MavenProject getProject(Artifact artifact) { + return getProjects() + .getOrDefault(artifact.getGroupId(), Collections.emptyMap()) + .getOrDefault(artifact.getArtifactId(), Collections.emptyMap()) + .getOrDefault(artifact.getBaseVersion(), null); + } + + private Map>> getProjects() { + // compute the projects mapping + if (projects == null) { + List allProjects = session.getAllProjects(); + if (allProjects != null) { + Map>> map = new HashMap<>(); + allProjects.forEach(project -> map.computeIfAbsent(project.getGroupId(), k -> new HashMap<>()) + .computeIfAbsent(project.getArtifactId(), k -> new HashMap<>()) + .put(project.getVersion(), project)); + this.projects = map; + } else { + return Collections.emptyMap(); + } + } + return projects; + } + + @Named + @Singleton + @SuppressWarnings("unused") + static class ReactorReaderSpy implements EventSpy { + + final PlexusContainer container; + + @Inject + ReactorReaderSpy(PlexusContainer container) { + this.container = container; + } + + @Override + public void init(Context context) throws Exception {} + + @Override + public void onEvent(Object event) throws Exception { + if (event instanceof ExecutionEvent) { + ExecutionEvent ee = (ExecutionEvent) event; + if (ee.getType() == ExecutionEvent.Type.ForkedProjectSucceeded + || ee.getType() == ExecutionEvent.Type.ProjectSucceeded) { + container.lookup(ReactorReader.class).processProject(ee.getProject()); + } + } + } + + @Override + public void close() throws Exception {} + } } From 3809e6f97b17bb9c83a9f3ee1a43423bde92be92 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 12 Jan 2023 20:56:38 +0100 Subject: [PATCH 02/19] Fix --- .../main/java/org/apache/maven/ReactorReader.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 74f0a714331e..43df3559f962 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -135,8 +135,15 @@ private File find(MavenProject project, Artifact artifact) { return project.getFile(); } + File packagedArtifactFile = find(artifact); + if (packagedArtifactFile != null + && packagedArtifactFile.exists() + && isPackagedArtifactUpToDate(project, packagedArtifactFile, artifact)) { + return packagedArtifactFile; + } + Artifact projectArtifact = findMatchingArtifact(project, artifact); - File packagedArtifactFile = determinePreviouslyPackagedArtifactFile(project, projectArtifact); + packagedArtifactFile = determinePreviouslyPackagedArtifactFile(project, projectArtifact); if (hasArtifactFileFromPackagePhase(projectArtifact)) { return projectArtifact.getFile(); @@ -190,11 +197,6 @@ private File determinePreviouslyPackagedArtifactFile(MavenProject project, Artif if (artifact == null) { return null; } - File file = find(artifact); - if (file != null) { - return file; - } - String fileName = String.format("%s.%s", project.getBuild().getFinalName(), artifact.getExtension()); return new File(project.getBuild().getDirectory(), fileName); } From 318864d67c98e2dba908f19ea07f4c25ce49f11d Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 13 Jan 2023 11:59:25 +0100 Subject: [PATCH 03/19] Revert changes on findVersions --- .../java/org/apache/maven/ReactorReader.java | 32 ++++++------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 43df3559f962..491016c55821 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -30,8 +30,7 @@ import java.nio.file.StandardCopyOption; import java.util.*; import java.util.function.Predicate; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.maven.eventspy.EventSpy; @@ -97,27 +96,14 @@ public File findArtifact(Artifact artifact) { } public List findVersions(Artifact artifact) { - List versions = new ArrayList<>(); - String artifactId = artifact.getArtifactId(); - String groupId = artifact.getGroupId(); - Path repo = getProjectLocalRepo().resolve(groupId).resolve(artifactId); - String classifier = artifact.getClassifier(); - String extension = artifact.getExtension(); - Pattern pattern = Pattern.compile("\\Q" + artifactId + "\\E-(.*)" - + (classifier != null ? "-\\Q" + classifier + "\\E" : "") - + (extension != null ? "." + extension : "")); - try (Stream paths = Files.list(repo)) { - paths.forEach(p -> { - String filename = p.getFileName().toString(); - Matcher matcher = pattern.matcher(filename); - if (matcher.matches()) { - versions.add(matcher.group(1)); - } - }); - } catch (IOException e) { - // ignore - } - return Collections.unmodifiableList(versions); + return getProjects() + .getOrDefault(artifact.getGroupId(), Collections.emptyMap()) + .getOrDefault(artifact.getArtifactId(), Collections.emptyMap()) + .values() + .stream() + .filter(p -> Objects.nonNull(find(p, artifact))) + .map(MavenProject::getVersion) + .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); } @Override From 9a5ac833c848235ea64dadec999afa0f473b4a2b Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 13 Jan 2023 16:14:51 +0100 Subject: [PATCH 04/19] Add temporary debug statement --- .../src/main/java/org/apache/maven/ReactorReader.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 491016c55821..31d87092e1e9 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -237,6 +237,11 @@ private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedAr relativizeOutputFile(outputFile), project.getArtifactId()); } + // TODO: remove the following log + LOGGER.warn( + "{} > {}", + Files.getLastModifiedTime(outputFile), + Files.getLastModifiedTime(packagedArtifactFile.toPath())); return false; } } @@ -334,7 +339,11 @@ public void processProject(MavenProject project) { try { LOGGER.debug("Copying {} to project local repository", artifact); Files.createDirectories(target.getParent()); - Files.copy(artifact.getFile().toPath(), target, StandardCopyOption.REPLACE_EXISTING); + Files.copy( + artifact.getFile().toPath(), + target, + StandardCopyOption.REPLACE_EXISTING, + StandardCopyOption.COPY_ATTRIBUTES); } catch (IOException e) { LOGGER.warn("Error while copying artifact to project local repository", e); } From 43a3b8db8a4c421d3238c8a62ac704527bc1bf3f Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 13 Jan 2023 19:42:12 +0100 Subject: [PATCH 05/19] Do not consider old files --- maven-core/src/main/java/org/apache/maven/ReactorReader.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 31d87092e1e9..110ed1e6a550 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -204,8 +204,9 @@ private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedAr long artifactLastModified = Files.getLastModifiedTime(packagedArtifactFile.toPath()).toMillis(); + long buildStartTime = 0; if (session.getProjectBuildingRequest().getBuildStartTime() != null) { - long buildStartTime = + buildStartTime = session.getProjectBuildingRequest().getBuildStartTime().getTime(); if (artifactLastModified > buildStartTime) { return true; @@ -222,7 +223,7 @@ private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedAr long outputFileLastModified = Files.getLastModifiedTime(outputFile).toMillis(); - if (outputFileLastModified > artifactLastModified) { + if (outputFileLastModified > buildStartTime && outputFileLastModified > artifactLastModified) { File alternative = determineBuildOutputDirectoryForArtifact(project, artifact); if (alternative != null) { LOGGER.warn( From b0b73967b1bde9c852aa1e31b2a2144d4293817e Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 13 Jan 2023 21:07:52 +0100 Subject: [PATCH 06/19] Fix --- .../java/org/apache/maven/ReactorReader.java | 23 ++++--------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 110ed1e6a550..01956bcd06df 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -224,26 +224,11 @@ private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedAr long outputFileLastModified = Files.getLastModifiedTime(outputFile).toMillis(); if (outputFileLastModified > buildStartTime && outputFileLastModified > artifactLastModified) { - File alternative = determineBuildOutputDirectoryForArtifact(project, artifact); - if (alternative != null) { - LOGGER.warn( - "File '{}' is more recent than the packaged artifact for '{}'; using '{}' instead", - relativizeOutputFile(outputFile), - project.getArtifactId(), - relativizeOutputFile(alternative.toPath())); - } else { - LOGGER.warn( - "File '{}' is more recent than the packaged artifact for '{}'; " - + "cannot use the build output directory for this type of artifact", - relativizeOutputFile(outputFile), - project.getArtifactId()); - } - // TODO: remove the following log LOGGER.warn( - "{} > {}", - Files.getLastModifiedTime(outputFile), - Files.getLastModifiedTime(packagedArtifactFile.toPath())); - return false; + "File '{}' is more recent than the packaged artifact for '{}', please run a full `mvn verify` build", + relativizeOutputFile(outputFile), + project.getArtifactId()); + return true; } } From 211952c6c8075966e41ae9a4a60b0a04e021ad0f Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 13 Jan 2023 21:56:20 +0100 Subject: [PATCH 07/19] Different fix --- maven-core/src/main/java/org/apache/maven/ReactorReader.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 01956bcd06df..5126a2b24e46 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -204,9 +204,8 @@ private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedAr long artifactLastModified = Files.getLastModifiedTime(packagedArtifactFile.toPath()).toMillis(); - long buildStartTime = 0; if (session.getProjectBuildingRequest().getBuildStartTime() != null) { - buildStartTime = + long buildStartTime = session.getProjectBuildingRequest().getBuildStartTime().getTime(); if (artifactLastModified > buildStartTime) { return true; @@ -223,7 +222,7 @@ private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedAr long outputFileLastModified = Files.getLastModifiedTime(outputFile).toMillis(); - if (outputFileLastModified > buildStartTime && outputFileLastModified > artifactLastModified) { + if (outputFileLastModified > artifactLastModified) { LOGGER.warn( "File '{}' is more recent than the packaged artifact for '{}', please run a full `mvn verify` build", relativizeOutputFile(outputFile), From 109c5f63fd56f2f66de8433f548cda67ceb5831b Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 17 Jan 2023 00:11:11 +0100 Subject: [PATCH 08/19] Improvements --- .../java/org/apache/maven/ReactorReader.java | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 5126a2b24e46..b4a97be0d460 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -28,7 +28,15 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -65,6 +73,7 @@ class ReactorReader implements MavenWorkspaceReader { private final MavenSession session; private final WorkspaceRepository repository; + // groupId -> (artifactId -> (version -> project))) private Map>> projects; @Inject @@ -306,7 +315,15 @@ private File find(Artifact artifact) { return Files.isRegularFile(target) ? target.toFile() : null; } - public void processProject(MavenProject project) { + /** + * Copy packaged and attached artifacts from this project to the + * project local repository. + * This allow a subsequent build to resume while still being able + * to locate attached artifacts. + * + * @param project the project to copy artifacts + */ + private void installIntoProjectLocalRepository(MavenProject project) { List artifacts = new ArrayList<>(); artifacts.add(RepositoryUtils.toArtifact(new ProjectArtifact(project))); @@ -322,7 +339,7 @@ public void processProject(MavenProject project) { if (artifact.getFile() != null && artifact.getFile().isFile()) { Path target = getArtifactPath(artifact); try { - LOGGER.debug("Copying {} to project local repository", artifact); + LOGGER.info("Copying {} to project local repository", artifact); Files.createDirectories(target.getParent()); Files.copy( artifact.getFile().toPath(), @@ -348,7 +365,7 @@ private Path getArtifactPath(Artifact artifact) { .resolve(artifactId + "-" + version + (classifier != null && !classifier.isEmpty() ? "-" + classifier : "") - + (extension != null && !extension.isEmpty() ? "." + extension : "")); + + "." + extension); } private Path getProjectLocalRepo() { @@ -363,6 +380,7 @@ private MavenProject getProject(Artifact artifact) { .getOrDefault(artifact.getBaseVersion(), null); } + // groupId -> (artifactId -> (version -> project))) private Map>> getProjects() { // compute the projects mapping if (projects == null) { @@ -380,6 +398,11 @@ private Map>> getProjects() { return projects; } + /** + * Singleton class used to receive events by implementing the EventSpy. + * We are only interested in project success events, in which case + * we call the {@link #installIntoProjectLocalRepository(MavenProject)} method. + */ @Named @Singleton @SuppressWarnings("unused") @@ -401,7 +424,7 @@ public void onEvent(Object event) throws Exception { ExecutionEvent ee = (ExecutionEvent) event; if (ee.getType() == ExecutionEvent.Type.ForkedProjectSucceeded || ee.getType() == ExecutionEvent.Type.ProjectSucceeded) { - container.lookup(ReactorReader.class).processProject(ee.getProject()); + container.lookup(ReactorReader.class).installIntoProjectLocalRepository(ee.getProject()); } } } From 2e83fa0a90302b779ac0b0f160293fccd2525ebf Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 17 Jan 2023 11:03:57 +0100 Subject: [PATCH 09/19] Copy artifacts only after the package phase --- maven-core/src/main/java/org/apache/maven/ReactorReader.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index b4a97be0d460..c38914f5d70a 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -324,6 +324,9 @@ private File find(Artifact artifact) { * @param project the project to copy artifacts */ private void installIntoProjectLocalRepository(MavenProject project) { + if (!hasBeenPackagedDuringThisSession(project)) { + return; + } List artifacts = new ArrayList<>(); artifacts.add(RepositoryUtils.toArtifact(new ProjectArtifact(project))); From 864205738bda58eff696ef316f9d8873a9a38e2f Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 17 Jan 2023 13:25:08 +0100 Subject: [PATCH 10/19] Use the correct lifecycle --- maven-core/src/main/java/org/apache/maven/ReactorReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index c38914f5d70a..963f77f01fcc 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -233,7 +233,7 @@ private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedAr Files.getLastModifiedTime(outputFile).toMillis(); if (outputFileLastModified > artifactLastModified) { LOGGER.warn( - "File '{}' is more recent than the packaged artifact for '{}', please run a full `mvn verify` build", + "File '{}' is more recent than the packaged artifact for '{}', please run a full `mvn package` build", relativizeOutputFile(outputFile), project.getArtifactId()); return true; From 225cd807f1ce1d18072b1f22678ff94814ec540a Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Tue, 17 Jan 2023 14:16:21 +0100 Subject: [PATCH 11/19] Revert the changes on DefaultMaven, those are only required for MNG-7646 This reverts commit 7421d07439c5d2a180001eba0f25d5e2fbe5423c. # Conflicts: # maven-core/src/main/java/org/apache/maven/ReactorReader.java --- .../main/java/org/apache/maven/DefaultMaven.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java index e1880ecae4b0..c6658d2f3909 100644 --- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java +++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java @@ -242,13 +242,6 @@ private MavenExecutionResult doExecute( return addExceptionToResult(result, e); } - try { - WorkspaceReader reactorReader = container.lookup(WorkspaceReader.class, ReactorReader.HINT); - repoSession.setWorkspaceReader(reactorReader); - } catch (ComponentLookupException e) { - return addExceptionToResult(result, e); - } - eventCatapult.fire(ExecutionEvent.Type.ProjectDiscoveryStarted, session, null); Result graphResult = buildGraph(session); @@ -339,13 +332,12 @@ private MavenExecutionResult doExecute( private void setupWorkspaceReader(MavenSession session, DefaultRepositorySystemSession repoSession) throws ComponentLookupException { // Desired order of precedence for workspace readers before querying the local artifact repositories - List workspaceReaders = new ArrayList<>(); + List workspaceReaders = new ArrayList(); // 1) Reactor workspace reader - WorkspaceReader reactorReader = container.lookup(WorkspaceReader.class, ReactorReader.HINT); - workspaceReaders.add(reactorReader); + workspaceReaders.add(container.lookup(WorkspaceReader.class, ReactorReader.HINT)); // 2) Repository system session-scoped workspace reader WorkspaceReader repoWorkspaceReader = repoSession.getWorkspaceReader(); - if (repoWorkspaceReader != null && repoWorkspaceReader != reactorReader) { + if (repoWorkspaceReader != null) { workspaceReaders.add(repoWorkspaceReader); } // 3) .. n) Project-scoped workspace readers From d5b1c55ada6f342153cd9c7745a7df7765063a14 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 18 Jan 2023 08:12:34 +0100 Subject: [PATCH 12/19] Update maven-core/src/main/java/org/apache/maven/ReactorReader.java Co-authored-by: Martin Kanters --- maven-core/src/main/java/org/apache/maven/ReactorReader.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 963f77f01fcc..42585618d767 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -318,10 +318,10 @@ private File find(Artifact artifact) { /** * Copy packaged and attached artifacts from this project to the * project local repository. - * This allow a subsequent build to resume while still being able + * This allows a subsequent build to resume while still being able * to locate attached artifacts. * - * @param project the project to copy artifacts + * @param project the project to copy artifacts from */ private void installIntoProjectLocalRepository(MavenProject project) { if (!hasBeenPackagedDuringThisSession(project)) { From c8fd96e9d97ecac5520ad57aa056ba3bbe612cf7 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 18 Jan 2023 13:12:09 +0100 Subject: [PATCH 13/19] Rename a few methods --- .../java/org/apache/maven/ReactorReader.java | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 42585618d767..270df97677e0 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -33,7 +33,6 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; @@ -94,9 +93,9 @@ public File findArtifact(Artifact artifact) { MavenProject project = getProject(artifact); if (project != null) { - File file = find(project, artifact); + File file = findArtifact(project, artifact); if (file == null && project != project.getExecutionProject()) { - file = find(project.getExecutionProject(), artifact); + file = findArtifact(project.getExecutionProject(), artifact); } return file; } @@ -110,7 +109,7 @@ public List findVersions(Artifact artifact) { .getOrDefault(artifact.getArtifactId(), Collections.emptyMap()) .values() .stream() - .filter(p -> Objects.nonNull(find(p, artifact))) + .filter(p -> Objects.nonNull(findArtifact(p, artifact))) .map(MavenProject::getVersion) .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); } @@ -125,12 +124,12 @@ public Model findModel(Artifact artifact) { // Implementation // - private File find(MavenProject project, Artifact artifact) { + private File findArtifact(MavenProject project, Artifact artifact) { if ("pom".equals(artifact.getExtension())) { return project.getFile(); } - File packagedArtifactFile = find(artifact); + File packagedArtifactFile = findInProjectLocalRepository(artifact); if (packagedArtifactFile != null && packagedArtifactFile.exists() && isPackagedArtifactUpToDate(project, packagedArtifactFile, artifact)) { @@ -221,10 +220,7 @@ private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedAr } } - Iterator iterator = outputFiles.iterator(); - while (iterator.hasNext()) { - Path outputFile = iterator.next(); - + for (Path outputFile : (Iterable) outputFiles::iterator) { if (Files.isDirectory(outputFile)) { continue; } @@ -233,7 +229,8 @@ private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedAr Files.getLastModifiedTime(outputFile).toMillis(); if (outputFileLastModified > artifactLastModified) { LOGGER.warn( - "File '{}' is more recent than the packaged artifact for '{}', please run a full `mvn package` build", + "File '{}' is more recent than the packaged artifact for '{}', " + + "please run a full `mvn package` build", relativizeOutputFile(outputFile), project.getArtifactId()); return true; @@ -310,7 +307,7 @@ private static boolean isTestArtifact(Artifact artifact) { || ("jar".equals(artifact.getExtension()) && "tests".equals(artifact.getClassifier())); } - private File find(Artifact artifact) { + private File findInProjectLocalRepository(Artifact artifact) { Path target = getArtifactPath(artifact); return Files.isRegularFile(target) ? target.toFile() : null; } From 90f80fcefe1c512996066cc85760d031c4585a2c Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 18 Jan 2023 14:40:53 +0100 Subject: [PATCH 14/19] Fix cleaning the project local repository --- .../java/org/apache/maven/ReactorReader.java | 57 +++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 270df97677e0..16cfc785434a 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -24,6 +24,7 @@ import java.io.File; import java.io.IOException; +import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -36,6 +37,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -353,6 +355,31 @@ private void installIntoProjectLocalRepository(MavenProject project) { } } + private void cleanProjectLocalRepository(MavenProject project) { + try { + Path artifactPath = getProjectLocalRepo() + .resolve(project.getGroupId()) + .resolve(project.getArtifactId()) + .resolve(project.getVersion()); + if (Files.isDirectory(artifactPath)) { + try (Stream paths = Files.list(artifactPath)) { + for (Path path : (Iterable) paths::iterator) { + Files.delete(path); + } + } + try { + Files.delete(artifactPath); + Files.delete(artifactPath.getParent()); + Files.delete(artifactPath.getParent().getParent()); + } catch (DirectoryNotEmptyException e) { + // ignore + } + } + } catch (IOException e) { + LOGGER.error("Error while cleaning project local repository", e); + } + } + private Path getArtifactPath(Artifact artifact) { String groupId = artifact.getGroupId(); String artifactId = artifact.getArtifactId(); @@ -362,6 +389,7 @@ private Path getArtifactPath(Artifact artifact) { Path repo = getProjectLocalRepo(); return repo.resolve(groupId) .resolve(artifactId) + .resolve(version) .resolve(artifactId + "-" + version + (classifier != null && !classifier.isEmpty() ? "-" + classifier : "") @@ -400,8 +428,11 @@ private Map>> getProjects() { /** * Singleton class used to receive events by implementing the EventSpy. - * We are only interested in project success events, in which case + * We are interested in project success events, in which case * we call the {@link #installIntoProjectLocalRepository(MavenProject)} method. + * The mojo success event is also captured to determine if the project + * has been cleaned as the last operation, in which case, we avoid copying + * the artifacts. */ @Named @Singleton @@ -409,6 +440,7 @@ private Map>> getProjects() { static class ReactorReaderSpy implements EventSpy { final PlexusContainer container; + final Map lastLifecycle = new ConcurrentHashMap<>(); @Inject ReactorReaderSpy(PlexusContainer container) { @@ -419,12 +451,29 @@ static class ReactorReaderSpy implements EventSpy { public void init(Context context) throws Exception {} @Override + @SuppressWarnings("checkstyle:MissingSwitchDefault") public void onEvent(Object event) throws Exception { if (event instanceof ExecutionEvent) { ExecutionEvent ee = (ExecutionEvent) event; - if (ee.getType() == ExecutionEvent.Type.ForkedProjectSucceeded - || ee.getType() == ExecutionEvent.Type.ProjectSucceeded) { - container.lookup(ReactorReader.class).installIntoProjectLocalRepository(ee.getProject()); + MavenProject project = ee.getProject(); + ExecutionEvent.Type eeType = ee.getType(); + switch (ee.getType()) { + case ProjectStarted: + case ForkedProjectStarted: + lastLifecycle.remove(project.getId()); + break; + case MojoStarted: + String phase = ee.getMojoExecution().getLifecyclePhase(); + lastLifecycle.put(project.getId(), phase); + if ("clean".equals(phase)) { + container.lookup(ReactorReader.class).cleanProjectLocalRepository(project); + } + break; + case ProjectSucceeded: + case ForkedProjectSucceeded: + if (!"clean".equals(lastLifecycle.get(project.getId()))) { + container.lookup(ReactorReader.class).installIntoProjectLocalRepository(project); + } } } } From 4beeeb17c2657e1d3b89b618ff818c213e4f46d3 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 18 Jan 2023 14:51:46 +0100 Subject: [PATCH 15/19] Use streams to install artifacts in the project local repository --- .../java/org/apache/maven/ReactorReader.java | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 16cfc785434a..cbfe30e913f1 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -29,7 +29,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -326,33 +325,7 @@ private void installIntoProjectLocalRepository(MavenProject project) { if (!hasBeenPackagedDuringThisSession(project)) { return; } - List artifacts = new ArrayList<>(); - - artifacts.add(RepositoryUtils.toArtifact(new ProjectArtifact(project))); - if (!"pom".equals(project.getPackaging())) { - org.apache.maven.artifact.Artifact mavenMainArtifact = project.getArtifact(); - artifacts.add(RepositoryUtils.toArtifact(mavenMainArtifact)); - } - for (org.apache.maven.artifact.Artifact attached : project.getAttachedArtifacts()) { - artifacts.add(RepositoryUtils.toArtifact(attached)); - } - - for (Artifact artifact : artifacts) { - if (artifact.getFile() != null && artifact.getFile().isFile()) { - Path target = getArtifactPath(artifact); - try { - LOGGER.info("Copying {} to project local repository", artifact); - Files.createDirectories(target.getParent()); - Files.copy( - artifact.getFile().toPath(), - target, - StandardCopyOption.REPLACE_EXISTING, - StandardCopyOption.COPY_ATTRIBUTES); - } catch (IOException e) { - LOGGER.warn("Error while copying artifact to project local repository", e); - } - } - } + getProjectArtifacts(project).filter(this::isRegularFile).forEach(this::installIntoProjectLocalRepository); } private void cleanProjectLocalRepository(MavenProject project) { @@ -380,6 +353,40 @@ private void cleanProjectLocalRepository(MavenProject project) { } } + /** + * Retrieve a stream of the project's artifacts + */ + private Stream getProjectArtifacts(MavenProject project) { + Stream artifacts = Stream.concat( + Stream.concat( + // pom artifact + Stream.of(new ProjectArtifact(project)), + // main project artifact if not a pom + "pom".equals(project.getPackaging()) ? Stream.empty() : Stream.of(project.getArtifact())), + // attached artifacts + project.getAttachedArtifacts().stream()); + return artifacts.map(RepositoryUtils::toArtifact); + } + + private boolean isRegularFile(Artifact artifact) { + return artifact.getFile() != null && artifact.getFile().isFile(); + } + + private void installIntoProjectLocalRepository(Artifact artifact) { + Path target = getArtifactPath(artifact); + try { + LOGGER.info("Copying {} to project local repository", artifact); + Files.createDirectories(target.getParent()); + Files.copy( + artifact.getFile().toPath(), + target, + StandardCopyOption.REPLACE_EXISTING, + StandardCopyOption.COPY_ATTRIBUTES); + } catch (IOException e) { + LOGGER.error("Error while copying artifact to project local repository", e); + } + } + private Path getArtifactPath(Artifact artifact) { String groupId = artifact.getGroupId(); String artifactId = artifact.getArtifactId(); From f74c3982c6bc2d8a193bffb874dc2245729f9f8a Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 18 Jan 2023 15:08:27 +0100 Subject: [PATCH 16/19] Clean a bit --- .../java/org/apache/maven/ReactorReader.java | 60 +++++++------------ 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index cbfe30e913f1..70d77be270ed 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -37,7 +37,6 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -126,10 +125,12 @@ public Model findModel(Artifact artifact) { // private File findArtifact(MavenProject project, Artifact artifact) { + // POMs are always returned from the file system if ("pom".equals(artifact.getExtension())) { return project.getFile(); } + // First check in the project local repository File packagedArtifactFile = findInProjectLocalRepository(artifact); if (packagedArtifactFile != null && packagedArtifactFile.exists() @@ -137,18 +138,25 @@ && isPackagedArtifactUpToDate(project, packagedArtifactFile, artifact)) { return packagedArtifactFile; } + // Get the matching artifact from the project Artifact projectArtifact = findMatchingArtifact(project, artifact); - packagedArtifactFile = determinePreviouslyPackagedArtifactFile(project, projectArtifact); + if (projectArtifact != null) { + // If the artifact has been associated to a file, use it + packagedArtifactFile = projectArtifact.getFile(); + if (packagedArtifactFile != null && packagedArtifactFile.exists()) { + return packagedArtifactFile; + } - if (hasArtifactFileFromPackagePhase(projectArtifact)) { - return projectArtifact.getFile(); + // Check whether an earlier Maven run might have produced an artifact that is still on disk. + packagedArtifactFile = determinePreviouslyPackagedArtifactFile(project, projectArtifact); + if (packagedArtifactFile != null + && packagedArtifactFile.exists() + && isPackagedArtifactUpToDate(project, packagedArtifactFile, artifact)) { + return packagedArtifactFile; + } } - // Check whether an earlier Maven run might have produced an artifact that is still on disk. - else if (packagedArtifactFile != null - && packagedArtifactFile.exists() - && isPackagedArtifactUpToDate(project, packagedArtifactFile, artifact)) { - return packagedArtifactFile; - } else if (!hasBeenPackagedDuringThisSession(project)) { + + if (!hasBeenPackagedDuringThisSession(project)) { // fallback to loose class files only if artifacts haven't been packaged yet // and only for plain old jars. Not war files, not ear files, not anything else. return determineBuildOutputDirectoryForArtifact(project, artifact); @@ -196,12 +204,6 @@ private File determinePreviouslyPackagedArtifactFile(MavenProject project, Artif return new File(project.getBuild().getDirectory(), fileName); } - private boolean hasArtifactFileFromPackagePhase(Artifact projectArtifact) { - return projectArtifact != null - && projectArtifact.getFile() != null - && projectArtifact.getFile().exists(); - } - private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedArtifactFile, Artifact artifact) { Path outputDirectory = Paths.get(project.getBuild().getOutputDirectory()); if (!outputDirectory.toFile().exists()) { @@ -270,33 +272,13 @@ private Path relativizeOutputFile(final Path outputFile) { */ private Artifact findMatchingArtifact(MavenProject project, Artifact requestedArtifact) { String requestedRepositoryConflictId = ArtifactIdUtils.toVersionlessId(requestedArtifact); - - Artifact mainArtifact = RepositoryUtils.toArtifact(project.getArtifact()); - if (requestedRepositoryConflictId.equals(ArtifactIdUtils.toVersionlessId(mainArtifact))) { - return mainArtifact; - } - - return RepositoryUtils.toArtifacts(project.getAttachedArtifacts()).stream() - .filter(isRequestedArtifact(requestedArtifact)) + return getProjectArtifacts(project) + .filter(artifact -> + Objects.equals(requestedRepositoryConflictId, ArtifactIdUtils.toVersionlessId(artifact))) .findFirst() .orElse(null); } - /** - * We are taking as much as we can from the DefaultArtifact.equals(). The requested artifact has no file, so we want - * to remove that from the comparison. - * - * @param requestArtifact checked against the given artifact. - * @return true if equals, false otherwise. - */ - private Predicate isRequestedArtifact(Artifact requestArtifact) { - return s -> s.getArtifactId().equals(requestArtifact.getArtifactId()) - && s.getGroupId().equals(requestArtifact.getGroupId()) - && s.getVersion().equals(requestArtifact.getVersion()) - && s.getExtension().equals(requestArtifact.getExtension()) - && s.getClassifier().equals(requestArtifact.getClassifier()); - } - /** * Determines whether the specified artifact refers to test classes. * From 197b743db736adf419627f56456e2d4b13f2d2e7 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 18 Jan 2023 15:20:19 +0100 Subject: [PATCH 17/19] Packaged artifacts are now loaded from the project local repository --- .../java/org/apache/maven/ReactorReader.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 70d77be270ed..0d3b39661808 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -146,14 +146,6 @@ && isPackagedArtifactUpToDate(project, packagedArtifactFile, artifact)) { if (packagedArtifactFile != null && packagedArtifactFile.exists()) { return packagedArtifactFile; } - - // Check whether an earlier Maven run might have produced an artifact that is still on disk. - packagedArtifactFile = determinePreviouslyPackagedArtifactFile(project, projectArtifact); - if (packagedArtifactFile != null - && packagedArtifactFile.exists() - && isPackagedArtifactUpToDate(project, packagedArtifactFile, artifact)) { - return packagedArtifactFile; - } } if (!hasBeenPackagedDuringThisSession(project)) { @@ -196,14 +188,6 @@ private File determineBuildOutputDirectoryForArtifact(final MavenProject project return null; } - private File determinePreviouslyPackagedArtifactFile(MavenProject project, Artifact artifact) { - if (artifact == null) { - return null; - } - String fileName = String.format("%s.%s", project.getBuild().getFinalName(), artifact.getExtension()); - return new File(project.getBuild().getDirectory(), fileName); - } - private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedArtifactFile, Artifact artifact) { Path outputDirectory = Paths.get(project.getBuild().getOutputDirectory()); if (!outputDirectory.toFile().exists()) { From f23aee0ed79c38df21e50c9f8494d91bc2b3f68d Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 18 Jan 2023 17:06:40 +0100 Subject: [PATCH 18/19] Use the topmost project's build directory to resolve the project local repository --- .../main/java/org/apache/maven/ReactorReader.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 0d3b39661808..9050fac39d8a 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -74,6 +74,7 @@ class ReactorReader implements MavenWorkspaceReader { private final WorkspaceRepository repository; // groupId -> (artifactId -> (version -> project))) private Map>> projects; + private Path projectLocalRepository; @Inject ReactorReader(MavenSession session) { @@ -370,8 +371,17 @@ private Path getArtifactPath(Artifact artifact) { } private Path getProjectLocalRepo() { - Path root = session.getRequest().getMultiModuleProjectDirectory().toPath(); - return root.resolve("target").resolve("project-local-repo"); + if (projectLocalRepository == null) { + Path root = session.getRequest().getMultiModuleProjectDirectory().toPath(); + projectLocalRepository = session.getProjects().stream() + .filter(project -> root.equals(project.getBasedir().toPath())) + .findFirst() + .map(project -> project.getBuild().getDirectory()) + .map(Paths::get) + .orElseGet(() -> root.resolve("target")) + .resolve("project-local-repo"); + } + return projectLocalRepository; } private MavenProject getProject(Artifact artifact) { From 065ff3be72a96a571fb18d6a981fb7b9da3d99b1 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 19 Jan 2023 10:54:21 +0100 Subject: [PATCH 19/19] Move logic from the even spy to the ReactorReader --- .../java/org/apache/maven/ReactorReader.java | 125 ++++++++++++------ 1 file changed, 83 insertions(+), 42 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java index 9050fac39d8a..6228dd0907f6 100644 --- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java +++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java @@ -29,9 +29,11 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.util.ArrayDeque; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Deque; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -65,6 +67,8 @@ class ReactorReader implements MavenWorkspaceReader { public static final String HINT = "reactor"; + public static final String PROJECT_LOCAL_REPO = "project-local-repo"; + private static final Collection COMPILE_PHASE_TYPES = Arrays.asList("jar", "ejb-client", "war", "rar", "ejb3", "par", "sar", "wsr", "har", "app-client"); @@ -75,6 +79,8 @@ class ReactorReader implements MavenWorkspaceReader { // groupId -> (artifactId -> (version -> project))) private Map>> projects; private Path projectLocalRepository; + // projectId -> Deque + private final Map> lifecycles = new ConcurrentHashMap<>(); @Inject ReactorReader(MavenSession session) { @@ -101,6 +107,12 @@ public File findArtifact(Artifact artifact) { return file; } + // No project, but most certainly a dependency which has been built previously + File packagedArtifactFile = findInProjectLocalRepository(artifact); + if (packagedArtifactFile != null && packagedArtifactFile.exists()) { + return packagedArtifactFile; + } + return null; } @@ -135,7 +147,7 @@ private File findArtifact(MavenProject project, Artifact artifact) { File packagedArtifactFile = findInProjectLocalRepository(artifact); if (packagedArtifactFile != null && packagedArtifactFile.exists() - && isPackagedArtifactUpToDate(project, packagedArtifactFile, artifact)) { + && isPackagedArtifactUpToDate(project, packagedArtifactFile)) { return packagedArtifactFile; } @@ -189,7 +201,7 @@ private File determineBuildOutputDirectoryForArtifact(final MavenProject project return null; } - private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedArtifactFile, Artifact artifact) { + private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedArtifactFile) { Path outputDirectory = Paths.get(project.getBuild().getOutputDirectory()); if (!outputDirectory.toFile().exists()) { return true; @@ -237,9 +249,22 @@ private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedAr } private boolean hasBeenPackagedDuringThisSession(MavenProject project) { - return project.hasLifecyclePhase("package") - || project.hasLifecyclePhase("install") - || project.hasLifecyclePhase("deploy"); + boolean packaged = false; + for (String phase : getLifecycles(project)) { + switch (phase) { + case "clean": + packaged = false; + break; + case "package": + case "install": + case "deploy": + packaged = true; + break; + default: + break; + } + } + return packaged; } private Path relativizeOutputFile(final Path outputFile) { @@ -280,6 +305,40 @@ private File findInProjectLocalRepository(Artifact artifact) { return Files.isRegularFile(target) ? target.toFile() : null; } + /** + * We are interested in project success events, in which case we call + * the {@link #installIntoProjectLocalRepository(MavenProject)} method. + * The mojo started event is also captured to determine the lifecycle + * phases the project has been through. + * + * @param event the execution event + */ + private void processEvent(ExecutionEvent event) { + MavenProject project = event.getProject(); + switch (event.getType()) { + case MojoStarted: + String phase = event.getMojoExecution().getLifecyclePhase(); + Deque phases = getLifecycles(project); + if (!Objects.equals(phase, phases.peekLast())) { + phases.addLast(phase); + if ("clean".equals(phase)) { + cleanProjectLocalRepository(project); + } + } + break; + case ProjectSucceeded: + case ForkedProjectSucceeded: + installIntoProjectLocalRepository(project); + break; + default: + break; + } + } + + private Deque getLifecycles(MavenProject project) { + return lifecycles.computeIfAbsent(project.getId(), k -> new ArrayDeque<>()); + } + /** * Copy packaged and attached artifacts from this project to the * project local repository. @@ -289,10 +348,11 @@ private File findInProjectLocalRepository(Artifact artifact) { * @param project the project to copy artifacts from */ private void installIntoProjectLocalRepository(MavenProject project) { - if (!hasBeenPackagedDuringThisSession(project)) { - return; + if ("pom".equals(project.getPackaging()) + && !"clean".equals(getLifecycles(project).peekLast()) + || hasBeenPackagedDuringThisSession(project)) { + getProjectArtifacts(project).filter(this::isRegularFile).forEach(this::installIntoProjectLocalRepository); } - getProjectArtifacts(project).filter(this::isRegularFile).forEach(this::installIntoProjectLocalRepository); } private void cleanProjectLocalRepository(MavenProject project) { @@ -373,13 +433,18 @@ private Path getArtifactPath(Artifact artifact) { private Path getProjectLocalRepo() { if (projectLocalRepository == null) { Path root = session.getRequest().getMultiModuleProjectDirectory().toPath(); - projectLocalRepository = session.getProjects().stream() - .filter(project -> root.equals(project.getBasedir().toPath())) - .findFirst() - .map(project -> project.getBuild().getDirectory()) - .map(Paths::get) - .orElseGet(() -> root.resolve("target")) - .resolve("project-local-repo"); + List projects = session.getProjects(); + if (projects != null) { + projectLocalRepository = projects.stream() + .filter(project -> Objects.equals(root.toFile(), project.getBasedir())) + .findFirst() + .map(project -> project.getBuild().getDirectory()) + .map(Paths::get) + .orElseGet(() -> root.resolve("target")) + .resolve(PROJECT_LOCAL_REPO); + } else { + return root.resolve("target").resolve(PROJECT_LOCAL_REPO); + } } return projectLocalRepository; } @@ -411,11 +476,7 @@ private Map>> getProjects() { /** * Singleton class used to receive events by implementing the EventSpy. - * We are interested in project success events, in which case - * we call the {@link #installIntoProjectLocalRepository(MavenProject)} method. - * The mojo success event is also captured to determine if the project - * has been cleaned as the last operation, in which case, we avoid copying - * the artifacts. + * It simply forwards all {@code ExecutionEvent}s to the {@code ReactorReader}. */ @Named @Singleton @@ -423,7 +484,6 @@ private Map>> getProjects() { static class ReactorReaderSpy implements EventSpy { final PlexusContainer container; - final Map lastLifecycle = new ConcurrentHashMap<>(); @Inject ReactorReaderSpy(PlexusContainer container) { @@ -437,27 +497,8 @@ public void init(Context context) throws Exception {} @SuppressWarnings("checkstyle:MissingSwitchDefault") public void onEvent(Object event) throws Exception { if (event instanceof ExecutionEvent) { - ExecutionEvent ee = (ExecutionEvent) event; - MavenProject project = ee.getProject(); - ExecutionEvent.Type eeType = ee.getType(); - switch (ee.getType()) { - case ProjectStarted: - case ForkedProjectStarted: - lastLifecycle.remove(project.getId()); - break; - case MojoStarted: - String phase = ee.getMojoExecution().getLifecyclePhase(); - lastLifecycle.put(project.getId(), phase); - if ("clean".equals(phase)) { - container.lookup(ReactorReader.class).cleanProjectLocalRepository(project); - } - break; - case ProjectSucceeded: - case ForkedProjectSucceeded: - if (!"clean".equals(lastLifecycle.get(project.getId()))) { - container.lookup(ReactorReader.class).installIntoProjectLocalRepository(project); - } - } + ReactorReader reactorReader = container.lookup(ReactorReader.class); + reactorReader.processEvent((ExecutionEvent) event); } }