Skip to content

Commit

Permalink
Update retrieval (which is immutable) is split from update execution.…
Browse files Browse the repository at this point in the history
… Made updates parallel.
  • Loading branch information
andrzejj0 committed Jan 3, 2025
1 parent 203124d commit 5847081
Showing 1 changed file with 139 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@
import javax.xml.stream.XMLStreamException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Stream;

import org.apache.maven.artifact.Artifact;
Expand All @@ -31,6 +36,7 @@
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.wagon.Wagon;
import org.codehaus.mojo.versions.api.ArtifactVersions;
import org.codehaus.mojo.versions.api.PomHelper;
Expand All @@ -52,6 +58,13 @@
*/
public abstract class UseLatestVersionsMojoBase extends AbstractVersionsDependencyUpdaterMojo {

/**
* Number of executor threads for update retrieval.
* @since 2.19.0
*/
@Parameter(property = "numThreads", defaultValue = "5")
private int numThreads = 5;

protected abstract boolean getAllowMajorUpdates();

protected abstract boolean getAllowMinorUpdates();
Expand All @@ -66,6 +79,8 @@ public abstract class UseLatestVersionsMojoBase extends AbstractVersionsDependen

protected abstract Optional<ArtifactVersion> versionProducer(Stream<ArtifactVersion> stream);

private final ExecutorService executor = Executors.newFixedThreadPool(numThreads);

public UseLatestVersionsMojoBase(
ArtifactHandlerManager artifactHandlerManager,
RepositorySystem repositorySystem,
Expand All @@ -74,6 +89,64 @@ public UseLatestVersionsMojoBase(
super(artifactHandlerManager, repositorySystem, wagonMap, changeRecorders);
}

/**
* Represents a version change of an artifact
*/
private abstract static class ArtifactVersionChange {
private final DependencyChangeRecord.ChangeKind changeKind;
private final String newVersion;

/**
* Creates a new instance
* @param changeKind change kind
* @param newVersion new version
*/
ArtifactVersionChange(DependencyChangeRecord.ChangeKind changeKind, String newVersion) {
this.changeKind = changeKind;
this.newVersion = newVersion;
}

/**
* @return change kind
*/
DependencyChangeRecord.ChangeKind getChangeKind() {
return changeKind;
}

/**
* @return new version
*/
String getNewVersion() {
return newVersion;
}
}

/**
* Represents a version change of a dependency
*/
private static final class DependencyVersionChange extends ArtifactVersionChange {
private final Dependency dependency;

/**
* Constructs a new instance
* @param changeKind change kind
* @param dependency {@code Dependency} instance
* @param newVersion new version
*/
DependencyVersionChange(
DependencyChangeRecord.ChangeKind changeKind, Dependency dependency, String newVersion) {
super(changeKind, newVersion);
this.dependency = dependency;
}

/**
* @return {@code Dependency} instance
*/
Dependency getDependency() {
return dependency;
}
}

/**
* @param pom the pom to update.
* @throws org.apache.maven.plugin.MojoExecutionException when things go wrong
Expand All @@ -89,74 +162,96 @@ protected void update(MutableXMLStreamReader pom)

Optional<Segment> unchangedSegment = SegmentUtils.determineUnchangedSegment(
getAllowMajorUpdates(), getAllowMinorUpdates(), getAllowIncrementalUpdates(), getLog());
ConcurrentLinkedQueue<DependencyVersionChange> versionChanges = new ConcurrentLinkedQueue<>();
Collection<CompletableFuture<Void>> versionChangeFutures = new ArrayList<>();
try {
if (getProcessDependencyManagement()) {
DependencyManagement dependencyManagement =
PomHelper.getRawModel(getProject()).getDependencyManagement();
if (dependencyManagement != null) {
update(
pom,
versionChangeFutures.add(getUpdates(
versionChanges,
dependencyManagement.getDependencies(),
DependencyChangeRecord.ChangeKind.DEPENDENCY_MANAGEMENT,
unchangedSegment);
unchangedSegment));
}
}
if (getProject().getDependencies() != null && getProcessDependencies()) {
update(
pom,
versionChangeFutures.add(getUpdates(
versionChanges,
getProject().getDependencies(),
DependencyChangeRecord.ChangeKind.DEPENDENCY,
unchangedSegment);
unchangedSegment));
}
if (getProject().getParent() != null && getProcessParent()) {
update(
pom,
versionChangeFutures.add(getUpdates(
versionChanges,
singletonList(getParentDependency()),
DependencyChangeRecord.ChangeKind.PARENT,
unchangedSegment);
unchangedSegment));
}

CompletableFuture.allOf(versionChangeFutures.toArray(new CompletableFuture[0]))
.join();
for (DependencyVersionChange change : versionChanges) {
updateDependencyVersion(pom, change.getDependency(), change.getNewVersion(), change.getChangeKind());
}
} catch (IOException e) {
throw new MojoExecutionException(e.getMessage(), e);
} catch (IllegalStateException e) {
if (e.getCause() instanceof MojoExecutionException) {
throw (MojoExecutionException) e.getCause();
}
if (e.getCause() instanceof VersionRetrievalException) {
throw (VersionRetrievalException) e.getCause();
}
throw e;
}
}

protected final void update(
MutableXMLStreamReader pom,
private CompletableFuture<Void> getUpdates(
ConcurrentLinkedQueue<DependencyVersionChange> updates,
Collection<Dependency> dependencies,
DependencyChangeRecord.ChangeKind changeKind,
Optional<Segment> unchangedSegment)
throws XMLStreamException, MojoExecutionException, VersionRetrievalException {
for (Dependency dep : dependencies) {
if (!updateFilter(dep)) {
continue;
} else if (getExcludeReactor() && isProducedByReactor(dep)) {
getLog().info("Ignoring reactor dependency: " + toString(dep));
continue;
} else if (isHandledByProperty(dep)) {
getLog().debug("Ignoring dependency with property as version: " + toString(dep));
continue;
}
Artifact artifact = toArtifact(dep);
if (!isIncluded(artifact)) {
continue;
}
if (getLog().isDebugEnabled()) {
ArtifactVersion selectedVersion = DefaultArtifactVersionCache.of(dep.getVersion());
getLog().debug("Selected version:" + selectedVersion);
getLog().debug("Looking for newer versions of " + toString(dep));
}
Optional<Segment> unchangedSegment) {
return CompletableFuture.allOf(dependencies.stream()
.map(dep -> CompletableFuture.runAsync(
() -> {
if (!updateFilter(dep)) {
return;
} else if (getExcludeReactor() && isProducedByReactor(dep)) {
getLog().info("Ignoring reactor dependency: " + toString(dep));
} else if (isHandledByProperty(dep)) {
getLog().debug("Ignoring dependency with property as version: " + toString(dep));
} else {
try {
Artifact artifact = toArtifact(dep);
if (!isIncluded(artifact)) {
return;
} else if (getLog().isDebugEnabled()) {
ArtifactVersion selectedVersion =
DefaultArtifactVersionCache.of(dep.getVersion());
getLog().debug("Selected version:" + selectedVersion);
getLog().debug("Looking for newer versions of " + toString(dep));
}

ArtifactVersions versions = getHelper().lookupArtifactVersions(artifact, false);
try {
Optional<ArtifactVersion> newestVer = versionProducer(Arrays.stream(versions.getNewerVersions(
dep.getVersion(), unchangedSegment, getAllowSnapshots(), getAllowDowngrade()))
.filter(this::artifactVersionsFilter));
if (newestVer.isPresent()) {
updateDependencyVersion(pom, dep, newestVer.get().toString(), changeKind);
}
} catch (InvalidSegmentException e) {
getLog().warn("Ignoring " + this.toString(dep) + " as the version number is too short");
}
}
ArtifactVersions versions = getHelper().lookupArtifactVersions(artifact, false);
versionProducer(Arrays.stream(versions.getNewerVersions(
dep.getVersion(),
unchangedSegment,
getAllowSnapshots(),
getAllowDowngrade()))
.filter(this::artifactVersionsFilter))
.ifPresent(ver -> updates.add(
new DependencyVersionChange(changeKind, dep, ver.toString())));
} catch (VersionRetrievalException
| InvalidSegmentException
| MojoExecutionException e) {
throw new IllegalStateException(e);
}
}
},
executor))
.toArray(CompletableFuture[]::new));
}
}

0 comments on commit 5847081

Please sign in to comment.