From 4a4d1f91df267330c152ab619a3f186840efed4b Mon Sep 17 00:00:00 2001 From: Peter Kriens Date: Sun, 24 Dec 2023 15:27:49 +0100 Subject: [PATCH] Added an option to add a directory as a jar/zip file --- Signed-off-by: Peter Kriens Signed-off-by: Peter Kriens --- .../test/test/IncludeResourceTest.java | 6 +++ .../src/aQute/bnd/osgi/Builder.java | 50 +++++++++++++------ .../src/aQute/bnd/osgi/DirectoryResource.java | 40 +++++++++++++++ docs/_instructions/includeresource.md | 8 ++- 4 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 biz.aQute.bndlib/src/aQute/bnd/osgi/DirectoryResource.java diff --git a/biz.aQute.bndlib.tests/test/test/IncludeResourceTest.java b/biz.aQute.bndlib.tests/test/test/IncludeResourceTest.java index 6e0295da21..717154cd17 100644 --- a/biz.aQute.bndlib.tests/test/test/IncludeResourceTest.java +++ b/biz.aQute.bndlib.tests/test/test/IncludeResourceTest.java @@ -119,6 +119,12 @@ public void testIncludeResourceFromUrl() throws Exception { Set excludeOneFile = testResources("@" + uri + "!/!LICENSE", 528 - 1); } + @Test + public void testIncludeResourceDirectoryToJar() throws Exception { + Set jar = testResources("foo.jar=@jar", 1); + assertThat(jar).containsExactlyInAnyOrder("foo.jar"); + } + @Test public void testIncludeResourceFromClasspathJars() throws Exception { Set deflt = testResources("@osgi.jar", 528); diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/Builder.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/Builder.java index 911da7b6ca..950761be8e 100644 --- a/biz.aQute.bndlib/src/aQute/bnd/osgi/Builder.java +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/Builder.java @@ -1,6 +1,11 @@ package aQute.bnd.osgi; import static aQute.bnd.exceptions.FunctionWithException.asFunction; +import static aQute.libg.re.Catalog.caseInsenstive; +import static aQute.libg.re.Catalog.eof; +import static aQute.libg.re.Catalog.lit; +import static aQute.libg.re.Catalog.or; +import static aQute.libg.re.Catalog.setAll; import static java.util.stream.Collectors.toList; import java.io.File; @@ -71,6 +76,7 @@ import aQute.lib.strings.Strings; import aQute.lib.zip.ZipUtil; import aQute.libg.generics.Create; +import aQute.libg.re.RE; /** * Include-Resource: ( [name '=' ] file )+ Private-Package: package-decl ( ',' @@ -80,7 +86,8 @@ public class Builder extends Analyzer { @SuppressWarnings("deprecation") - private static final String INCLUDERESOURCE_HEADERS = Constants.INCLUDERESOURCE + "|" + Constants.INCLUDE_RESOURCE; + private static final String INCLUDERESOURCE_HEADERS = Constants.INCLUDERESOURCE + "|" + + Constants.INCLUDE_RESOURCE; private final static Logger logger = LoggerFactory.getLogger(Builder.class); private final static Pattern IR_PATTERN = Pattern @@ -376,14 +383,16 @@ private void doSaveManifest(Jar dot) throws Exception { } } - protected void changedFile(@SuppressWarnings("unused") File f) {} + protected void changedFile(@SuppressWarnings("unused") + File f) {} /** * Sign the jar file. -sign : [ ';' 'password:=' ] [ ';' * 'keystore:=' ] [ ';' 'sign-password:=' ] ( ',' ... )* */ - void sign(@SuppressWarnings("unused") Jar jar) throws Exception { + void sign(@SuppressWarnings("unused") + Jar jar) throws Exception { String signing = getProperty(SIGN); if (signing == null) return; @@ -608,7 +617,8 @@ public Collection getSourcePath() { return sourcePath; } - private void doVerify(@SuppressWarnings("unused") Jar dot) throws Exception { + private void doVerify(@SuppressWarnings("unused") + Jar dot) throws Exception { // Give the verifier the benefit of our analysis // prevents parsing the files twice @@ -666,11 +676,11 @@ else if (Logic.hasOverlap(testpackage.keySet(), unused)) else if (Logic.hasOverlap(includepackage.keySet(), unused)) header = Constants.INCLUDEPACKAGE; - warning( - "Unused %s instructions , no such package(s) on the class path: %s", header, unused).header(header) - .context(unused.iterator() - .next() - .getInput()); + warning("Unused %s instructions , no such package(s) on the class path: %s", header, unused) + .header(header) + .context(unused.iterator() + .next() + .getInput()); } } @@ -1009,8 +1019,7 @@ private void doIncludeResource(Jar jar, String name, Map extra) private void doClassAttribute(Jar jar, String name, Map extra, Instructions preprocess, boolean absentIsOk) throws Exception { - FileLine header = getHeader(INCLUDERESOURCE_HEADERS, - Constants.CLASS_ATTRIBUTE); + FileLine header = getHeader(INCLUDERESOURCE_HEADERS, Constants.CLASS_ATTRIBUTE); String fqn = extra.get(Constants.CLASS_ATTRIBUTE); TypeRef typeRef = getTypeRefFromFQN(fqn); if (typeRef == null) { @@ -1292,14 +1301,15 @@ private void noSuchFile(Jar jar, String clause, Map extra, Strin } } + final static RE ZIP_P = caseInsenstive(setAll, lit("."), or("jar", "zip"), eof); + /** * Extra resources from a Jar and add them to the given jar. * * @param extra */ private void extractFromJar(Jar jar, String source, String destination, boolean absentIsOk, - Map extra) - throws ZipException, IOException { + Map extra) throws ZipException, IOException { // Inline all resources and classes from another jar // optionally appended with a modified regular expression // like @zip.jar!/META-INF/MANIFEST.MF @@ -1310,6 +1320,14 @@ private void extractFromJar(Jar jar, String source, String destination, boolean source = source.substring(0, n); } + File f = getFile(source); + if (f.isDirectory() && ZIP_P.matches(destination) + .isPresent()) { + DirectoryResource resource = new DirectoryResource(f); + jar.putResource(destination, resource); + return; + } + List sub = getJarsFromName(source, "extract from jar"); if (sub.isEmpty()) { if (absentIsOk) @@ -1325,7 +1343,7 @@ private void extractFromJar(Jar jar, String source, String destination, boolean Instruction in = instr; String replacement = extra.get("rename:"); nameMapper = path -> in.getMatcher(path) - .replaceAll(replacement); + .replaceAll(replacement); } } @@ -1334,7 +1352,6 @@ private void extractFromJar(Jar jar, String source, String destination, boolean } } - /** * Add all the resources in the given jar that match the given filter. * @@ -1766,7 +1783,8 @@ protected void setTypeSpecificPlugins(PluginsContainer pluginsContainer) { * @throws Exception */ - public void doDiff(@SuppressWarnings("unused") Jar dot) throws Exception { + public void doDiff(@SuppressWarnings("unused") + Jar dot) throws Exception { Parameters diffs = parseHeader(getProperty("-diff")); if (diffs.isEmpty()) return; diff --git a/biz.aQute.bndlib/src/aQute/bnd/osgi/DirectoryResource.java b/biz.aQute.bndlib/src/aQute/bnd/osgi/DirectoryResource.java new file mode 100644 index 0000000000..dcb1aba1ee --- /dev/null +++ b/biz.aQute.bndlib/src/aQute/bnd/osgi/DirectoryResource.java @@ -0,0 +1,40 @@ +package aQute.bnd.osgi; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Path; + +/** + * Resource for a directory. This class implementation assumes the file does not + * change underneath this object. + */ +public class DirectoryResource extends WriteResource { + private final File dir; + + public DirectoryResource(File dir) throws IOException { + this.dir = dir; + assert dir.isDirectory(); + } + + public DirectoryResource(Path path) throws IOException { + this(path.toFile()); + } + + @Override + public String toString() { + return dir.toString(); + } + + @Override + public void write(OutputStream out) throws Exception { + try (Jar jar = new Jar(dir)) { + jar.write(out); + } + } + + @Override + public long lastModified() { + return dir.lastModified(); + } +} diff --git a/docs/_instructions/includeresource.md b/docs/_instructions/includeresource.md index ea8a49f112..f1c1fb2d9e 100644 --- a/docs/_instructions/includeresource.md +++ b/docs/_instructions/includeresource.md @@ -42,7 +42,13 @@ A _source_ in the clause starting with a `-` sign will not generare an error whe `-includeresource.all = {foo=-bar}`, -foo.txt -## Unrolling +## Rolling + +There are two variants of the rolling _operator_ `@`. It can be used to _roll up_ a directory as a zip or jar file, or it can be used to unroll a jar file into its constituents. + +If the destination is a path of a `jar` or `zip` file, like `foo/bar/icons.zip` and the source points to a directory in the file system, then the directory will be wrapped up in a Jar and stored as a single entry in the receiving jar file. + + -includeresource foo/bar/icons.zip=@icons/ _Unrolling_ is getting the content from another JAR. It is activated by starting the source with an at sign (`@`). The at sign signals that it is not the actual file that should be copied, but the contents of that file should be placed in the destination.