From 46da72942e3ee3f2ea33fe3e69983a1fa85442df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Mon, 22 Jan 2024 06:16:58 +0100 Subject: [PATCH] Add support to specify target locations in the pom configuration Currently one can either define a target reference as a file or artefact this now adds support to also add locations directly to the pom xml configuration. --- RELEASE_NOTES.md | 40 +++++++++++++++++-- .../tycho/target/TargetParameterObject.java | 2 + .../TargetPlatformConfigurationMojo.java | 1 + .../core/TargetPlatformConfiguration.java | 21 ++++++++++ ...aultTargetPlatformConfigurationReader.java | 19 ++++++--- .../targetplatform/TargetDefinitionFile.java | 38 ++++++++++++++++-- 6 files changed, 108 insertions(+), 13 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index f9ea79cb7a..ea5ba733d6 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -6,6 +6,40 @@ If you are reading this in the browser, then you can quickly jump to specific ve ## 5.0.0 (under development) +### support for embedded target locations + +You can already define target definition files in various ways, e.g. as maven artifact or file reference, +now it is also possible to define them as an embedded part of the target platform configuration, +all locations are handled as if they are part of a single target file: + +```xml + + org.eclipse.tycho + target-platform-configuration + ${tycho-version} + + + + + + + ... + + + + + + ... + + + ... + + + +``` + +this is especially useful if you need some content only for the build but not in the IDE. + ### using javac as the compiler for Tycho You can now use `javac` as the compiler backend for Tycho by adding the following configuration: @@ -19,7 +53,7 @@ You can now use `javac` as the compiler backend for Tycho by adding the followin javac - ``` +``` ### new `mirror-target-platform` @@ -39,7 +73,7 @@ There is a new `mirror-target-platform` that allows to mirror the current target - ``` +``` the most usual use-case for this is to transform an existing target-file into a standalone repository. @@ -68,7 +102,7 @@ This mojo can be used in two ways: - ``` +``` ### new `tycho-eclipse-plugin` diff --git a/target-platform-configuration/src/main/java/org/eclipse/tycho/target/TargetParameterObject.java b/target-platform-configuration/src/main/java/org/eclipse/tycho/target/TargetParameterObject.java index 1bb03d319f..5e48ab4615 100644 --- a/target-platform-configuration/src/main/java/org/eclipse/tycho/target/TargetParameterObject.java +++ b/target-platform-configuration/src/main/java/org/eclipse/tycho/target/TargetParameterObject.java @@ -12,6 +12,7 @@ import java.io.File; import java.net.URI; +import org.codehaus.plexus.configuration.PlexusConfiguration; import org.eclipse.tycho.p2.repository.GAV; /** @@ -23,4 +24,5 @@ public class TargetParameterObject { public GAV target; public File file; public URI uri; + public PlexusConfiguration location; } diff --git a/target-platform-configuration/src/main/java/org/eclipse/tycho/target/TargetPlatformConfigurationMojo.java b/target-platform-configuration/src/main/java/org/eclipse/tycho/target/TargetPlatformConfigurationMojo.java index 5b8a39a0f7..23cd5b3d51 100644 --- a/target-platform-configuration/src/main/java/org/eclipse/tycho/target/TargetPlatformConfigurationMojo.java +++ b/target-platform-configuration/src/main/java/org/eclipse/tycho/target/TargetPlatformConfigurationMojo.java @@ -89,6 +89,7 @@ public class TargetPlatformConfigurationMojo extends AbstractMojo { *
  • <file> to define a file local to the build
  • *
  • <uri> to define a (remote) URI that specifies a target, currently only * URIs that can be converted to URLs are supported (e.g. file:/.... http://..., )
  • + *
  • {@code } to define target locations inline
  • * */ @Parameter(name = DefaultTargetPlatformConfigurationReader.TARGET) diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/TargetPlatformConfiguration.java b/tycho-core/src/main/java/org/eclipse/tycho/core/TargetPlatformConfiguration.java index 9e4ae8ffdf..26a450f199 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/TargetPlatformConfiguration.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/TargetPlatformConfiguration.java @@ -17,7 +17,9 @@ import java.io.File; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Base64; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -28,6 +30,7 @@ import java.util.Set; import java.util.function.Supplier; +import org.codehaus.plexus.util.xml.Xpp3Dom; import org.eclipse.equinox.p2.metadata.IRequirement; import org.eclipse.tycho.ArtifactKey; import org.eclipse.tycho.OptionalResolutionAction; @@ -121,6 +124,8 @@ public enum InjectP2MavenMetadataHandling { private ReferencedRepositoryMode referencedRepositoryMode = ReferencedRepositoryMode.include; + private List xmlFragments = new ArrayList<>(); + /** * Returns the list of configured target environments, or the running environment if no * environments have been specified explicitly. @@ -141,6 +146,18 @@ public synchronized List getTargets() { targets.add(supplier.get().toURI()); iterator.remove(); } + if (!xmlFragments.isEmpty()) { + Xpp3Dom target = new Xpp3Dom("target"); + Xpp3Dom locations = new Xpp3Dom(TargetDefinitionFile.ELEMENT_LOCATIONS); + target.addChild(locations); + for (Xpp3Dom location : xmlFragments) { + locations.addChild(new Xpp3Dom(location)); + } + String collect = target.toString(); + targets.add(URI.create("data:" + TargetDefinitionFile.APPLICATION_TARGET + ";base64," + + Base64.getEncoder().encodeToString(collect.getBytes(StandardCharsets.UTF_8)))); + xmlFragments.clear(); + } return targets.stream().map(TargetDefinitionFile::read).toList(); } @@ -319,4 +336,8 @@ public void setReferencedRepositoryMode(ReferencedRepositoryMode referencedRepos this.referencedRepositoryMode = referencedRepositoryMode; } + public void addTargetLocation(Xpp3Dom locationDom) { + xmlFragments.add(locationDom); + } + } diff --git a/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/DefaultTargetPlatformConfigurationReader.java b/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/DefaultTargetPlatformConfigurationReader.java index 169ea2941a..c9cd9d6863 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/DefaultTargetPlatformConfigurationReader.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/core/resolver/DefaultTargetPlatformConfigurationReader.java @@ -331,10 +331,10 @@ private void setBREEHeaderSelectionPolicy(TargetPlatformConfiguration result, Xp /** * Take the constraints of the configured execution environment into account when resolving - * dependencies or target definitions. These constraints include the list of system packages and the - * Bundle-RequiredExecutionEnvironment header. When set to true, the - * dependency resolution verifies that the bundle and all required bundles can be used in an OSGi - * container with the configured execution environment. + * dependencies or target definitions. These constraints include the list of system packages and + * the Bundle-RequiredExecutionEnvironment header. When set to true, the + * dependency resolution verifies that the bundle and all required bundles can be used in an + * OSGi container with the configured execution environment. */ private void setResolveWithEEContraints(TargetPlatformConfiguration result, Xpp3Dom resolverDom) { String value = getStringValue(resolverDom.getChild(RESOLVE_WITH_EXECUTION_ENVIRONMENT_CONSTRAINTS)); @@ -462,6 +462,13 @@ private void setTarget(TargetPlatformConfiguration result, MavenSession session, } } } + Xpp3Dom[] locationsArray = targetDom.getChildren("location"); + if (locationsArray != null && locationsArray.length > 0) { + for (Xpp3Dom locationDom : locationsArray) { + result.addTargetLocation(locationDom); + } + } + } protected void addTargetArtifact(TargetPlatformConfiguration result, MavenSession session, MavenProject project, @@ -592,9 +599,9 @@ private static String getStringValue(Xpp3Dom element) { * * @param project * @param targetFile - * the target file to check + * the target file to check * @param otherTargetFiles - * other target files to take into account + * other target files to take into account * @return true if the target file is the primary artifact, false * otherwise */ diff --git a/tycho-targetplatform/src/main/java/org/eclipse/tycho/targetplatform/TargetDefinitionFile.java b/tycho-targetplatform/src/main/java/org/eclipse/tycho/targetplatform/TargetDefinitionFile.java index 0cda363213..53549f0cd5 100644 --- a/tycho-targetplatform/src/main/java/org/eclipse/tycho/targetplatform/TargetDefinitionFile.java +++ b/tycho-targetplatform/src/main/java/org/eclipse/tycho/targetplatform/TargetDefinitionFile.java @@ -21,14 +21,17 @@ package org.eclipse.tycho.targetplatform; import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; +import java.net.MalformedURLException; import java.net.URI; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Base64; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; @@ -65,7 +68,8 @@ public final class TargetDefinitionFile implements TargetDefinition { - private static final Map FILE_CACHE = new ConcurrentHashMap<>(); + public static final String ELEMENT_LOCATIONS = "locations"; + private static final Map FILE_CACHE = new ConcurrentHashMap<>(); //just for information purpose private final String origin; @@ -75,6 +79,7 @@ public final class TargetDefinitionFile implements TargetDefinition { private String targetEE; public static final String FILE_EXTENSION = ".target"; + public static final String APPLICATION_TARGET = "application/target"; private abstract static class AbstractPathLocation implements TargetDefinition.PathLocation { private String path; @@ -554,8 +559,8 @@ public static TargetDefinitionFile read(URI uri) { try { return FILE_CACHE.computeIfAbsent(uri.normalize(), key -> { try { - try (InputStream input = uri.toURL().openStream()) { - return parse(parseDocument(input), uri.toASCIIString()); + try (InputStream input = openTargetStream(uri)) { + return parse(parseDocument(input), getOrigin(uri)); } catch (ParserConfigurationException e) { throw new TargetDefinitionSyntaxException("No valid XML parser: " + e.getMessage(), e); } catch (SAXException e) { @@ -573,6 +578,31 @@ public static TargetDefinitionFile read(URI uri) { } } + private static String getOrigin(URI uri) { + if (isDataUrl(uri)) { + return ""; + } + return uri.toASCIIString(); + } + + private static InputStream openTargetStream(URI uri) throws IOException, MalformedURLException { + if (isDataUrl(uri)) { + String rawPath = uri.toASCIIString(); + int indexOf = rawPath.indexOf(','); + if (indexOf > -1) { + String data = rawPath.substring(indexOf + 1); + return new ByteArrayInputStream(Base64.getDecoder().decode(data)); + } else { + throw new MalformedURLException("invalid data url!"); + } + } + return uri.toURL().openStream(); + } + + private static boolean isDataUrl(URI uri) { + return "data".equals(uri.getScheme()); + } + public static TargetDefinitionFile parse(Document document, String origin) { return new TargetDefinitionFile(document, origin); } @@ -618,7 +648,7 @@ public static boolean isTargetFile(File file) { private static List parseLocations(Element dom) { ArrayList locations = new ArrayList<>(); - Element locationsDom = getChild(dom, "locations"); + Element locationsDom = getChild(dom, ELEMENT_LOCATIONS); if (locationsDom != null) { for (Element locationDom : getChildren(locationsDom, "location")) { String type = locationDom.getAttribute("type");