Skip to content

Commit

Permalink
Add TargetPlatformService for unified acces to the TargetPlatform
Browse files Browse the repository at this point in the history
Fix #1377
  • Loading branch information
laeubi authored and Christoph Läubrich committed Sep 22, 2022
1 parent 90a3a61 commit 466dad9
Show file tree
Hide file tree
Showing 17 changed files with 256 additions and 150 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,150 +13,29 @@
*******************************************************************************/
package org.eclipse.tycho.target;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.LegacySupport;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.logging.Logger;
import org.eclipse.sisu.equinox.EquinoxServiceFactory;
import org.eclipse.tycho.ReactorProject;
import org.eclipse.tycho.ReactorProjectIdentities;
import org.eclipse.tycho.TychoConstants;
import org.eclipse.tycho.core.DependencyResolver;
import org.eclipse.tycho.TargetPlatformService;
import org.eclipse.tycho.core.osgitools.DefaultReactorProject;
import org.eclipse.tycho.core.resolver.DefaultDependencyResolverFactory;
import org.eclipse.tycho.osgi.TychoServiceFactory;
import org.eclipse.tycho.p2.repository.GAV;
import org.eclipse.tycho.p2.target.facade.PomDependencyCollector;
import org.eclipse.tycho.repository.registry.facade.ReactorRepositoryManagerFacade;

