adding MetadataBuilderMojo
diff --git a/winegrower-extension/winegrower-build/winegrower-build-common/src/main/java/org/apache/winegrower/extension/build/common/FatJar.java b/winegrower-extension/winegrower-build/winegrower-build-common/src/main/java/org/apache/winegrower/extension/build/common/FatJar.java
index 25119c0..7fe34a4 100644
--- a/winegrower-extension/winegrower-build/winegrower-build-common/src/main/java/org/apache/winegrower/extension/build/common/FatJar.java
+++ b/winegrower-extension/winegrower-build/winegrower-build-common/src/main/java/org/apache/winegrower/extension/build/common/FatJar.java
@@ -14,25 +14,19 @@
package org.apache.winegrower.extension.build.common;
import static java.util.Objects.requireNonNull;
-import static java.util.stream.Collectors.joining;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
-import java.util.Properties;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
-import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
public class FatJar implements Runnable {
@@ -49,21 +43,12 @@
try (final JarOutputStream outputStream = new JarOutputStream(
new BufferedOutputStream(new FileOutputStream(configuration.output)))) {
- final Properties manifests = new Properties();
- final Properties index = new Properties();
+ final MetadataBuilder metadataBuilder = new MetadataBuilder();
byte[] buffer = new byte[8192];
final Set<String> alreadyAdded = new HashSet<>();
configuration.jars.forEach(shadedJar -> {
- final Collection<String> files = new ArrayList<>();
try (final JarInputStream inputStream = new JarInputStream(new BufferedInputStream(new FileInputStream(shadedJar)))) {
- final Manifest manifest = inputStream.getManifest();
- if (manifest != null) {
- try (final ByteArrayOutputStream manifestStream = new ByteArrayOutputStream()) {
- manifest.write(manifestStream);
- manifestStream.flush();
- manifests.put(shadedJar.getName(), new String(manifestStream.toByteArray(), StandardCharsets.UTF_8));
- }
- }
+ metadataBuilder.onJar(shadedJar.getName(), inputStream);
ZipEntry nextEntry;
while ((nextEntry = inputStream.getNextEntry()) != null) {
@@ -71,7 +56,7 @@
if (!alreadyAdded.add(name)) {
continue;
}
- files.add(name);
+ metadataBuilder.onFile(name);
outputStream.putNextEntry(nextEntry);
int count;
while ((count = inputStream.read(buffer, 0, buffer.length)) >= 0) {
@@ -84,19 +69,21 @@
} catch (final IOException e) {
throw new IllegalStateException(e);
}
- index.put(shadedJar.getName(), files.stream().collect(joining(",")));
+ metadataBuilder.afterJar();
});
outputStream.putNextEntry(new JarEntry("WINEGROWER-INF/"));
outputStream.closeEntry();
- outputStream.putNextEntry(new JarEntry("WINEGROWER-INF/index.properties"));
- index.store(outputStream, "index");
- outputStream.closeEntry();
-
- outputStream.putNextEntry(new JarEntry("WINEGROWER-INF/manifests.properties"));
- manifests.store(outputStream, "manifests");
- outputStream.closeEntry();
+ metadataBuilder.getMetadata().forEach((key, value) -> {
+ try {
+ outputStream.putNextEntry(new JarEntry("WINEGROWER-INF/" + key + ".properties"));
+ value.store(outputStream, "index");
+ outputStream.closeEntry();
+ } catch (final IOException ioe) {
+ throw new IllegalStateException(ioe);
+ }
+ });
} catch (final IOException e) {
throw new IllegalStateException(e);
}
diff --git a/winegrower-extension/winegrower-build/winegrower-build-common/src/main/java/org/apache/winegrower/extension/build/common/MetadataBuilder.java b/winegrower-extension/winegrower-build/winegrower-build-common/src/main/java/org/apache/winegrower/extension/build/common/MetadataBuilder.java
new file mode 100644
index 0000000..9191cdc
--- /dev/null
+++ b/winegrower-extension/winegrower-build/winegrower-build-common/src/main/java/org/apache/winegrower/extension/build/common/MetadataBuilder.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.winegrower.extension.build.common;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+public class MetadataBuilder {
+ private final Properties manifests = new Properties();
+ private final Properties index = new Properties();
+
+ private String currentJar;
+ private List<String> files;
+
+ public Map<String, Properties> getMetadata() {
+ final HashMap<String, Properties> meta = new HashMap<>();
+ meta.put("index", index);
+ meta.put("manifests", manifests);
+ return meta;
+ }
+
+ public void onJar(final String jarName, final JarInputStream jarInputStream) {
+ final Manifest manifest = jarInputStream.getManifest();
+ if (manifest != null) {
+ try (final ByteArrayOutputStream manifestStream = new ByteArrayOutputStream()) {
+ manifest.write(manifestStream);
+ manifestStream.flush();
+ manifests.put(jarName, new String(manifestStream.toByteArray(), StandardCharsets.UTF_8));
+ } catch (final IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ this.currentJar = jarName;
+ this.files = new ArrayList<>();
+ }
+
+ public void onFile(final String name) {
+ files.add(name);
+ }
+
+ public void afterJar() {
+ index.put(currentJar, String.join(",", files));
+ currentJar = null;
+ files = null;
+ }
+}
diff --git a/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/asciidoc/index.adoc b/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/asciidoc/index.adoc
index 6fa116b..ecceb10 100644
--- a/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/asciidoc/index.adoc
+++ b/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/asciidoc/index.adoc
@@ -121,6 +121,28 @@
|workDir|File|winegrower.workDir|${project.build.directory}/${project.artifactId}-distribution|Where the distribution is built during the build.
|===
+== Generate Winegrower metadata
+
+When you build a Fatjar, Winegrower uses metadata to respect the jar bundle modularity.
+It can be neat to generate these metadata without generating a fatjar - for GraalVM for example.
+To do that, you can use `metadata` mojo.
+
+[source,sh]
+----
+mvn winegrower:metadata
+----
+
+=== Configuration
+
+[cols="e,m,m,m,a",headers]
+|===
+|Name|Type|Property|Default|Description
+|buildArtifact|File|winegrower.buildArtifact|${project.build.directory}/${project.build.finalName}.${project.packaging}.|Path of the project artifact if any.
+|includeScopes|Collection<String>|winegrower.includeScopes|provided,compile,runtime|The scopes included in the produced artifact.
+|output|File|winegrower.metadata.output|${project.build.outputDirectory}|Where to dump metadata.
+|namingPattern|String|winegrower.metadata.namingPattern|WINEGROWER-INF/%s.properties|Naming pattern for each metadata - relative to output directory.
+|===
+
== From Winegrower no-manifest deployment to OSGi deployments
Winegrower supports some custom API not requiring a full OSGi packaging
diff --git a/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/BaseClasspathMojo.java b/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/BaseClasspathMojo.java
new file mode 100644
index 0000000..339e0b6
--- /dev/null
+++ b/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/BaseClasspathMojo.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.winegrower.extension.build.maven;
+
+import static java.util.stream.Collectors.toList;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+
+public abstract class BaseClasspathMojo extends AbstractMojo {
+ @Parameter(defaultValue = "${project}", readonly = true, required = true)
+ protected MavenProject project;
+
+ @Parameter(defaultValue = "provided,compile,runtime", property = "winegrower.includeScopes")
+ private Collection<String> includeScopes;
+
+ @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.${project.packaging}", property = "winegrower.buildArtifact")
+ private File buildArtifact;
+
+ protected Collection<File> collectJars() {
+ return Stream.concat(
+ project.getArtifacts().stream()
+ .filter(it -> includeScopes.contains(it.getScope()))
+ .map(Artifact::getFile),
+ Stream.of(buildArtifact))
+ .filter(Objects::nonNull)
+ .filter(File::exists)
+ .collect(toList());
+ }
+}
diff --git a/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/FatJarMojo.java b/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/FatJarMojo.java
index f06b11a..4721ff8 100644
--- a/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/FatJarMojo.java
+++ b/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/FatJarMojo.java
@@ -13,31 +13,18 @@
*/
package org.apache.winegrower.extension.build.maven;
-import static java.util.stream.Collectors.toList;
import static org.apache.maven.plugins.annotations.ResolutionScope.RUNTIME_PLUS_SYSTEM;
import java.io.File;
-import java.util.Collection;
-import java.util.Objects;
-import java.util.stream.Stream;
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
-import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.apache.winegrower.extension.build.common.FatJar;
@Mojo(name = "fatjar", requiresDependencyResolution = RUNTIME_PLUS_SYSTEM)
-public class FatJarMojo extends AbstractMojo {
- @Parameter(defaultValue = "${project}", readonly = true, required = true)
- private MavenProject project;
-
- @Parameter(defaultValue = "provided,compile,runtime", property = "winegrower.includeScopes")
- private Collection<String> includeScopes;
-
+public class FatJarMojo extends BaseClasspathMojo {
@Parameter(defaultValue = "${project.build.directory}/${project.artifactId}-fatjar.jar", property = "winegrower.output")
private File output;
@@ -47,9 +34,6 @@
@Parameter(defaultValue = "fatjar", property = "winegrower.classifier")
private String classifier;
- @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.${project.packaging}", property = "winegrower.buildArtifact")
- private File buildArtifact;
-
@Component
private MavenProjectHelper helper;
@@ -60,15 +44,4 @@
helper.attachArtifact(project, output, classifier);
}
}
-
- private Collection<File> collectJars() {
- return Stream.concat(
- project.getArtifacts().stream()
- .filter(it -> includeScopes.contains(it.getScope()))
- .map(Artifact::getFile),
- Stream.of(buildArtifact))
- .filter(Objects::nonNull)
- .filter(File::exists)
- .collect(toList());
- }
}
diff --git a/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/MetadataBuilderMojo.java b/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/MetadataBuilderMojo.java
new file mode 100644
index 0000000..d38ecfe
--- /dev/null
+++ b/winegrower-extension/winegrower-build/winegrower-maven-plugin/src/main/java/org/apache/winegrower/extension/build/maven/MetadataBuilderMojo.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.winegrower.extension.build.maven;
+
+import static org.apache.maven.plugins.annotations.ResolutionScope.RUNTIME_PLUS_SYSTEM;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarInputStream;
+import java.util.zip.ZipEntry;
+
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.winegrower.extension.build.common.MetadataBuilder;
+
+@Mojo(name = "metadata", requiresDependencyResolution = RUNTIME_PLUS_SYSTEM)
+public class MetadataBuilderMojo extends BaseClasspathMojo {
+ @Parameter(defaultValue = "${project.build.outputDirectory}", property = "winegrower.metadata.output")
+ private File output;
+
+ @Parameter(defaultValue = "WINEGROWER-INF/%s.properties", property = "winegrower.metadata.namingPattern")
+ private String namingPattern;
+
+ @Override
+ public void execute() {
+ final MetadataBuilder metadataBuilder = new MetadataBuilder();
+ final Set<String> alreadyAdded = new HashSet<>();
+ collectJars().forEach(jar -> {
+ try (final JarInputStream inputStream = new JarInputStream(new BufferedInputStream(new FileInputStream(jar)))) {
+ metadataBuilder.onJar(jar.getName(), inputStream);
+
+ ZipEntry nextEntry;
+ while ((nextEntry = inputStream.getNextEntry()) != null) {
+ final String name = nextEntry.getName();
+ if (!alreadyAdded.add(name)) {
+ continue;
+ }
+ metadataBuilder.onFile(name);
+ }
+ } catch (final IOException e) {
+ throw new IllegalStateException(e);
+ }
+ metadataBuilder.afterJar();
+ });
+
+ metadataBuilder.getMetadata().forEach((key, value) -> {
+ final Path target = output.toPath().resolve(String.format(namingPattern, key));
+ try {
+ if (!Files.exists(target.getParent())) {
+ Files.createDirectories(target.getParent());
+ }
+ try (final OutputStream out = Files.newOutputStream(target)) {
+ value.store(out, "index");
+ }
+ getLog().info("Generated '" + target + "'");
+ } catch (final IOException ioe) {
+ throw new IllegalStateException(ioe);
+ }
+ });
+ }
+}