Skip to content

Commit

Permalink
Add support for setting an API baseline in EclipseBuildMojos
Browse files Browse the repository at this point in the history
Currently only setting a target platform is supported, this now also
adds support for setting the API Baseline if the projects has api nature
enabled.
  • Loading branch information
laeubi committed Jan 23, 2025
1 parent a3868f8 commit 02b7115
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ private MavenRepositoryLocation getRepository() {
private Collection<Path> getBaselineBundles() throws MojoFailureException {
long start = System.currentTimeMillis();
try {
Collection<TargetEnvironment> targetEnvironments = getBaselineEnvironments();
Collection<TargetEnvironment> targetEnvironments = projectManager.getBaselineEnvironments(project);
Optional<ArtifactKey> artifactKey = projectManager.getArtifactKey(project);
getLog().info("Resolve API baseline for " + project.getId() + " with "
+ targetEnvironments.stream().map(String::valueOf).collect(Collectors.joining(", ")));
Expand All @@ -427,25 +427,6 @@ private Collection<Path> getBaselineBundles() throws MojoFailureException {
}
}

/**
* This method selected the a target environment best suited for the current
* baseline, if it is a valid choice the running target is used (e.g. linux on
* linux host, windows on windows hosts and so on), if such environment is not
* available it is using the configured ones form the project as is.
*
* @return the chosen {@link TargetEnvironment}s
*/
private Collection<TargetEnvironment> getBaselineEnvironments() {
Collection<TargetEnvironment> targetEnvironments = projectManager.getTargetEnvironments(project);
TargetEnvironment runningEnvironment = TargetEnvironment.getRunningEnvironment();
for (TargetEnvironment targetEnvironment : targetEnvironments) {
if (targetEnvironment.equals(runningEnvironment)) {
return List.of(targetEnvironment);
}
}
return targetEnvironments;
}

private String time(long start) {
long ms = System.currentTimeMillis() - start;
if (ms < 1000) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,16 @@
package org.eclipse.tycho.apitools;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.ArtifactType;
import org.eclipse.tycho.IllegalArtifactReferenceException;
import org.eclipse.tycho.MavenRepositoryLocation;
import org.eclipse.tycho.TargetEnvironment;
import org.eclipse.tycho.TargetPlatform;
import org.eclipse.tycho.core.resolver.P2ResolutionResult;
import org.eclipse.tycho.core.resolver.P2ResolutionResult.Entry;
import org.eclipse.tycho.core.resolver.P2Resolver;
import org.eclipse.tycho.osgi.framework.Bundles;
import org.eclipse.tycho.osgi.framework.EclipseApplication;
import org.eclipse.tycho.osgi.framework.EclipseApplicationFactory;
Expand All @@ -56,19 +49,7 @@ public class ApiApplicationResolver {
public Collection<Path> getApiBaselineBundles(Collection<MavenRepositoryLocation> baselineRepoLocations,
ArtifactKey artifactKey, Collection<TargetEnvironment> environment)
throws IllegalArtifactReferenceException {
P2Resolver resolver = applicationFactory.createResolver(environment);
resolver.addDependency(ArtifactType.TYPE_INSTALLABLE_UNIT, artifactKey.getId(), "0.0.0");
List<Path> resolvedBundles = new ArrayList<>();
TargetPlatform targetPlatform = applicationFactory.createTargetPlatform(baselineRepoLocations);
for (P2ResolutionResult result : resolver.resolveTargetDependencies(targetPlatform, null).values()) {
for (Entry entry : result.getArtifacts()) {
if (ArtifactType.TYPE_ECLIPSE_PLUGIN.equals(entry.getType())
&& !"org.eclipse.osgi".equals(entry.getId())) {
resolvedBundles.add(entry.getLocation(true).toPath());
}
}
}
return resolvedBundles;
return applicationFactory.getApiBaselineBundles(baselineRepoLocations, artifactKey, environment);
}

public EclipseApplication getApiApplication(MavenRepositoryLocation apiToolsRepo) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,4 +379,25 @@ public Stream<ExecutionEnvironment> getExecutionEnvironments(MavenProject projec
return Arrays.stream(manifestBREEs);
}

/**
* This method selected the a target environment best suited for the current baseline, if it is
* a valid choice the running target is used (e.g. linux on linux host, windows on windows hosts
* and so on), if such environment is not available it is using the configured ones form the
* project as is.
*
* @param project
*
* @return the chosen {@link TargetEnvironment}s
*/
public Collection<TargetEnvironment> getBaselineEnvironments(MavenProject project) {
Collection<TargetEnvironment> targetEnvironments = getTargetEnvironments(project);
TargetEnvironment runningEnvironment = TargetEnvironment.getRunningEnvironment();
for (TargetEnvironment targetEnvironment : targetEnvironments) {
if (targetEnvironment.equals(runningEnvironment)) {
return List.of(targetEnvironment);
}
}
return targetEnvironments;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*******************************************************************************/
package org.eclipse.tycho.osgi.framework;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
Expand All @@ -26,11 +28,16 @@
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.ArtifactType;
import org.eclipse.tycho.ExecutionEnvironmentConfiguration;
import org.eclipse.tycho.IllegalArtifactReferenceException;
import org.eclipse.tycho.MavenRepositoryLocation;
import org.eclipse.tycho.TargetEnvironment;
import org.eclipse.tycho.TargetPlatform;
import org.eclipse.tycho.core.ee.ExecutionEnvironmentConfigurationImpl;
import org.eclipse.tycho.core.resolver.P2ResolutionResult;
import org.eclipse.tycho.core.resolver.P2ResolutionResult.Entry;
import org.eclipse.tycho.core.resolver.P2Resolver;
import org.eclipse.tycho.core.resolver.P2ResolverFactory;
import org.eclipse.tycho.core.resolver.shared.IncludeSourceMode;
Expand Down Expand Up @@ -95,6 +102,24 @@ public TargetPlatform createTargetPlatform(Collection<MavenRepositoryLocation> l
return targetPlatform;
}

public Collection<Path> getApiBaselineBundles(Collection<MavenRepositoryLocation> baselineRepoLocations,
ArtifactKey artifactKey, Collection<TargetEnvironment> environment)
throws IllegalArtifactReferenceException {
P2Resolver resolver = createResolver(environment);
resolver.addDependency(ArtifactType.TYPE_INSTALLABLE_UNIT, artifactKey.getId(), "0.0.0");
List<Path> resolvedBundles = new ArrayList<>();
TargetPlatform targetPlatform = createTargetPlatform(baselineRepoLocations);
for (P2ResolutionResult result : resolver.resolveTargetDependencies(targetPlatform, null).values()) {
for (Entry entry : result.getArtifacts()) {
if (ArtifactType.TYPE_ECLIPSE_PLUGIN.equals(entry.getType())
&& !"org.eclipse.osgi".equals(entry.getId())) {
resolvedBundles.add(entry.getLocation(true).toPath());
}
}
}
return resolvedBundles;
}

public P2Resolver createResolver() {
return createResolver(List.of(TargetEnvironment.getRunningEnvironment()));
}
Expand Down
12 changes: 12 additions & 0 deletions tycho-eclipse-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.pde</groupId>
<artifactId>org.eclipse.pde.api.tools</artifactId>
<version>1.3.600</version>
<type>jar</type>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.tycho</groupId>
<artifactId>sisu-equinox-launching</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@
package org.eclipse.tycho.eclipsebuild;

import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.nio.file.Path;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import org.apache.maven.model.Repository;
import org.apache.maven.plugin.AbstractMojo;
Expand All @@ -31,11 +34,17 @@
import org.apache.maven.project.MavenProject;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.DependencyResolutionException;
import org.eclipse.tycho.IllegalArtifactReferenceException;
import org.eclipse.tycho.MavenRepositoryLocation;
import org.eclipse.tycho.TargetEnvironment;
import org.eclipse.tycho.TargetPlatform;
import org.eclipse.tycho.core.TychoProjectManager;
import org.eclipse.tycho.model.project.EclipseProject;
import org.eclipse.tycho.osgi.framework.Bundles;
import org.eclipse.tycho.osgi.framework.EclipseApplication;
import org.eclipse.tycho.osgi.framework.EclipseApplicationFactory;
import org.eclipse.tycho.osgi.framework.EclipseApplicationManager;
import org.eclipse.tycho.osgi.framework.EclipseFramework;
import org.eclipse.tycho.osgi.framework.EclipseWorkspaceManager;
Expand All @@ -55,12 +64,22 @@ public abstract class AbstractEclipseBuildMojo<Result extends EclipseBuildResult
@Parameter()
private Repository eclipseRepository;

/**
* If configured, automatically sets a baseline for this project if api tools
* nature is enabled
*/
@Parameter(property = "baselines", name = "baselines")
private List<Repository> baselines;

@Parameter(defaultValue = "false", property = "tycho.eclipsebuild.skip")
private boolean skip;

@Parameter(defaultValue = "false", property = "tycho.eclipsebuild.debug")
protected boolean debug;

@Parameter(defaultValue = "false")
private boolean failOnResolutionError;

/**
* Controls if the local target platform of the project should be used to
* resolve the eclipse application
Expand All @@ -86,6 +105,9 @@ public abstract class AbstractEclipseBuildMojo<Result extends EclipseBuildResult
@Component
private EclipseApplicationManager eclipseApplicationManager;

@Component
private EclipseApplicationFactory applicationFactory;

@Component
private TychoProjectManager projectManager;

Expand Down Expand Up @@ -120,11 +142,25 @@ public final void execute() throws MojoExecutionException, MojoFailureException
if (debug) {
framework.printState();
}
if (framework.hasBundle(Bundles.BUNDLE_PDE_CORE)) {
framework.execute(new SetTargetPlatform(projectDependencies, debug));
} else {
getLog().info("Skip set Target Platform because " + Bundles.BUNDLE_PDE_CORE
+ " is not part of the framework...");
if (hasPDENature(eclipseProject)) {
if (framework.hasBundle(Bundles.BUNDLE_PDE_CORE)) {
framework.execute(new SetTargetPlatform(projectDependencies, debug));
} else {
getLog().info("Skip set Target Platform because " + Bundles.BUNDLE_PDE_CORE
+ " is not part of the framework...");
}
}
if (hasAPIToolsNature(eclipseProject)) {
if (framework.hasBundle(Bundles.BUNDLE_API_TOOLS)) {
if (hasBaselinesSet()) {
framework.execute(new SetApiBaseline(project.getId(), getBaselineBundles(), debug));
} else {
getLog().info("Skip set ApiBasline because no baselines set...");
}
} else {
getLog().info("Skip set ApiBasline because " + Bundles.BUNDLE_API_TOOLS
+ " is not part of the framework...");
}
}
Result result = framework.execute(createExecutable(), getRequireBundles());
if (printMarker) {
Expand Down Expand Up @@ -179,18 +215,57 @@ protected Set<String> getBundles(EclipseProject eclipseProject) {
for (String requiredBundle : getRequireBundles()) {
set.add(requiredBundle);
}
if (eclipseProject.hasNature("org.eclipse.pde.PluginNature")) {
if (hasPDENature(eclipseProject)) {
set.add(Bundles.BUNDLE_PDE_CORE);
}
if (eclipseProject.hasNature("org.eclipse.jdt.core.javanature")) {
if (hasJDTNature(eclipseProject)) {
set.add(Bundles.BUNDLE_JDT_CORE);
}
// TODO if project has org.eclipse.pde.api.tools.apiAnalysisNature and we have a
// baseline parameter then
// set.add(Bundles.BUNDLE_API_TOOLS);
if (hasAPIToolsNature(eclipseProject)) {
set.add(Bundles.BUNDLE_API_TOOLS);
}
return set;
}

private Collection<Path> getBaselineBundles() throws MojoFailureException {
try {
Collection<TargetEnvironment> targetEnvironments = projectManager.getBaselineEnvironments(project);
Optional<ArtifactKey> artifactKey = projectManager.getArtifactKey(project);
getLog().info("Resolve API baseline for " + project.getId() + " with "
+ targetEnvironments.stream().map(String::valueOf).collect(Collectors.joining(", ")));
return applicationFactory.getApiBaselineBundles(
baselines.stream().filter(repo -> repo.getUrl() != null)
.map(repo -> new MavenRepositoryLocation(repo.getId(), URI.create(repo.getUrl()))).toList(),
artifactKey.get(), targetEnvironments);
} catch (IllegalArtifactReferenceException e) {
throw new MojoFailureException("Project specify an invalid artifact key", e);
} catch (DependencyResolutionException e) {
if (failOnResolutionError) {
throw new MojoFailureException("Can't resolve API baseline!", e);
} else {
getLog().warn(
"Can't resolve API baseline: " + Objects.requireNonNullElse(e.getMessage(), e.toString()));
return List.of();
}
}
}

private boolean hasJDTNature(EclipseProject eclipseProject) {
return eclipseProject.hasNature("org.eclipse.jdt.core.javanature");
}

private boolean hasAPIToolsNature(EclipseProject eclipseProject) {
return eclipseProject.hasNature("org.eclipse.pde.api.tools.apiAnalysisNature");
}

private boolean hasPDENature(EclipseProject eclipseProject) {
return eclipseProject.hasNature("org.eclipse.pde.PluginNature");
}

private boolean hasBaselinesSet() {
return baselines != null && baselines.size() > 0;
}

private static void printMarker(IMarker marker, EclipseBuildResult result, Consumer<CharSequence> consumer) {
consumer.accept(asString(marker, result).toString().trim());
}
Expand Down
Loading

0 comments on commit 02b7115

Please sign in to comment.