Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generalize usage of Eclipse Applications in Tycho #3050

Merged
merged 1 commit into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import java.net.URI;
import java.nio.file.Path;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand All @@ -41,23 +40,13 @@
import org.eclipse.pde.api.tools.internal.IApiCoreConstants;
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem;
import org.eclipse.tycho.ArtifactDescriptor;
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.ClasspathEntry;
import org.eclipse.tycho.DependencyResolutionException;
import org.eclipse.tycho.IllegalArtifactReferenceException;
import org.eclipse.tycho.MavenRepositoryLocation;
import org.eclipse.tycho.ReactorProject;
import org.eclipse.tycho.ResolvedArtifactKey;
import org.eclipse.tycho.TychoConstants;
import org.eclipse.tycho.classpath.ClasspathContributor;
import org.eclipse.tycho.core.TychoProject;
import org.eclipse.tycho.core.TychoProjectManager;
import org.eclipse.tycho.core.osgitools.DefaultReactorProject;
import org.eclipse.tycho.core.osgitools.MavenBundleResolver;
import org.eclipse.tycho.core.osgitools.OsgiBundleProject;
import org.eclipse.tycho.core.utils.TychoProjectUtils;
import org.eclipse.tycho.helper.PluginRealmHelper;
import org.eclipse.tycho.model.project.EclipseProject;
import org.eclipse.tycho.osgi.framework.EclipseApplication;
import org.eclipse.tycho.osgi.framework.EclipseFramework;
Expand Down Expand Up @@ -122,12 +111,6 @@ public class ApiAnalysisMojo extends AbstractMojo {
@Component
private ApiApplicationResolver resolver;

@Component
private PluginRealmHelper pluginRealmHelper;

@Component
protected MavenBundleResolver mavenBundleResolver;

@Component
private ApiApplicationResolver applicationResolver;

Expand Down Expand Up @@ -158,7 +141,7 @@ public void execute() throws MojoExecutionException, MojoFailureException {
}
Collection<Path> dependencyBundles;
try {
dependencyBundles = getProjectDependencies();
dependencyBundles = projectManager.getProjectDependencies(project);
} catch (Exception e) {
throw new MojoFailureException("Can't fetch dependencies!", e);
}
Expand Down Expand Up @@ -279,56 +262,6 @@ private String time(long start) {
return sec + " s";
}

private Collection<Path> getProjectDependencies() throws Exception {
Set<Path> dependencySet = new HashSet<>();
TychoProject tychoProject = projectManager.getTychoProject(project).get();
List<ArtifactDescriptor> dependencies = TychoProjectUtils
.getDependencyArtifacts(DefaultReactorProject.adapt(project)).getArtifacts();
for (ArtifactDescriptor descriptor : dependencies) {
File location = descriptor.fetchArtifact().get();
if (location.equals(project.getBasedir())) {
continue;
}
ReactorProject reactorProject = descriptor.getMavenProject();
if (reactorProject == null) {
writeLocation(location, dependencySet);
} else {
ReactorProject otherProject = reactorProject;
writeLocation(otherProject.getArtifact(descriptor.getClassifier()), dependencySet);
}
}
if (tychoProject instanceof OsgiBundleProject bundleProject) {
pluginRealmHelper.visitPluginExtensions(project, session, ClasspathContributor.class, cpc -> {
List<ClasspathEntry> list = cpc.getAdditionalClasspathEntries(project, Artifact.SCOPE_COMPILE);
if (list != null && !list.isEmpty()) {
for (ClasspathEntry entry : list) {
for (File locations : entry.getLocations()) {
writeLocation(locations, dependencySet);
}
}
}
});
// This is a hack because "org.eclipse.osgi.services" exports the annotation
// package and might then be resolved by Tycho as a dependency, but then PDE
// can't find the annotations here, so we always add this as a dependency
// manually here, once "org.eclipse.osgi.services" is gone we can remove this
// again!
Optional<ResolvedArtifactKey> bundle = mavenBundleResolver.resolveMavenBundle(project, session, "org.osgi",
"org.osgi.service.component.annotations", "1.3.0");
bundle.ifPresent(key -> {
writeLocation(key.getLocation(), dependencySet);
});
}
return dependencySet;
}

private void writeLocation(File location, Collection<Path> consumer) {
if (location == null) {
return;
}
consumer.add(location.getAbsoluteFile().toPath());
}

private static final class ApiAppKey {

private URI key;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.codehaus.plexus.component.annotations.Component;
Expand All @@ -31,8 +32,11 @@
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;
import org.eclipse.tycho.osgi.framework.EclipseApplicationManager;
import org.eclipse.tycho.osgi.framework.Features;
import org.osgi.framework.BundleException;
import org.osgi.service.log.LogEntry;

Expand All @@ -43,14 +47,6 @@
@Component(role = ApiApplicationResolver.class)
public class ApiApplicationResolver {

private static final String FRAGMENT_COMPATIBILITY = "org.eclipse.osgi.compatibility.state";

private static final String BUNDLE_API_TOOLS = "org.eclipse.pde.api.tools";

private static final String BUNDLE_LAUNCHING_MACOS = "org.eclipse.jdt.launching.macosx";

private static final String FILTER_MACOS = "(osgi.os=macosx)";

private final Map<URI, EclipseApplication> cache = new ConcurrentHashMap<>();

@Requirement
Expand All @@ -59,6 +55,9 @@ public class ApiApplicationResolver {
@Requirement
private EclipseApplicationFactory applicationFactory;

@Requirement
private EclipseApplicationManager applicationManager;

public Collection<Path> getApiBaselineBundles(Collection<MavenRepositoryLocation> baselineRepoLocations,
ArtifactKey artifactKey) throws IllegalArtifactReferenceException {
P2Resolver resolver = applicationFactory.createResolver();
Expand All @@ -77,16 +76,11 @@ public Collection<Path> getApiBaselineBundles(Collection<MavenRepositoryLocation
}

public EclipseApplication getApiApplication(MavenRepositoryLocation apiToolsRepo) {
return cache.computeIfAbsent(apiToolsRepo.getURL().normalize(), x -> {
logger.info("Resolve API tools runtime from " + apiToolsRepo + "...");
EclipseApplication application = applicationFactory.createEclipseApplication(apiToolsRepo,
"ApiToolsApplication");
application.addBundle(BUNDLE_API_TOOLS);
application.addBundle(FRAGMENT_COMPATIBILITY);
application.addConditionalBundle(BUNDLE_LAUNCHING_MACOS, FILTER_MACOS);
application.setLoggingFilter(ApiApplicationResolver::isOnlyDebug);
return application;
});

EclipseApplication application = applicationManager.getApplication(apiToolsRepo, new Bundles(Set.of(Bundles.BUNDLE_API_TOOLS)),
new Features(Set.of()), "Api Tools");
application.setLoggingFilter(ApiApplicationResolver::isOnlyDebug);
return application;
}

private static boolean isOnlyDebug(LogEntry entry) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.inject.Inject;
Expand All @@ -31,18 +36,28 @@
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import org.eclipse.tycho.ArtifactDescriptor;
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.ClasspathEntry;
import org.eclipse.tycho.DefaultArtifactKey;
import org.eclipse.tycho.ExecutionEnvironmentConfiguration;
import org.eclipse.tycho.ReactorProject;
import org.eclipse.tycho.ResolvedArtifactKey;
import org.eclipse.tycho.TargetPlatform;
import org.eclipse.tycho.TargetPlatformService;
import org.eclipse.tycho.TychoConstants;
import org.eclipse.tycho.classpath.ClasspathContributor;
import org.eclipse.tycho.core.ee.ExecutionEnvironmentConfigurationImpl;
import org.eclipse.tycho.core.osgitools.AbstractTychoProject;
import org.eclipse.tycho.core.osgitools.BundleReader;
import org.eclipse.tycho.core.osgitools.DefaultReactorProject;
import org.eclipse.tycho.core.osgitools.MavenBundleResolver;
import org.eclipse.tycho.core.osgitools.OsgiBundleProject;
import org.eclipse.tycho.core.osgitools.OsgiManifest;
import org.eclipse.tycho.core.osgitools.OsgiManifestParserException;
import org.eclipse.tycho.core.resolver.DefaultTargetPlatformConfigurationReader;
import org.eclipse.tycho.core.utils.TychoProjectUtils;
import org.eclipse.tycho.helper.PluginRealmHelper;
import org.eclipse.tycho.model.project.EclipseProject;
import org.eclipse.tycho.targetplatform.TargetDefinition;

Expand Down Expand Up @@ -72,6 +87,15 @@ public class TychoProjectManager {
@Requirement
ToolchainManager toolchainManager;

@Requirement
PluginRealmHelper pluginRealmHelper;

@Requirement
MavenBundleResolver mavenBundleResolver;

@Requirement
TargetPlatformService targetPlatformService;

private final Map<File, Optional<EclipseProject>> eclipseProjectCache = new ConcurrentHashMap<>();

private final MavenSession mavenSession;
Expand Down Expand Up @@ -203,4 +227,67 @@ public Optional<Processor> getBndTychoProject(MavenProject project) {
return Optional.empty();
}

/**
* Determine the list of dependencies for a given project as a collection of path items
*
* @param project
* the project to use to determine the dependencies
* @return a Collection of pathes describing the project dependencies
* @throws Exception
*/
public Collection<Path> getProjectDependencies(MavenProject project) throws Exception {
Set<Path> dependencySet = new HashSet<>();
TychoProject tychoProject = getTychoProject(project).get();
List<ArtifactDescriptor> dependencies = TychoProjectUtils
.getDependencyArtifacts(DefaultReactorProject.adapt(project)).getArtifacts();
for (ArtifactDescriptor descriptor : dependencies) {
File location = descriptor.fetchArtifact().get();
if (location.equals(project.getBasedir())) {
continue;
}
ReactorProject reactorProject = descriptor.getMavenProject();
if (reactorProject == null) {
writeLocation(location, dependencySet);
} else {
writeLocation(reactorProject.getArtifact(descriptor.getClassifier()), dependencySet);
}
}
if (tychoProject instanceof OsgiBundleProject bundleProject) {
MavenSession session = getMavenSession();
pluginRealmHelper.visitPluginExtensions(project, session, ClasspathContributor.class, cpc -> {
List<ClasspathEntry> list = cpc.getAdditionalClasspathEntries(project, Artifact.SCOPE_COMPILE);
if (list != null && !list.isEmpty()) {
for (ClasspathEntry entry : list) {
for (File locations : entry.getLocations()) {
writeLocation(locations, dependencySet);
}
}
}
});
// This is a hack because "org.eclipse.osgi.services" exports the annotation
// package and might then be resolved by Tycho as a dependency, but then PDE
// can't find the annotations here, so we always add this as a dependency
// manually here, once "org.eclipse.osgi.services" is gone we can remove this
// again!
Optional<ResolvedArtifactKey> bundle = mavenBundleResolver.resolveMavenBundle(project, session, "org.osgi",
"org.osgi.service.component.annotations", "1.3.0");
bundle.ifPresent(key -> {
writeLocation(key.getLocation(), dependencySet);
});
}
return dependencySet;
}

private void writeLocation(File location, Collection<Path> consumer) {
if (location == null) {
return;
}
consumer.add(location.getAbsoluteFile().toPath());
}

public Optional<TargetPlatform> getTargetPlatform(MavenProject project) {
return targetPlatformService.getTargetPlatform(DefaultReactorProject.adapt(project));

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*******************************************************************************
* 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.osgi.framework;

import java.util.Set;

public record Bundles(Set<String> bundles) {

public static final String BUNDLE_API_TOOLS = "org.eclipse.pde.api.tools";
public static final String BUNDLE_ECLIPSE_HELP_BASE = "org.eclipse.help.base";
public static final String BUNDLE_PDE_CORE = "org.eclipse.pde.core";
static final String BUNDLE_LAUNCHING_MACOS = "org.eclipse.jdt.launching.macosx";
static final String BUNDLE_APP = "org.eclipse.equinox.app";
static final String BUNDLE_SCR = "org.apache.felix.scr";
static final String BUNDLE_CORE = "org.eclipse.core.runtime";
static final String BUNDLE_LAUNCHER = "org.eclipse.equinox.launcher";

public static Bundles of(String... bundles) {
return new Bundles(Set.of(bundles));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ public class EclipseApplication {

public static final String ARG_APPLICATION = "-application";

private static final Set<String> ALWAYS_START_BUNDLES = Set.of(EclipseApplicationFactory.BUNDLE_CORE,
EclipseApplicationFactory.BUNDLE_SCR, EclipseApplicationFactory.BUNDLE_APP);
private static final Set<String> ALWAYS_START_BUNDLES = Set.of(Bundles.BUNDLE_CORE,
Bundles.BUNDLE_SCR, Bundles.BUNDLE_APP);
private P2Resolver resolver;
private TargetPlatform targetPlatform;
private Logger logger;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,6 @@
@SessionScoped
public class EclipseApplicationFactory {

static final String BUNDLE_APP = "org.eclipse.equinox.app";

static final String BUNDLE_SCR = "org.apache.felix.scr";

static final String BUNDLE_CORE = "org.eclipse.core.runtime";

private static final String BUNDLE_LAUNCHER = "org.eclipse.equinox.launcher";

@Requirement
private ToolchainManager toolchainManager;

Expand All @@ -67,15 +59,17 @@ public EclipseApplicationFactory(MavenSession mavenSession) {
}

public EclipseApplication createEclipseApplication(MavenRepositoryLocation repositoryLocation, String name) {
return createEclipseApplication(createTargetPlatform(List.of(repositoryLocation)), name);
}

public EclipseApplication createEclipseApplication(TargetPlatform targetPlatform, String name) {
P2Resolver resolver = createResolver();
List<MavenRepositoryLocation> locations = List.of(repositoryLocation);
TargetPlatform targetPlatform = createTargetPlatform(locations);
EclipseApplication application = new EclipseApplication(name, resolver, targetPlatform, logger);
//add the bare minimum required ...
application.addBundle(BUNDLE_CORE);
application.addBundle(BUNDLE_SCR);
application.addBundle(BUNDLE_APP);
application.addBundle(BUNDLE_LAUNCHER);
application.addBundle(Bundles.BUNDLE_CORE);
application.addBundle(Bundles.BUNDLE_SCR);
application.addBundle(Bundles.BUNDLE_APP);
application.addBundle(Bundles.BUNDLE_LAUNCHER);
return application;
}

Expand Down
Loading
Loading