diff --git a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/repository/P2RepositoryManager.java b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/repository/P2RepositoryManager.java index 95b7295d5a..18f7cdfcb4 100644 --- a/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/repository/P2RepositoryManager.java +++ b/p2-maven-plugin/src/main/java/org/eclipse/tycho/p2maven/repository/P2RepositoryManager.java @@ -131,7 +131,7 @@ public IQueryable getCompositeMetadataRepository(Collection getTargetEnvironments(MavenProject project) { TychoProject tychoProject = projectTypes.get(project.getPackaging()); if (tychoProject != null) { - //these will already be filtered at reading the target configuration + //these will already be filtered at reading the target configuration return getTargetPlatformConfiguration(project).getEnvironments(); } //if no tycho project, just assume the default running environment @@ -199,6 +200,10 @@ public Optional getTychoProject(MavenProject project) { return Optional.ofNullable(projectTypes.get(project.getPackaging())); } + public Optional getDependencyArtifacts(MavenProject project) { + return getTychoProject(project).map(tp -> tp.getDependencyArtifacts(project)); + } + public Optional getTychoProject(ReactorProject project) { if (project == null) { return Optional.empty(); diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/AbstractTychoProject.java b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/AbstractTychoProject.java index 8a4a0cf2ae..26ce8bb6b2 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/AbstractTychoProject.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/AbstractTychoProject.java @@ -72,6 +72,11 @@ public abstract class AbstractTychoProject extends AbstractLogEnabled implements @Requirement(hint = "p2") protected DependencyResolver dependencyResolver; + @Override + public DependencyArtifacts getDependencyArtifacts(MavenProject project) { + return getDependencyArtifacts(DefaultReactorProject.adapt(project)); + } + @Override public DependencyArtifacts getDependencyArtifacts(ReactorProject reactorProject) { return reactorProject.computeContextValue(TychoConstants.CTX_DEPENDENCY_ARTIFACTS, () -> { diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/BaselineServiceImpl.java b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/BaselineServiceImpl.java index 2ebd4931f4..6f3ce55b45 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/BaselineServiceImpl.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/osgitools/BaselineServiceImpl.java @@ -75,7 +75,7 @@ public Map getProjectBaseline(Collection projects = mavenSession.getProjects(); + List reactorDependencies = projects.stream().parallel().unordered().flatMap(project -> { + MavenSession old = legacySupport.getSession(); + try { + MavenSession clone = mavenSession.clone(); + clone.setCurrentProject(project); + legacySupport.setSession(clone); + return projectManager.getDependencyArtifacts(project).map(DependencyArtifacts::getNonReactorUnits) + .stream().flatMap(Collection::stream).filter(iu -> { + if (iu.getId().endsWith(".source")) { + return false; + } + if (iu.getId().endsWith(".feature.jar")) { + return false; + } + return true; + }); + } finally { + legacySupport.setSession(old); + } + }).distinct().toList(); + List repoList = projects.stream().flatMap(project -> { + Stream pomRepos = project.getRepositories().stream().filter(repo -> "p2".equals(repo.getLayout())) + .map(repo -> repo.getUrl()); + return pomRepos; + }).distinct().sorted().toList(); + log.info("Found " + reactorDependencies.size() + " dependencies and " + repoList.size() + + " possible repositories: "); + Map> repo2unitMap = new LinkedHashMap<>(); + Set notFound = new HashSet<>(reactorDependencies); + for (String repository : repoList) { + log.info("\tScanning " + repository + "..."); + try { + IMetadataRepository metadataRepository = repositoryManager + .getMetadataRepository(new MavenRepositoryLocation(null, URI.create(repository))); + Set units = new HashSet<>(); + for (IInstallableUnit unit : reactorDependencies) { + if (metadataRepository.contains(unit)) { + units.add(unit); + notFound.remove(unit); + } + } + if (units.size() > 0) { + repo2unitMap.put(metadataRepository, units); + log.info("\tFound: " + units.size() + " dependencies in this repository!"); + } + } catch (ProvisionException e) { + throw new MojoFailureException("can't load repository " + repository, e); + } + } + if (notFound.size() > 0) { + log.info(notFound.size() + " dependencies where not mapped to a repository:"); + for (IInstallableUnit unit : notFound) { + log.info("\t" + unit); + } + } + log.info("Generate Target ..."); + StringBuilder builder = new StringBuilder("\n" + + "\n\n\t\n"); + for (Entry> entry : repo2unitMap.entrySet()) { + builder.append("\t\t\n"); + Set requiredUnits = entry.getValue(); + //First step is to remove everything that is already required by something... + Set alreayTransitiveRequired = computeRequired(requiredUnits); + requiredUnits.removeAll(alreayTransitiveRequired); + IMetadataRepository repository = entry.getKey(); + if (!hasOnlyFeatures(requiredUnits)) { + Set strict = new HashSet<>(requiredUnits); + //Next is we try to find all features that do require something we still want to have + IQueryResult features = repository.query(QueryUtil.createIUGroupQuery(), null); + Set providingFeatures = computeFeatureRequires(features, requiredUnits); + requiredUnits.addAll(providingFeatures); + //Now a final reduction step + Set transitiveRequiredFinal = computeRequired(requiredUnits); + requiredUnits.removeAll(transitiveRequiredFinal); + if (!strict.equals(requiredUnits)) { + builder.append("\t\t\t\n"); + for (IInstallableUnit unit : strict) { + builder.append("\t\t\t\n"); + } + builder.append( + "\n\t\t\t\n"); + } + } + for (IInstallableUnit unit : requiredUnits) { + builder.append("\t\t\t"); + addUnit(unit, builder); + builder.append("\n"); + } + builder.append("\t\t\t\n"); + builder.append("\t\t\n"); + } + if (notFound.size() > 0) { + List osgiMaven = new ArrayList<>(); + List wrappedMaven = new ArrayList<>(); + for (IInstallableUnit mavenUnit : notFound) { + String osgi = getMavenDependency(mavenUnit, builder, TychoConstants.PROP_GROUP_ID, + TychoConstants.PROP_ARTIFACT_ID, TychoConstants.PROP_VERSION); + if (osgi == null) { + String wrapped = getMavenDependency(mavenUnit, builder, TychoConstants.PROP_WRAPPED_GROUP_ID, + TychoConstants.PROP_WRAPPED_ARTIFACT_ID, TychoConstants.PROP_WRAPPED_VERSION); + if (wrapped != null) { + wrappedMaven.add(wrapped); + } else { + log.warn(mavenUnit + " can not be represented in the target at all!"); + } + } else { + osgiMaven.add(osgi); + } + } + createMavenLocation(osgiMaven, "error", builder); + createMavenLocation(wrappedMaven, "generate", builder); + } + builder.append("\t\n"); + try { + targetFile.getParentFile().mkdirs(); + Files.writeString(targetFile.toPath(), builder, StandardCharsets.UTF_8); + log.info("Target is written to " + targetFile.getAbsolutePath()); + } catch (IOException e) { + throw new MojoFailureException("writing target file failed", e); + } + } + + private void createMavenLocation(List artifacts, String mm, StringBuilder builder) { + builder.append("\t\t\n"); + for (String artifact : artifacts) { + builder.append("\t\t\t"); + builder.append(artifact); + builder.append("\n"); + } + builder.append("\t\t\n"); + } + + private String getMavenDependency(IInstallableUnit mavenUnit, StringBuilder builder, String groupProperty, + String artifactProperty, String versionProperty) { + String groupId = mavenUnit.getProperty(groupProperty); + String artifactId = mavenUnit.getProperty(artifactProperty); + String version = mavenUnit.getProperty(versionProperty); + if (groupId != null && artifactId != null && version != null) { + return String.format( + "\n\t\t\t\t%s\n\t\t\t\t%s\n\t\t\t\t%s\n\t\t\t", + groupId, artifactId, version); + } + return null; + } + + private boolean hasOnlyFeatures(Set requiredUnits) { + for (IInstallableUnit unit : requiredUnits) { + if (!Boolean.TRUE.toString().equals(unit.getProperty(QueryUtil.PROP_TYPE_GROUP))) { + return false; + } + } + return true; + } + + private void addUnit(IInstallableUnit unit, StringBuilder builder) { + builder.append(""); + } + + private Set computeFeatureRequires(IQueryResult features, + Set units) { + HashSet result = new HashSet<>(); + outer: for (IInstallableUnit feature : features) { + if (units.contains(feature)) { + continue; + } + if (Boolean.TRUE.toString() + .equals(feature.getProperty(MetadataFactory.InstallableUnitDescription.PROP_TYPE_PRODUCT))) { + continue; + } + for (IRequirement featureRequirement : feature.getRequirements()) { + for (IInstallableUnit unit : units) { + if (unit.satisfies(featureRequirement)) { + result.add(feature); + continue outer; + } + } + } + } + return result; + } + + private Set computeRequired(Set units) { + Set required = new HashSet<>(); + for (IInstallableUnit base : units) { + for (IRequirement requirement : base.getRequirements()) { + for (IInstallableUnit other : units) { + if (other == base) { + continue; + } + if (other.satisfies(requirement)) { + required.add(other); + } + } + } + } + return required; + } + +}