@Mojo(name = "target-platform", threadSafe = true)
public class TargetPlatformMojo extends AbstractMojo {
// TODO site doc (including steps & parameters handled in afterProjectsRead?)
@Parameter(property = "project", readonly = true)
private MavenProject project;

@Component(hint = TychoServiceFactory.HINT)
private EquinoxServiceFactory osgiServices;

@Component
private Logger logger;

@Component
private LegacySupport legacySupport;

@Component
private DefaultDependencyResolverFactory dependencyResolverLocator;
private TargetPlatformService platformService;

@Override
public void execute() throws MojoExecutionException, MojoFailureException {
MavenSession session = legacySupport.getSession();
ReactorRepositoryManagerFacade repositoryManager = osgiServices
.getService(ReactorRepositoryManagerFacade.class);
List<ReactorProjectIdentities> upstreamProjects = getReferencedTychoProjects();
ReactorProject reactorProject = DefaultReactorProject.adapt(project);
DependencyResolver dependencyResolver = dependencyResolverLocator.lookupDependencyResolver(project);
PomDependencyCollector pomDependenciesCollector = dependencyResolver.resolvePomDependencies(session, project);
repositoryManager.computeFinalTargetPlatform(reactorProject, upstreamProjects, pomDependenciesCollector);
}

private List<ReactorProjectIdentities> getReferencedTychoProjects() throws MojoExecutionException {
List<ReactorProjectIdentities> result = new ArrayList<>();
HashSet<GAV> considered = new HashSet<>();
//TODO instead of using the MavenProject here, we should fetch the DependencyArtifacts from project type and then use the ArtifactDescriptor!
Collection<MavenProject> values = project.getProjectReferences().values();
getTransitivelyReferencedTychoProjects(values, considered, result);

return result;
}

private void getTransitivelyReferencedTychoProjects(Collection<MavenProject> candidateProjects,
HashSet<GAV> consideredProjects, List<ReactorProjectIdentities> result) throws MojoExecutionException {

for (MavenProject reactorProject : candidateProjects) {
if (!enterProject(reactorProject, consideredProjects)) {
continue;
}

// check for target platform relevant build results (registered by either p2-metadata-default or attach-artifacts)
File metadataXml = getAttachedArtifact(reactorProject, TychoConstants.CLASSIFIER_P2_METADATA);
if (metadataXml == null) {
continue;
}
File artifactXml = getAttachedArtifact(reactorProject, TychoConstants.CLASSIFIER_P2_ARTIFACTS);

// found a Tycho project -> include in target platform
logger.debug("Adding reactor project: " + reactorProject.toString());
ReactorProject tychoReactorProject = DefaultReactorProject.adapt(reactorProject);
verifyIndexFileLocations(tychoReactorProject, metadataXml, artifactXml);
result.add(tychoReactorProject.getIdentities());

Collection<MavenProject> values = reactorProject.getProjectReferences().values();
getTransitivelyReferencedTychoProjects(values, consideredProjects, result);
}
}

private boolean enterProject(MavenProject project, HashSet<GAV> consideredProjects) {
GAV projectGav = new GAV(project.getGroupId(), project.getArtifactId(), project.getVersion());

if (consideredProjects.contains(projectGav)) {
return false;
} else {
consideredProjects.add(projectGav);
return true;
}
}

private static File getAttachedArtifact(MavenProject project, String classifier) {
for (Artifact artifact : project.getAttachedArtifacts()) {
if (classifier.equals(artifact.getClassifier())) {
return artifact.getFile();
}
}
return null;
}

private static void verifyIndexFileLocations(ReactorProject project, File metadataXml, File artifactXml)
throws MojoExecutionException {
verifyArtifactLocationInTargetFolder(project, TychoConstants.CLASSIFIER_P2_METADATA,
TychoConstants.FILE_NAME_P2_METADATA, metadataXml);
verifyArtifactLocationInTargetFolder(project, TychoConstants.CLASSIFIER_P2_ARTIFACTS,
TychoConstants.FILE_NAME_P2_ARTIFACTS, artifactXml);
verifyFilePresenceInTargetFolder(project, TychoConstants.FILE_NAME_LOCAL_ARTIFACTS);
}

private static void verifyArtifactLocationInTargetFolder(ReactorProject project, String artifactClassifier,
String expectedPathInTarget, File actualLocation) throws MojoExecutionException {
File expectedLocation = project.getBuildDirectory().getChild(expectedPathInTarget);
if (actualLocation == null) {
throw new MojoExecutionException("Unexpected build result of " + project + ": Artifact with classifier '"
+ artifactClassifier + "' expected at location \"" + expectedLocation + "\", but is missing");
} else if (!(expectedLocation.equals(actualLocation.getAbsoluteFile()))) {
throw new MojoExecutionException("Unexpected build result of " + project + ": Artifact with classifier '"
+ artifactClassifier + "' expected at location \"" + expectedLocation + "\", but is at \""
+ actualLocation.getAbsolutePath() + "\"");
}
}

private static void verifyFilePresenceInTargetFolder(ReactorProject project, String expectedPathInTarget)
throws MojoExecutionException {
File expectedLocation = project.getBuildDirectory().getChild(expectedPathInTarget);
if (!expectedLocation.isFile()) {
throw new MojoExecutionException(
"Unexpected build result of " + project + ": File \"" + expectedLocation + "\" is missing");
}
//trigger target platform resoloution....
platformService.getTargetPlatform(DefaultReactorProject.adapt(project));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,6 @@ default BuildProperties getBuildProperties() {
public boolean sameProject(/* MavenProject */Object otherProject);

public String getName();

<T> T adapt(Class<T> target);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*******************************************************************************
* Copyright (c) 2022 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;

import java.util.Optional;

/**
* {@link TargetPlatformService} allows access to the {@link TargetPlatform} used to resolve
* dependencies.
*
*/
public interface TargetPlatformService {

/**
*
* @param project
* the project for what the {@link TargetPlatform} should be queried
* @return the target platform for the given {@link ReactorProject} or an empty optional if the
* project do not has one (e.g. is not a Tycho project type)
* @throws DependencyResolutionException
* when the target platform for the project can not be resolved
*/
Optional<TargetPlatform> getTargetPlatform(ReactorProject project) throws DependencyResolutionException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,10 @@ public String getName() {
throw new UnsupportedOperationException();
}

@Override
public <T> T adapt(Class<T> target) {
// TODO Auto-generated method stub
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ public class ReactorRepositoryManagerImpl implements ReactorRepositoryManager {

private static final String PRELIMINARY_TARGET_PLATFORM_KEY = ReactorRepositoryManagerImpl.class.getName()
+ "/dependencyOnlyTargetPlatform";
private static final String FINAL_TARGET_PLATFORM_KEY = TargetPlatform.FINAL_TARGET_PLATFORM_KEY;

private IProvisioningAgentProvider agentFactory;
private File agentDir;
Expand Down Expand Up @@ -109,18 +108,19 @@ public TargetPlatform computePreliminaryTargetPlatform(ReactorProject project,
}

@Override
public void computeFinalTargetPlatform(ReactorProject project,
public TargetPlatform computeFinalTargetPlatform(ReactorProject project,
List<? extends ReactorProjectIdentities> upstreamProjects, PomDependencyCollector pomDependencyCollector) {
PreliminaryTargetPlatformImpl preliminaryTargetPlatform = getRegisteredPreliminaryTargetPlatform(project);
if (preliminaryTargetPlatform == null) {
// project doesn't seem to use resolver=p2
return;
return null;
}
List<PublishingRepository> upstreamProjectResults = getBuildResults(upstreamProjects);
TargetPlatform result = tpFactory.createTargetPlatformWithUpdatedReactorContent(preliminaryTargetPlatform,
upstreamProjectResults, pomDependencyCollector);

project.setContextValue(FINAL_TARGET_PLATFORM_KEY, result);
project.setContextValue(TargetPlatform.FINAL_TARGET_PLATFORM_KEY, result);
return result;
}

private PreliminaryTargetPlatformImpl getRegisteredPreliminaryTargetPlatform(ReactorProject project) {
Expand All @@ -141,7 +141,8 @@ private List<PublishingRepository> getBuildResults(List<? extends ReactorProject

@Override
public TargetPlatform getFinalTargetPlatform(ReactorProject project) {
TargetPlatform targetPlatform = (TargetPlatform) project.getContextValue(FINAL_TARGET_PLATFORM_KEY);
TargetPlatform targetPlatform = (TargetPlatform) project
.getContextValue(TargetPlatform.FINAL_TARGET_PLATFORM_KEY);
if (targetPlatform == null) {
throw new IllegalStateException("Target platform is missing");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ TargetPlatform computePreliminaryTargetPlatform(ReactorProject project,
* Other projects in the reactor which have already been built and may be referenced
* by the given project.
*/
void computeFinalTargetPlatform(ReactorProject project, List<? extends ReactorProjectIdentities> upstreamProjects,
PomDependencyCollector pomDependencyCollector);
TargetPlatform computeFinalTargetPlatform(ReactorProject project,
List<? extends ReactorProjectIdentities> upstreamProjects, PomDependencyCollector pomDependencyCollector);

/**
* Returns the target platform with final p2 metadata for the given project.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ public interface TychoProject {
*/
public ArtifactDependencyWalker getDependencyWalker(ReactorProject project);

/**
* Walks project dependencies resolved for the specified runtime environment.
*/
public ArtifactDependencyWalker getDependencyWalker(ReactorProject project, TargetEnvironment environment);

/**
* Returns resolved project dependencies. For projects targeting multiple runtime environments,
* returned collection includes artifacts for all supported runtime environments.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ public ArtifactDependencyWalker getDependencyWalker(ReactorProject project) {
return getDependencyWalker(project, null);
}

@Override
public ArtifactDependencyWalker getDependencyWalker(ReactorProject project, TargetEnvironment environment) {
return newDependencyWalker(project, environment);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,4 +259,12 @@ public String getName() {
return project.getName();
}

@Override
public <T> T adapt(Class<T> target) {
if (target == MavenProject.class) {
return target.cast(project);
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,6 @@ public class OsgiBundleProject extends AbstractTychoProject implements BundlePro
@Requirement
private DeclarativeServiceConfigurationReader dsConfigReader;

@Override
public ArtifactDependencyWalker getDependencyWalker(ReactorProject project, TargetEnvironment environment) {
return getDependencyWalker(project);
}

@Override
public ArtifactDependencyWalker getDependencyWalker(ReactorProject project) {
final DependencyArtifacts artifacts = getDependencyArtifacts(project);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ public class DefaultDependencyResolverFactory {
private PlexusContainer container;

public DependencyResolver lookupDependencyResolver(MavenProject project) {
ReactorProject reactorProject = DefaultReactorProject.adapt(project);
return lookupDependencyResolver(DefaultReactorProject.adapt(project));
}

public DependencyResolver lookupDependencyResolver(ReactorProject reactorProject) {

Properties properties = (Properties) reactorProject.getContextValue(TychoConstants.CTX_MERGED_PROPERTIES);
TargetPlatformConfiguration configuration = TychoProjectUtils.getTargetPlatformConfiguration(reactorProject);

Expand Down
Loading

0 comments on commit 466dad9

Please sign in to comment.