From 1bf7c48e83e9492e88383b39c9f6883886e21253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Tue, 12 Dec 2023 06:15:36 +0100 Subject: [PATCH] Only rely on context IUs for filtering project dependencies Currently the context IUs are not used to filter project requirements, this can result in dependencies that are actually disabled to be included in the project dependencies. This now removes the previous special handling of fragments by fully depend on only the context IUs and maximum requirements, for this purpose the filtering has to be made on project specific contextIUs and can't just store one collection of filtered items for all callers. Fix https://github.com/eclipse-tycho/tycho/issues/3197 --- .../MavenProjectDependencyProcessor.java | 83 +++++-------------- .../tycho/build/TychoGraphBuilder.java | 15 +++- .../tycho/core/TychoProjectManager.java | 2 +- .../maven/TychoMavenLifecycleParticipant.java | 6 +- 4 files changed, 37 insertions(+), 69 deletions(-) diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/MavenProjectDependencyProcessor.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/MavenProjectDependencyProcessor.java index f9ef50c124..b6116a8b5b 100644 --- a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/MavenProjectDependencyProcessor.java +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/MavenProjectDependencyProcessor.java @@ -18,9 +18,6 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -29,6 +26,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -57,8 +55,7 @@ @Component(role = MavenProjectDependencyProcessor.class) public class MavenProjectDependencyProcessor { - private static final ProjectDependencies EMPTY_DEPENDENCIES = new ProjectDependencies(Collections.emptyList(), - Collections.emptyList(), Map.of(), Set.of()); + private static final ProjectDependencies EMPTY_DEPENDENCIES = new ProjectDependencies(Map.of(), Set.of()); private static final boolean DUMP_DATA = Boolean.getBoolean("tycho.p2.dump") || Boolean.getBoolean("tycho.p2.dump.dependencies"); @@ -112,9 +109,11 @@ public ProjectDependencies getProjectDependecies(MavenProject mavenProject) { } @Override - public Stream>> dependencies() { + public Stream>> dependencies( + Function> contextIuSupplier) { return projectDependenciesMap.entrySet().stream() - .map(pd -> new SimpleEntry<>(pd.getKey(), pd.getValue().dependencies)); + .map(pd -> new SimpleEntry<>(pd.getKey(), + pd.getValue().getDependencies(contextIuSupplier.apply(pd.getKey())))); } @Override @@ -158,7 +157,8 @@ private Map computeProjectDependencies(Collec if (DUMP_DATA) { File file = new File(project.getBasedir(), "project-dependencies.xml"); try { - new MetadataIO().writeXML(Collections.unmodifiableCollection(projectDependencies.dependencies), + new MetadataIO().writeXML( + Collections.unmodifiableCollection(projectDependencies.getDependencies(List.of())), file); } catch (IOException e) { } @@ -197,29 +197,7 @@ private ProjectDependencies computeProjectDependencies(Set pro } Map> dependencies = slicer.computeDirectDependencies(projectUnits, avaiableIUs); - // first collect the maximum desired number - Set resolved = new LinkedHashSet<>(); - for (Entry> entry : dependencies.entrySet()) { - IRequirement requirement = entry.getKey(); - Collection units = entry.getValue(); - List limit = units.stream().filter(unit -> !projectUnits.contains(unit)) - .limit(requirement.getMax()).toList(); - resolved.addAll(limit); - } - // now we need to filter all fragments that we are a host! - // for example SWT creates an explicit requirement to its fragments and we don't - // want them included directly - // TODO reevaluate, this is where filters come into place we probabbly no longer - // need this part! - Set projectFragments = new HashSet<>(); - for (Iterator iterator = resolved.iterator(); iterator.hasNext();) { - IInstallableUnit unit = iterator.next(); - if (hasAnyHost(unit, projectUnits)) { - projectFragments.add(unit); - iterator.remove(); - } - } - return new ProjectDependencies(resolved, projectFragments, dependencies, projectUnits); + return new ProjectDependencies(dependencies, projectUnits); } private static boolean hasAnyHost(IInstallableUnit unit, Iterable collection) { @@ -267,27 +245,15 @@ private static boolean isMatch(IRequirement requirement, Collection dependencies; - private final Collection fragments; - private Map> requirementsMap; - private Set projectUnits; + private final Map> requirementsMap; + private final Set projectUnits; - ProjectDependencies(Collection dependencies, Collection fragments, - Map> requirementsMap, Set projectUnits) { - this.dependencies = dependencies; - this.fragments = fragments; + ProjectDependencies(Map> requirementsMap, + Set projectUnits) { this.requirementsMap = requirementsMap; this.projectUnits = projectUnits; } - public Collection getDependencies() { - return dependencies; - } - - public Collection getFragments() { - return fragments; - } - public Collection getDependencies(Collection contextIUs) { return requirementsMap.entrySet().stream().filter(entry -> isMatch(entry.getKey(), contextIUs)) .flatMap(entry -> entry.getValue().stream().filter(unit -> !projectUnits.contains(unit)) @@ -319,31 +285,24 @@ public static interface ProjectDependencyClosure { /** * @return a stream of all contained maven projects with dependecies */ - Stream>> dependencies(); + Stream>> dependencies( + Function> contextIuSupplier); /** * Given a maven project returns all other maven projects this one (directly) * depends on * - * @param mavenProject + * @param mavenProject the maven project for which all direct dependent projects + * should be collected + * @param contextIUs the context IUs to filter dependencies * @return the collection of projects this maven project depend on in this * closure */ - default Collection getDependencyProjects(MavenProject mavenProject) { + default Collection getDependencyProjects(MavenProject mavenProject, + Collection contextIUs) { ProjectDependencies projectDependecies = getProjectDependecies(mavenProject); - List list = projectDependecies.getDependencies().stream() + return projectDependecies.getDependencies(contextIUs).stream() .flatMap(dependency -> getProject(dependency).stream()).distinct().toList(); - if (isFragment(mavenProject)) { - return list; - } - return list.stream().flatMap(project -> { - ProjectDependencies dependecies = getProjectDependecies(project); - if (dependecies.getFragments().isEmpty()) { - return Stream.of(project); - } - return Stream.concat(Stream.of(project), - dependecies.getFragments().stream().flatMap(dependency -> getProject(dependency).stream())); - }).distinct().toList(); } /** diff --git a/tycho-build/src/main/java/org/eclipse/tycho/build/TychoGraphBuilder.java b/tycho-build/src/main/java/org/eclipse/tycho/build/TychoGraphBuilder.java index 2b2ac745af..8607af5846 100644 --- a/tycho-build/src/main/java/org/eclipse/tycho/build/TychoGraphBuilder.java +++ b/tycho-build/src/main/java/org/eclipse/tycho/build/TychoGraphBuilder.java @@ -15,6 +15,7 @@ package org.eclipse.tycho.build; import java.util.ArrayList; +import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -161,11 +162,14 @@ public Result build(MavenSession session) { if (DEBUG) { for (MavenProject project : projects) { ProjectDependencies depends = dependencyClosure.getProjectDependecies(project); - if (depends.getDependencies().isEmpty()) { + // we fetch all dependencies here without filtering, because the goal is to find + // as many projects that are maybe required + Collection dependencies = depends.getDependencies(List.of()); + if (dependencies.isEmpty()) { continue; } log.info("[[ project " + project.getName() + " depends on: ]]"); - for (IInstallableUnit dependency : depends.getDependencies()) { + for (IInstallableUnit dependency : dependencies) { Optional mavenProject = dependencyClosure.getProject(dependency); if (mavenProject.isEmpty()) { log.info(" IU: " + dependency); @@ -186,7 +190,10 @@ public Result build(MavenSession session) { ProjectRequest projectRequest = queue.poll(); if (selectedProjects.add(projectRequest.mavenProject)) { if (projectRequest.addDependencies) { - dependencyClosure.getDependencyProjects(projectRequest.mavenProject).forEach(project -> { + // we fetch all dependencies here without filtering for the context, because the + // goal is to find as many projects that are might be required + dependencyClosure.getDependencyProjects(projectRequest.mavenProject, List.of()) + .forEach(project -> { if (DEBUG) { log.info(" + add dependency project '" + project.getId() + "' of project '" + projectRequest.mavenProject.getId() + "'"); @@ -196,7 +203,7 @@ public Result build(MavenSession session) { }); } if (projectRequest.addRequires) { - dependencyClosure.dependencies()// + dependencyClosure.dependencies(always -> List.of())// .filter(entry -> entry.getValue().stream()// .flatMap(dependency -> dependencyClosure.getProject(dependency).stream())// .anyMatch(projectRequest::matches))// diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/TychoProjectManager.java b/tycho-core/src/main/java/org/eclipse/tycho/core/TychoProjectManager.java index e315e753a2..5abc26e29e 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/TychoProjectManager.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/TychoProjectManager.java @@ -146,7 +146,7 @@ public void readExecutionEnvironmentConfiguration(ReactorProject project, Execut } } - public List getContextIUs(MavenProject project) { + public Collection getContextIUs(MavenProject project) { TargetPlatformConfiguration configuration = getTargetPlatformConfiguration(project); return configuration.getEnvironments().stream().map(env -> getProfileProperties(env, configuration)) .map(InstallableUnit::contextIU).toList(); diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/maven/TychoMavenLifecycleParticipant.java b/tycho-core/src/main/java/org/eclipse/tycho/core/maven/TychoMavenLifecycleParticipant.java index 2c0377b850..cbdd5dc257 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/maven/TychoMavenLifecycleParticipant.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/maven/TychoMavenLifecycleParticipant.java @@ -154,7 +154,8 @@ public void afterProjectsRead(MavenSession session) throws MavenExecutionExcepti //do not inject additional dependencies for non Tycho managed projects! continue; } - Collection dependencyProjects = closure.getDependencyProjects(project); + Collection dependencyProjects = closure.getDependencyProjects(project, + projectManager.getContextIUs(project)); MavenDependencyInjector.injectMavenProjectDependencies(project, dependencyProjects); if (DUMP_DATA) { try { @@ -198,7 +199,8 @@ private void dumpProjectRequirements(MavenProject project, BufferedWriter writer writer.write(indent2 + "provides " + satIU + " that satisfies " + requirement + "\r\n"); } } - dumpProjectRequirements(dependency, writer, closure, closure.getDependencyProjects(dependency), indent2, + dumpProjectRequirements(dependency, writer, closure, + closure.getDependencyProjects(dependency, projectManager.getContextIUs(project)), indent2, visited); } }