From 1daa6ea95c0f2f9c1e1ee90dea3b4378fbfd9aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Wed, 5 Jul 2023 13:24:35 +0200 Subject: [PATCH] Create tycho-repository-plugin to generate standard OSGi repositories --- RELEASE_NOTES.md | 4 + demo/osgi-repository/README.MD | 13 ++ .../maven-repository/.gitignore | 1 + demo/osgi-repository/my-bundle/pom.xml | 39 ++++++ .../java/hello/world/GreetingService.java | 6 + .../main/java/hello/world/package-info.java | 3 + demo/osgi-repository/pom.xml | 15 +++ demo/osgi-repository/repository/pom.xml | 23 ++++ pom.xml | 8 +- .../eclipse/tycho/MavenArtifactNamespace.java | 31 +++++ .../java/org/eclipse/tycho/test/DemoTest.java | 5 + tycho-maven-plugin/pom.xml | 6 - .../.settings/org.eclipse.jdt.core.prefs | 8 ++ tycho-repository-plugin/pom.xml | 71 +++++++++++ .../PackageMavenLifecycleParticipant.java | 53 ++++++++ .../plugin/PackageMavenRepositoryMojo.java | 113 ++++++++++++++++++ .../resources/META-INF/plexus/components.xml | 52 ++++++++ 17 files changed, 444 insertions(+), 7 deletions(-) create mode 100644 demo/osgi-repository/README.MD create mode 100644 demo/osgi-repository/maven-repository/.gitignore create mode 100644 demo/osgi-repository/my-bundle/pom.xml create mode 100644 demo/osgi-repository/my-bundle/src/main/java/hello/world/GreetingService.java create mode 100644 demo/osgi-repository/my-bundle/src/main/java/hello/world/package-info.java create mode 100644 demo/osgi-repository/pom.xml create mode 100644 demo/osgi-repository/repository/pom.xml create mode 100644 tycho-api/src/main/java/org/eclipse/tycho/MavenArtifactNamespace.java create mode 100644 tycho-repository-plugin/.settings/org.eclipse.jdt.core.prefs create mode 100644 tycho-repository-plugin/pom.xml create mode 100644 tycho-repository-plugin/src/main/java/org/eclipse/tycho/repository/plugin/PackageMavenLifecycleParticipant.java create mode 100644 tycho-repository-plugin/src/main/java/org/eclipse/tycho/repository/plugin/PackageMavenRepositoryMojo.java create mode 100644 tycho-repository-plugin/src/main/resources/META-INF/plexus/components.xml diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index aba398832f..fda9d803e6 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -4,6 +4,10 @@ This page describes the noteworthy improvements provided by each release of Ecli ## 5.0.0 (under development) +### new tycho-repository-plugin + +Tycho now contains a new `tycho-repository-plugin` that can be used to package OSGi repositories. + ## 4.0.0 diff --git a/demo/osgi-repository/README.MD b/demo/osgi-repository/README.MD new file mode 100644 index 0000000000..dc872fbc7e --- /dev/null +++ b/demo/osgi-repository/README.MD @@ -0,0 +1,13 @@ +# Publish bundles as an OSGi Repository to maven repository + +This Demo shows how to publish a set of bundles as an OSGi Repository and deploy it to a maven repository (simulated by a folder here), +with this approach it is possible to deploy a whole project consumable by OSGi and maven users with only using the maven repository as the backing store. + +This example uses a single bundle build with bnd-maven-plugin, but actually any jar project that produces a bundle (including Tycho ones) would work! + +As a result of building the project with `mvn clean deploy -DaltDeploymentRepository=snapshot-repo::default::file:maven-repository` you can inspect the following items: + +- find the produced site in `site/target/repository` +- see the deployed artifacts in the file base maven repository under `maven-repository` + +**Currently there is no support in Eclipse/Tycho for consuming such repository!** \ No newline at end of file diff --git a/demo/osgi-repository/maven-repository/.gitignore b/demo/osgi-repository/maven-repository/.gitignore new file mode 100644 index 0000000000..cf1db2eed3 --- /dev/null +++ b/demo/osgi-repository/maven-repository/.gitignore @@ -0,0 +1 @@ +/org/ diff --git a/demo/osgi-repository/my-bundle/pom.xml b/demo/osgi-repository/my-bundle/pom.xml new file mode 100644 index 0000000000..7a3415e5fe --- /dev/null +++ b/demo/osgi-repository/my-bundle/pom.xml @@ -0,0 +1,39 @@ + + 4.0.0 + + org.eclipse.tycho.demo + parent + 1.0.0 + + my-bundle + + 1.8 + 1.8 + + + + org.osgi + org.osgi.annotation.bundle + 2.0.0 + provided + + + + + + biz.aQute.bnd + bnd-maven-plugin + 6.4.0 + true + + + jar + + jar + + + + + + + \ No newline at end of file diff --git a/demo/osgi-repository/my-bundle/src/main/java/hello/world/GreetingService.java b/demo/osgi-repository/my-bundle/src/main/java/hello/world/GreetingService.java new file mode 100644 index 0000000000..ca31645d53 --- /dev/null +++ b/demo/osgi-repository/my-bundle/src/main/java/hello/world/GreetingService.java @@ -0,0 +1,6 @@ +package hello.world; + +public interface GreetingService { + + void sayHello(); +} diff --git a/demo/osgi-repository/my-bundle/src/main/java/hello/world/package-info.java b/demo/osgi-repository/my-bundle/src/main/java/hello/world/package-info.java new file mode 100644 index 0000000000..eb21a24b53 --- /dev/null +++ b/demo/osgi-repository/my-bundle/src/main/java/hello/world/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.bundle.Export +@org.osgi.annotation.versioning.Version("1.0") +package hello.world; \ No newline at end of file diff --git a/demo/osgi-repository/pom.xml b/demo/osgi-repository/pom.xml new file mode 100644 index 0000000000..7a76839048 --- /dev/null +++ b/demo/osgi-repository/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + org.eclipse.tycho.demo + parent + 1.0.0 + pom + + repository + my-bundle + + + 5.0.0-SNAPSHOT + + + diff --git a/demo/osgi-repository/repository/pom.xml b/demo/osgi-repository/repository/pom.xml new file mode 100644 index 0000000000..ac45caa6ab --- /dev/null +++ b/demo/osgi-repository/repository/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + org.eclipse.tycho.demo + parent + 1.0.0 + + repository + repository + + + + org.eclipse.tycho + tycho-repository-plugin + ${tycho-version} + + true + + + + diff --git a/pom.xml b/pom.xml index 50267d4afc..5d8e712c7f 100644 --- a/pom.xml +++ b/pom.xml @@ -67,11 +67,16 @@ 3.9.3 3.9.0 - 3.1.2 3.18.400 3.34.0 6.4.0 + + 2.4.3 + 2.3.1 + 2.5 + 2.4.1 + ${surefire-version} @@ -544,6 +549,7 @@ tycho-apitools-plugin tycho-targetplatform tycho-bnd-plugin + tycho-repository-plugin diff --git a/tycho-api/src/main/java/org/eclipse/tycho/MavenArtifactNamespace.java b/tycho-api/src/main/java/org/eclipse/tycho/MavenArtifactNamespace.java new file mode 100644 index 0000000000..cbd651817f --- /dev/null +++ b/tycho-api/src/main/java/org/eclipse/tycho/MavenArtifactNamespace.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2023 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; + +public class MavenArtifactNamespace { + + /** + * Namespace name for maven artifact capabilities and requirements. + */ + public static final String MAVEN_ARTIFACT_NAMESPACE = "apache.maven.artifact"; + + /** + * The capability attribute identifying the group id. + */ + public static final String CAPABILITY_GROUP_ATTRIBUTE = "group"; + + /** + * The capability attribute identifying the {@code Version} of the artifact. + */ + public static final String CAPABILITY_VERSION_ATTRIBUTE = "version"; +} diff --git a/tycho-its/src/test/java/org/eclipse/tycho/test/DemoTest.java b/tycho-its/src/test/java/org/eclipse/tycho/test/DemoTest.java index f12bbaa5ce..dba3c902be 100644 --- a/tycho-its/src/test/java/org/eclipse/tycho/test/DemoTest.java +++ b/tycho-its/src/test/java/org/eclipse/tycho/test/DemoTest.java @@ -67,6 +67,11 @@ public void testP2MavenRepositoryDemo() throws Exception { runDemo("p2-maven-site", "deploy", "-DaltDeploymentRepository=snapshot-repo::default::file:maven-repository"); } + @Test + public void testOsgiMavenRepositoryDemo() throws Exception { + runDemo("osgi-repository", "deploy", "-DaltDeploymentRepository=snapshot-repo::default::file:maven-repository"); + } + protected Verifier runDemo(String test, String... xargs) throws Exception { Verifier verifier = super.getVerifier("../../demo/" + test, true, true); for (String xarg : xargs) { diff --git a/tycho-maven-plugin/pom.xml b/tycho-maven-plugin/pom.xml index c07455c4dc..0033622337 100644 --- a/tycho-maven-plugin/pom.xml +++ b/tycho-maven-plugin/pom.xml @@ -37,12 +37,6 @@ - - 2.4.3 - 2.3.1 - 2.5 - 2.4.1 - ${surefire-version} diff --git a/tycho-repository-plugin/.settings/org.eclipse.jdt.core.prefs b/tycho-repository-plugin/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..cf2cd4590a --- /dev/null +++ b/tycho-repository-plugin/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=17 diff --git a/tycho-repository-plugin/pom.xml b/tycho-repository-plugin/pom.xml new file mode 100644 index 0000000000..551bd0f8dd --- /dev/null +++ b/tycho-repository-plugin/pom.xml @@ -0,0 +1,71 @@ + + 4.0.0 + + org.eclipse.tycho + tycho + 5.0.0-SNAPSHOT + + tycho-repository-plugin + Tycho Repository Plugin + Mojos dedicated to creating OSGi Repositories + maven-plugin + + ${minimal-maven-version} + + + + org.apache.maven + maven-core + + + org.apache.maven + maven-plugin-api + + + org.apache.maven.plugin-tools + maven-plugin-annotations + + + org.eclipse.tycho + tycho-api + ${project.version} + + + biz.aQute.bnd + biz.aQute.bndlib + + + org.osgi + org.osgi.service.repository + 1.1.0 + + + org.osgi + org.osgi.util.function + 1.2.0 + + + org.osgi + org.osgi.util.promise + 1.3.0 + + + + + + org.codehaus.plexus + plexus-component-metadata + + ${project.build.directory}/filtered/META-INF/plexus/ + + + + + + src/main/resources + true + ${project.build.directory}/filtered + + + + \ No newline at end of file diff --git a/tycho-repository-plugin/src/main/java/org/eclipse/tycho/repository/plugin/PackageMavenLifecycleParticipant.java b/tycho-repository-plugin/src/main/java/org/eclipse/tycho/repository/plugin/PackageMavenLifecycleParticipant.java new file mode 100644 index 0000000000..324cdf3272 --- /dev/null +++ b/tycho-repository-plugin/src/main/java/org/eclipse/tycho/repository/plugin/PackageMavenLifecycleParticipant.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2023 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.repository.plugin; + +import java.util.List; + +import org.apache.maven.AbstractMavenLifecycleParticipant; +import org.apache.maven.MavenExecutionException; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.model.Dependency; +import org.apache.maven.model.Plugin; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.component.annotations.Component; + +@Component(role = AbstractMavenLifecycleParticipant.class) +public class PackageMavenLifecycleParticipant extends AbstractMavenLifecycleParticipant { + + @Override + public void afterProjectsRead(MavenSession session) throws MavenExecutionException { + List projects = session.getProjects(); + for (MavenProject project : projects) { + if ("repository".equals(project.getPackaging()) && project.getPlugin("org.eclipse.tycho:tycho-repository-plugin") != null) { + addInterestingProjects(project, projects); + } + } + } + + private void addInterestingProjects(MavenProject project, List projects) { + for (MavenProject other : projects) { + if (other == project) { + continue; + } + if (PackageMavenRepositoryMojo.isInteresting(other)) { + Dependency dependency = new Dependency(); + dependency.setGroupId(other.getGroupId()); + dependency.setArtifactId(other.getArtifactId()); + dependency.setVersion(other.getVersion()); + project.getModel().addDependency(dependency); + } + } + } + +} diff --git a/tycho-repository-plugin/src/main/java/org/eclipse/tycho/repository/plugin/PackageMavenRepositoryMojo.java b/tycho-repository-plugin/src/main/java/org/eclipse/tycho/repository/plugin/PackageMavenRepositoryMojo.java new file mode 100644 index 0000000000..ae771679bb --- /dev/null +++ b/tycho-repository-plugin/src/main/java/org/eclipse/tycho/repository/plugin/PackageMavenRepositoryMojo.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2023 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.repository.plugin; + +import java.io.File; +import java.io.IOException; +import java.net.URI; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.handler.DefaultArtifactHandler; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.eclipse.tycho.ArtifactType; +import org.eclipse.tycho.MavenArtifactNamespace; + +import aQute.bnd.osgi.repository.XMLResourceGenerator; +import aQute.bnd.osgi.resource.CapReqBuilder; +import aQute.bnd.osgi.resource.ResourceBuilder; + +/** + * Generates an OSGi repository from the current reactor projects + * + */ +@Mojo(name = "package-maven-repository") +public class PackageMavenRepositoryMojo extends AbstractMojo { + + @Parameter(property = "session", readonly = true) + protected MavenSession session; + + /** + *

