diff --git a/m2e-maven-runtime/org.eclipse.m2e.archetype.common/pom.xml b/m2e-maven-runtime/org.eclipse.m2e.archetype.common/pom.xml index 61537457a..c21f8a642 100644 --- a/m2e-maven-runtime/org.eclipse.m2e.archetype.common/pom.xml +++ b/m2e-maven-runtime/org.eclipse.m2e.archetype.common/pom.xml @@ -19,7 +19,7 @@ org.eclipse.m2e.archetype.common - 1.18.1-SNAPSHOT + 1.19.0-SNAPSHOT eclipse-plugin M2E Maven Archetype Common @@ -99,7 +99,7 @@ org.apache.maven.archetype.*;provider=m2e;mandatory:=provider;x-internal:=true, org.codehaus.plexus.velocity;provider=m2e;mandatory:=provider;x-internal:=true, - org.eclipse.m2e.maven.runtime;bundle-version="[1.18.0,1.19.0)" + org.eclipse.m2e.maven.runtime;bundle-version="[1.18.0,2)" diff --git a/m2e-maven-runtime/org.eclipse.m2e.maven.indexer/pom.xml b/m2e-maven-runtime/org.eclipse.m2e.maven.indexer/pom.xml index 91adf3665..eeca34f42 100644 --- a/m2e-maven-runtime/org.eclipse.m2e.maven.indexer/pom.xml +++ b/m2e-maven-runtime/org.eclipse.m2e.maven.indexer/pom.xml @@ -19,7 +19,7 @@ org.eclipse.m2e.maven.indexer - 1.18.1-SNAPSHOT + 1.19.0-SNAPSHOT eclipse-plugin M2E Maven/Nexus Indexer @@ -114,8 +114,8 @@ javax.inject;version="1.0.0" - org.eclipse.m2e.maven.runtime;bundle-version="[1.18.0,1.19.0)", - org.eclipse.m2e.archetype.common;bundle-version="[1.18.0,1.19.0)", + org.eclipse.m2e.maven.runtime;bundle-version="[1.18.0,2)", + org.eclipse.m2e.archetype.common;bundle-version="[1.18.0,2)", com.google.guava diff --git a/m2e-maven-runtime/org.eclipse.m2e.maven.runtime.slf4j.simple/pom.xml b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime.slf4j.simple/pom.xml index c0e325e05..485637e2c 100644 --- a/m2e-maven-runtime/org.eclipse.m2e.maven.runtime.slf4j.simple/pom.xml +++ b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime.slf4j.simple/pom.xml @@ -19,7 +19,7 @@ org.eclipse.m2e.maven.runtime.slf4j.simple - 1.18.1-SNAPSHOT + 1.19.0-SNAPSHOT eclipse-plugin M2E SLF4J-Simple Binding for Embedded Maven Runtime diff --git a/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/pom.xml b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/pom.xml index 94c3ab788..fb90bee4c 100644 --- a/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/pom.xml +++ b/m2e-maven-runtime/org.eclipse.m2e.maven.runtime/pom.xml @@ -19,7 +19,7 @@ org.eclipse.m2e.maven.runtime - 1.18.2-SNAPSHOT + 1.19.0-SNAPSHOT eclipse-plugin M2E Embedded Maven Runtime (includes Incubating components) @@ -155,7 +155,7 @@ javax.inject;version="1.0.0" - org.eclipse.m2e.maven.runtime.slf4j.simple;bundle-version="[1.18.0,1.19.0)", + org.eclipse.m2e.maven.runtime.slf4j.simple;bundle-version="[1.18.0,2)", com.google.guava TODO we should generate a - // feature from them! + if (isPomType(artifact)) { + MavenTargetFeature feature = new MavenTargetFeature(new MavenPomFeatureModel(artifact, targetBundles)); + targetBundles.features.add(feature); return; } BNDInstructions bndInstructions = instructionsMap.get(getKey(artifact)); @@ -239,7 +310,7 @@ private void addBundleForArtifact(Artifact artifact, CacheManager cacheManager, public MavenTargetLocation update(IProgressMonitor monitor) throws CoreException { - List latest = new ArrayList<>(); + List latest = new ArrayList(); int updated = 0; for (MavenTargetDependency dependency : roots) { Artifact artifact = new DefaultArtifact( @@ -284,7 +355,7 @@ public VersionRangeResult call(IMavenExecutionContext context, IProgressMonitor } return new MavenTargetLocation(latest, extraRepositories, metadataMode, dependencyScope, includeSource, - instructionsMap.values(), excludedArtifacts); + instructionsMap.values(), excludedArtifacts, featureTemplate); } @@ -294,7 +365,11 @@ public List getRoots() { public MavenTargetLocation withInstructions(Collection instructions) { return new MavenTargetLocation(roots, extraRepositories, metadataMode, dependencyScope, includeSource, - instructions, excludedArtifacts); + instructions, excludedArtifacts, featureTemplate); + } + + public IFeature getFeatureTemplate() { + return featureTemplate; } public BNDInstructions getInstructions(Artifact artifact) { @@ -327,15 +402,18 @@ public int getDependencyCount() { } List getDependencyNodes(MavenTargetDependency dependency) { - return dependencyNodes.get(dependency); + TargetBundles bundles = targetBundles; + if (bundles == null) { + return Collections.emptyList(); + } + return bundles.dependencyNodes.get(dependency); } @Override protected TargetFeature[] resolveFeatures(ITargetDefinition definition, IProgressMonitor monitor) throws CoreException { - // XXX it would be possible to deploy features as maven artifacts, are there any - // examples? - return new TargetFeature[] {}; + return resolveArtifacts(definition, monitor).stream().flatMap(tb -> tb.features.stream()) + .toArray(TargetFeature[]::new); } @Override @@ -350,7 +428,7 @@ public String getLocation(boolean resolve) throws CoreException { @Override public int hashCode() { - return Objects.hash(roots, dependencyNodes, dependencyScope, failedArtifacts, metadataMode); + return Objects.hash(roots, dependencyScope, failedArtifacts, metadataMode); } @Override @@ -365,8 +443,7 @@ public boolean equals(Object obj) { return false; } MavenTargetLocation other = (MavenTargetLocation) obj; - return Objects.equals(roots, other.roots) && Objects.equals(dependencyNodes, other.dependencyNodes) - && Objects.equals(dependencyScope, other.dependencyScope) + return Objects.equals(roots, other.roots) && Objects.equals(dependencyScope, other.dependencyScope) && Objects.equals(failedArtifacts, other.failedArtifacts); } @@ -383,6 +460,12 @@ public String serialize() { attribute(xml, ATTRIBUTE_DEPENDENCY_SCOPE, dependencyScope); attribute(xml, ATTRIBUTE_INCLUDE_SOURCE, includeSource ? "true" : ""); xml.append(">"); + if (featureTemplate != null) { + try (PrintWriter writer = new PrintWriter(new StringBuilderWriter(xml))) { + featureTemplate.write("", writer); + writer.flush(); + } + } if (!roots.isEmpty()) { xml.append("<" + ELEMENT_DEPENDENCIES + ">"); roots.stream().sorted(Comparator.comparing(MavenTargetDependency::getKey)).forEach(dependency -> { @@ -416,9 +499,12 @@ public String serialize() { xml.append(instructions); xml.append("\r\n]]>"); }); - excludedArtifacts.stream().sorted().forEach(ignored -> element(xml, ELEMENT_EXCLUDED, ignored)); + excludedArtifacts.stream().sorted().forEach(ignored -> { + element(xml, ELEMENT_EXCLUDED, ignored); + }); xml.append(""); - return xml.toString(); + String string = xml.toString(); + return string; } private static void element(StringBuilder xml, String name, String value) { @@ -452,7 +538,6 @@ public MissingMetadataMode getMetadataMode() { } public void refresh() { - dependencyNodes.clear(); targetBundles = null; clearResolutionStatus(); } @@ -491,22 +576,15 @@ public void setExcluded(Artifact artifact, boolean disabled) { public MavenTargetBundle getMavenTargetBundle(Artifact artifact) { TargetBundles bundles = targetBundles; if (bundles != null) { - TargetBundle targetBundle = bundles.bundles.get(artifact); - if (targetBundle instanceof MavenTargetBundle) { - return (MavenTargetBundle) targetBundle; - } + return bundles.getTargetBundle(artifact).orElse(null); } return null; } public MavenTargetBundle getMavenTargetBundle(MavenTargetDependency dependency) { - List list = dependencyNodes.get(dependency); - if (list != null) { - for (DependencyNode node : list) { - if (node.getData().get(DEPENDENCYNODE_ROOT) == dependency) { - return getMavenTargetBundle(node.getArtifact()); - } - } + TargetBundles bundles = targetBundles; + if (bundles != null) { + return bundles.getTargetBundle(dependency).orElse(null); } return null; } diff --git a/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MavenTargetLocationFactory.java b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MavenTargetLocationFactory.java index 2000215ab..f5d0f3c69 100644 --- a/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MavenTargetLocationFactory.java +++ b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/MavenTargetLocationFactory.java @@ -16,6 +16,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.stream.IntStream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -25,6 +26,7 @@ import org.eclipse.core.runtime.Status; import org.eclipse.pde.core.target.ITargetLocation; import org.eclipse.pde.core.target.ITargetLocationFactory; +import org.eclipse.pde.internal.core.ifeature.IFeature; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -97,9 +99,13 @@ public ITargetLocation getTargetLocation(String type, String serializedXML) thro excludes.add(((Element) item).getTextContent()); } } + NodeList featuresNodeList = location.getElementsByTagName(MavenTargetLocation.ELEMENT_FEATURE); + IFeature templateFeature = IntStream.range(0, featuresNodeList.getLength()) + .mapToObj(index -> featuresNodeList.item(index)).map(DomXmlFeature::new).findFirst().orElse(null); + return new MavenTargetLocation(dependencies, repositories, mode, dependencyScope, Boolean.parseBoolean(location.getAttribute(MavenTargetLocation.ATTRIBUTE_INCLUDE_SOURCE)), - instructions, excludes); + instructions, excludes, templateFeature); } catch (Exception e) { throw new CoreException(new Status(IStatus.ERROR, MavenTargetLocationFactory.class.getPackage().getName(), e.getMessage(), e)); diff --git a/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/TargetBundles.java b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/TargetBundles.java index cb80eb1cb..f1aa0664e 100644 --- a/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/TargetBundles.java +++ b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/TargetBundles.java @@ -12,13 +12,21 @@ *******************************************************************************/ package org.eclipse.m2e.pde; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; +import org.apache.maven.model.Model; import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.graph.DependencyNode; import org.eclipse.pde.core.target.TargetBundle; +import org.eclipse.pde.core.target.TargetFeature; + +import aQute.bnd.version.Version; /** * represents a resolved set of {@link Artifact} -> {@link TargetBundle} @@ -26,4 +34,56 @@ class TargetBundles { final Map bundles = new HashMap<>(); final Set ignoredArtifacts = new HashSet<>(); + final List features = new ArrayList<>(); + final Map> dependencyNodes = new HashMap<>(); + + Optional getDependencyNode(Artifact artifact) { + return dependencyNodes.values().stream().flatMap(l -> l.stream()) + .filter(node -> artifact.equals(node.getArtifact())).findAny(); + } + + Optional getTargetBundle(Artifact artifact) { + TargetBundle targetBundle = bundles.get(artifact); + if (targetBundle instanceof MavenTargetBundle) { + return Optional.of((MavenTargetBundle) targetBundle); + } + return Optional.empty(); + } + + Optional getTargetBundle(MavenTargetDependency dependency) { + List list = dependencyNodes.get(dependency); + if (list != null) { + Optional artifact = list.stream() + .filter(node -> node.getData().get(MavenTargetLocation.DEPENDENCYNODE_ROOT) == dependency) + .findFirst().map(DependencyNode::getArtifact); + return artifact.flatMap(this::getTargetBundle); + } + return Optional.empty(); + } + + public static Version createOSGiVersion(Artifact artifact) { + String version = artifact.getVersion(); + return createOSGiVersion(version); + } + + public static Version createOSGiVersion(Model model) { + return createOSGiVersion(model.getVersion()); + } + + public static Version createOSGiVersion(String version) { + if (version == null || version.isEmpty()) { + return new Version(0, 0, 1); + } + try { + int index = version.indexOf('-'); + if (index > -1) { + StringBuilder sb = new StringBuilder(version); + sb.setCharAt(index, '.'); + return Version.parseVersion(sb.toString()); + } + return Version.parseVersion(version); + } catch (IllegalArgumentException e) { + return new Version(0, 0, 1, version); + } + } } diff --git a/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/TemplateFeatureModel.java b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/TemplateFeatureModel.java new file mode 100644 index 000000000..e43f345a0 --- /dev/null +++ b/org.eclipse.m2e.pde/src/org/eclipse/m2e/pde/TemplateFeatureModel.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2021 Christoph Läubrich + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Christoph Läubrich - initial API and implementation + *******************************************************************************/ +package org.eclipse.m2e.pde; + +import java.io.ByteArrayInputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.pde.internal.core.NLResourceHelper; +import org.eclipse.pde.internal.core.feature.AbstractFeatureModel; +import org.eclipse.pde.internal.core.feature.Feature; +import org.eclipse.pde.internal.core.ifeature.IFeature; + +/** + * creates a new model by copy the a given {@link IFeature} as its template + */ +@SuppressWarnings("restriction") +public final class TemplateFeatureModel extends AbstractFeatureModel { + + private static final long serialVersionUID = 1L; + private String xml; + private boolean editable = true; + + public TemplateFeatureModel(IFeature template) { + if (template != null) { + StringWriter stringWriter = new StringWriter(); + try (PrintWriter writer = new PrintWriter(stringWriter)) { + template.write("", writer); + writer.flush(); + } + this.xml = stringWriter.toString(); + } + } + + @Override + public synchronized void load() throws CoreException { + if (xml != null && isEditable()) { + load(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)), false); + updateTimeStampWith(System.currentTimeMillis()); + setLoaded(true); + xml = null; + } + } + + @Override + protected NLResourceHelper createNLResourceHelper() { + return null; + } + + @Override + public boolean isEditable() { + return editable; + } + + public void makeReadOnly() { + this.editable = false; + } + + @Override + public IFeature getFeature() { + if (feature == null) { + feature = new TemplateFeature(this); + } + return feature; + } + + private static final class TemplateFeature extends Feature { + + public TemplateFeature(TemplateFeatureModel templateFeatureModel) { + setModel(templateFeatureModel); + } + + @Override + public boolean isValid() { + return hasRequiredAttributes(); + } + } +} diff --git a/target-platform/target-platform.target b/target-platform/target-platform.target index e27bb104d..d41a2b81f 100644 --- a/target-platform/target-platform.target +++ b/target-platform/target-platform.target @@ -26,7 +26,7 @@ - +