Skip to content

Commit

Permalink
Separate Update Implementation into specific components
Browse files Browse the repository at this point in the history
Currently everything is implemented in the mojo that might mixes up
different concerns.

This now separates the update login into dedicated components so they
are easier to understand and use.
  • Loading branch information
laeubi committed Aug 13, 2024
1 parent 82bc6a6 commit 9f6d927
Show file tree
Hide file tree
Showing 6 changed files with 350 additions and 242 deletions.
9 changes: 7 additions & 2 deletions tycho-extras/tycho-version-bump-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
- Sonatype Inc. - initial API and implementation
-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

Expand Down Expand Up @@ -41,7 +42,7 @@
<artifactId>tycho-core</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
Expand All @@ -52,6 +53,10 @@
<goalPrefix>tycho-version-bump</goalPrefix>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.sisu</groupId>
<artifactId>sisu-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,23 @@
import org.eclipse.tycho.TargetEnvironment;
import org.eclipse.tycho.core.resolver.P2Resolver;
import org.eclipse.tycho.core.resolver.P2ResolverFactory;
import org.eclipse.tycho.p2.target.facade.TargetPlatformConfigurationStub;

public abstract class AbstractUpdateMojo extends AbstractMojo {

@Component
private Logger logger;

@Parameter(defaultValue = "JavaSE-1.7")
protected String executionEnvironment;

protected P2Resolver p2;

protected TargetPlatformConfigurationStub resolutionContext;
@Parameter(defaultValue = "JavaSE-17")
private String executionEnvironment;

@Parameter(property = "project")
protected MavenProject project;
private MavenProject project;

@Component
P2ResolverFactory factory;
private P2ResolverFactory factory;

public void execute() throws MojoExecutionException, MojoFailureException {
try {
createResolver();
doUpdate();
} catch (Exception e) {
if (e instanceof MojoFailureException mfe) {
Expand All @@ -65,9 +59,17 @@ public void execute() throws MojoExecutionException, MojoFailureException {

protected abstract void doUpdate() throws Exception;

private void createResolver() {
p2 = factory.createResolver(Collections.singletonList(TargetEnvironment.getRunningEnvironment()));
resolutionContext = new TargetPlatformConfigurationStub();
P2Resolver createResolver() {
return factory.createResolver(Collections.singletonList(TargetEnvironment.getRunningEnvironment()));

}

String getExecutionEnvironment() {
return executionEnvironment;
}

MavenProject getProject() {
return project;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
/*******************************************************************************
* Copyright (c) 2010, 2022 Sonatype Inc. and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor Fedorenko - initial API and implementation
* Christoph Läubrich - Issue #502 - TargetDefinitionUtil / UpdateTargetMojo should not be allowed to modify the internal state of the target
*******************************************************************************/
package org.eclipse.tycho.versionbump;

import static java.util.stream.Collectors.toList;

import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.inject.Named;

import org.apache.maven.plugin.MojoFailureException;
import org.eclipse.tycho.TargetEnvironment;
import org.eclipse.tycho.core.resolver.P2ResolutionResult;
import org.eclipse.tycho.p2.target.facade.TargetPlatformConfigurationStub;
import org.eclipse.tycho.p2resolver.TargetDefinitionVariableResolver;
import org.eclipse.tycho.targetplatform.TargetDefinition;
import org.eclipse.tycho.targetplatform.TargetDefinition.FollowRepositoryReferences;
import org.eclipse.tycho.targetplatform.TargetDefinition.IncludeMode;
import org.eclipse.tycho.targetplatform.TargetDefinition.InstallableUnitLocation;
import org.eclipse.tycho.targetplatform.TargetDefinition.Unit;
import org.eclipse.tycho.targetplatform.TargetDefinitionFile;

import de.pdark.decentxml.Element;

@Named
public class InstallableUnitLocationUpdater {

@Inject
private TargetDefinitionVariableResolver varResolver;

public boolean update(Element iuLocation, UpdateTargetMojo context) throws MojoFailureException {
TargetDefinitionFile parsedTarget = TargetDefinitionFile.read(context.getFileToBeUpdated());
TargetPlatformConfigurationStub resolutionContext = new TargetPlatformConfigurationStub();
resolutionContext.setEnvironments(Collections.singletonList(TargetEnvironment.getRunningEnvironment()));
resolutionContext.addTargetDefinition(new LatestVersionTarget(parsedTarget, varResolver));
resolutionContext.setIgnoreLocalArtifacts(true);
P2ResolutionResult result = context.createResolver().getTargetPlatformAsResolutionResult(resolutionContext,
context.getExecutionEnvironment());

Map<String, String> ius = new HashMap<>();
for (P2ResolutionResult.Entry entry : result.getArtifacts()) {
ius.put(entry.getId(), entry.getVersion());
}
boolean updated = false;
List<Element> children = iuLocation.getChildren("unit");
for (Element unit : children) {
String id = unit.getAttributeValue("id");
String version = ius.get(id);
if (version != null) {
String currentVersion = unit.getAttributeValue("version");
if (version.equals(currentVersion)) {
context.getLog().debug("unit '" + id + "' is already up-to date");
} else {
updated = true;
context.getLog()
.info("Update version of unit '" + id + "' from " + currentVersion + " > " + version);
unit.setAttribute("version", version);
}
} else {
context.getLog().warn(
"Resolution result does not contain root installable unit '" + id + "' update is skipped!");
}
}
return updated;
}

private static final class LatestVersionTarget implements TargetDefinition {

private TargetDefinitionFile delegate;
private TargetDefinitionVariableResolver varResolver;

public LatestVersionTarget(TargetDefinitionFile delegate, TargetDefinitionVariableResolver varResolver) {
this.delegate = delegate;
this.varResolver = varResolver;
}

@Override
public List<? extends Location> getLocations() {
return delegate.getLocations().stream().map(location -> {
if (location instanceof InstallableUnitLocation iuLocation) {
return new LatestVersionLocation(iuLocation, varResolver);
} else {
return location;
}
}).toList();
}

@Override
public boolean hasIncludedBundles() {
return delegate.hasIncludedBundles();
}

@Override
public String getOrigin() {
return delegate.getOrigin();
}

@Override
public String getTargetEE() {
return delegate.getTargetEE();
}

}

private static final class LatestVersionLocation implements InstallableUnitLocation {

private InstallableUnitLocation delegate;
private TargetDefinitionVariableResolver varResolver;

public LatestVersionLocation(InstallableUnitLocation delegate, TargetDefinitionVariableResolver varResolver) {
this.delegate = delegate;
this.varResolver = varResolver;
}

@Override
public List<? extends TargetDefinition.Repository> getRepositories() {
return delegate.getRepositories().stream().map(repo -> {
URI resolvedLocation = URI.create(varResolver.resolve(repo.getLocation()));
return new ResolvedRepository(repo.getId(), resolvedLocation.toString());
}).collect(toList());
}

@Override
public List<? extends TargetDefinition.Unit> getUnits() {
return delegate.getUnits().stream().map(LatestVersionUnit::new).toList();
}

@Override
public IncludeMode getIncludeMode() {
return delegate.getIncludeMode();
}

@Override
public boolean includeAllEnvironments() {
return delegate.includeAllEnvironments();
}

@Override
public boolean includeSource() {
return delegate.includeSource();
}

@Override
public boolean includeConfigurePhase() {
return delegate.includeConfigurePhase();
}

@Override
public FollowRepositoryReferences followRepositoryReferences() {
return delegate.followRepositoryReferences();
}

}

private static final class LatestVersionUnit implements TargetDefinition.Unit {

private Unit delegate;

public LatestVersionUnit(TargetDefinition.Unit delegate) {
this.delegate = delegate;
}

@Override
public String getId() {
return delegate.getId();
}

@Override
public String getVersion() {
return "0.0.0";
}

}

private static final class ResolvedRepository implements TargetDefinition.Repository {

private final String id;
private final String uri;

ResolvedRepository(String id, String uri) {
this.id = id;
this.uri = uri;
}

@Override
public String getId() {
return id;
}

@Override
public String getLocation() {
return uri;
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*******************************************************************************
* Copyright (c) 2023 Christoph Läubrich and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.versionbump;

import javax.inject.Inject;
import javax.inject.Named;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.Dependency;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.VersionRangeResolutionException;
import org.eclipse.tycho.core.maven.MavenDependenciesResolver;

import de.pdark.decentxml.Element;

@Named
public class MavenLocationUpdater {

@Inject
private MavenDependenciesResolver resolver;

public boolean update(Element mavenLocation, UpdateTargetMojo context)
throws VersionRangeResolutionException, ArtifactResolutionException {
boolean changed = false;
Element dependencies = mavenLocation.getChild("dependencies");
if (dependencies != null) {
for (Element dependency : dependencies.getChildren("dependency")) {
Dependency mavenDependency = getDependency(dependency);
String oldVersion = mavenDependency.getVersion();
if (!context.isUpdateMajorVersion()) {
try {
String[] strings = oldVersion.split("\\.");
mavenDependency.setVersion("[," + (Integer.parseInt(strings[0]) + 1) + "-alpha)");
} catch (RuntimeException e) {
context.getLog().warn("Can't check for update of " + mavenDependency
+ " because the version format is not parseable: " + e);
continue;
}
}
Artifact newArtifactVersion = resolver.resolveHighestVersion(context.getProject(),
context.getMavenSession(), mavenDependency);
if (newArtifactVersion == null) {
continue;
}
String newVersion = newArtifactVersion.getVersion();
if (newVersion.equals(oldVersion)) {
context.getLog().debug(mavenDependency + " is already up-to date");
} else {
changed = true;
UpdateTargetMojo.setElementValue("version", newVersion, dependency);
context.getLog().info("update " + mavenDependency + " to version " + newVersion);
}
}
}
return changed;
}

private static Dependency getDependency(Element dependency) {
Dependency mavenDependency = new Dependency();
mavenDependency.setGroupId(UpdateTargetMojo.getElementValue("groupId", dependency));
mavenDependency.setArtifactId(UpdateTargetMojo.getElementValue("artifactId", dependency));
mavenDependency.setVersion(UpdateTargetMojo.getElementValue("version", dependency));
mavenDependency.setType(UpdateTargetMojo.getElementValue("type", dependency));
mavenDependency.setClassifier(UpdateTargetMojo.getElementValue("classifier", dependency));
return mavenDependency;
}

}
Loading

0 comments on commit 9f6d927

Please sign in to comment.