+ * The name attribute stored in the created p2 repository. + *

+ */ + @Parameter(defaultValue = "${project.name}") + private String repositoryName; + + /** + * Specify the filename of the additionally generated OSGi Repository (if + * enabled) + */ + @Parameter(defaultValue = "repository.xml") + private String repositoryFileName; + + @Parameter(defaultValue = "${project.build.directory}") + private File destination; + + @Parameter(property = "project", readonly = true) + private MavenProject project; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + XMLResourceGenerator resourceGenerator = new XMLResourceGenerator(); + resourceGenerator.name(repositoryName); + for (MavenProject project : session.getProjects()) { + if (isInteresting(project)) { + ResourceBuilder rb = new ResourceBuilder(); + try { + if (rb.addFile(project.getArtifact().getFile(), new URI("mvn:" + project.getGroupId() + ":" + + project.getArtifactId() + ":" + project.getVersion()))) { + CapReqBuilder identity = new CapReqBuilder(MavenArtifactNamespace.MAVEN_ARTIFACT_NAMESPACE) + .addAttribute(MavenArtifactNamespace.CAPABILITY_GROUP_ATTRIBUTE, project.getGroupId()) + .addAttribute(MavenArtifactNamespace.MAVEN_ARTIFACT_NAMESPACE, project.getArtifactId()) + .addAttribute(MavenArtifactNamespace.CAPABILITY_VERSION_ATTRIBUTE, + project.getVersion()); + rb.addCapability(identity); + resourceGenerator.resource(rb.build()); + getLog().info("Adding " + project.getId()); + } else { + getLog().info("Skip " + project.getId() + ": Not a bundle"); + } + } catch (Exception e) { + Log log = getLog(); + log.warn("Ignoring " + project.getId() + ": " + e, log.isDebugEnabled() ? e : null); + } + } + } + try { + File location = new File(destination, repositoryFileName); + resourceGenerator.save(location); + Artifact artifact = project.getArtifact(); + artifact.setArtifactHandler(new DefaultArtifactHandler("xml")); + artifact.setFile(location); + } catch (IOException e) { + throw new MojoExecutionException("Could not write OSGi Repository!", e); + } + } + + public static boolean isInteresting(MavenProject other) { + String packaging = other.getPackaging(); + return "jar".equalsIgnoreCase(packaging) || "bundle".equalsIgnoreCase(packaging) + || ArtifactType.TYPE_ECLIPSE_PLUGIN.equals(packaging) + || ArtifactType.TYPE_BUNDLE_FRAGMENT.equals(packaging) + || ArtifactType.TYPE_ECLIPSE_TEST_PLUGIN.equals(packaging); + } + +} diff --git a/tycho-repository-plugin/src/main/resources/META-INF/plexus/components.xml b/tycho-repository-plugin/src/main/resources/META-INF/plexus/components.xml new file mode 100644 index 0000000000..7d4a3d00c1 --- /dev/null +++ b/tycho-repository-plugin/src/main/resources/META-INF/plexus/components.xml @@ -0,0 +1,52 @@ + + + + org.apache.maven.lifecycle.mapping.LifecycleMapping + repository + + org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping + + + + + default + + + + + + + org.apache.maven.plugins:maven-resources-plugin:${resources-plugin.version}:resources + + + + + + + + + + + + + + + org.eclipse.tycho:tycho-repository-plugin:${project.version}:package-maven-repository + + + + + + + org.apache.maven.plugins:maven-install-plugin:${install-plugin.version}:install + + + org.apache.maven.plugins:maven-deploy-plugin:${deploy-plugin.version}:deploy + + + + + + + +