This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ant-antlibs-cyclonedx.git
The following commit(s) were added to refs/heads/main by this push:
new cd13226 new resource collection that will help with SBOMs for tarballs
cd13226 is described below
commit cd13226ae4aa850912a4249919a8f93bbea9ee59
Author: Stefan Bodewig <[email protected]>
AuthorDate: Sun Jun 14 14:42:09 2026 +0200
new resource collection that will help with SBOMs for tarballs
---
changes.xml | 10 ++
docs/componentbom.html | 2 +-
docs/fsonlymappedresources.html | 93 +++++++++++++++
docs/index.html | 1 +
.../FilesystemOnlyMappedResourceCollection.java | 131 +++++++++++++++++++++
src/main/org/apache/ant/cyclonedx/antlib.xml | 2 +
src/tests/antunit/fsonlymappedresources-test.xml | 128 ++++++++++++++++++++
7 files changed, 366 insertions(+), 1 deletion(-)
diff --git a/changes.xml b/changes.xml
index 573cc4d..e1a2285 100644
--- a/changes.xml
+++ b/changes.xml
@@ -58,6 +58,16 @@
metadata.tools.component of generated SBOMs now contains hashes
of ant-cyclonedx as has been intended originally.
</action>
+ <action type="add">
+ A new resource collection "fsonlymappedresources" has been added
+ that decorates file-system-only resource collections modifying
+ the names of the resources just like Ant's built-in
+ mappedresources but still allows tasks to access the original
+ files.
+ This should only be used with componentbom's purefileresources
+ nested element. Other tasks and types may bypass the mapped name
+ if they can go to the underlying files directly.
+ </action>
</release>
<release version="0.1" date="2026-06-03" description="initial release">
diff --git a/docs/componentbom.html b/docs/componentbom.html
index ca89074..5858ada 100644
--- a/docs/componentbom.html
+++ b/docs/componentbom.html
@@ -154,7 +154,7 @@ <h4>additionalComponent</h4>
(transitive) dependencies of the main component but may also be
present for different reasons.</p>
- <h4>pureFileComponents</h4>
+ <h4 id="pureFileComponents">pureFileComponents</h4>
<p><code>pureFileComponents</code> is a container for arbitrary
resources or resource collections. Only file-system resources
diff --git a/docs/fsonlymappedresources.html b/docs/fsonlymappedresources.html
new file mode 100644
index 0000000..0106982
--- /dev/null
+++ b/docs/fsonlymappedresources.html
@@ -0,0 +1,93 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ 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.
+-->
+<html>
+ <head>
+ <meta http-equiv="Content-Language" content="en-us"></meta>
+ <link rel="stylesheet" type="text/css" href="style.css">
+ <title>Apache CycloneDX Ant Library - fsonlymappedresources</title>
+ </head>
+
+ <body>
+ <h2 id="fsonlymappedresources">fsonlymappedresources</h2>
+
+ <p><em>since CycloneDX Antlib 0.2</em></p>
+
+ <p>This is a resource collection very similar to Ant's
+ built-in <a
href="https://ant.apache.org/manual/Types/resources.html#mappedresources">mappedresources</a>
+ in that it decorates an existing resource collection by mapping
+ the resource names. Unlike <code>mappedresources</code> it can
+ only be used for file-system resources and allows tasks to
+ directly access the underlying files.</p>
+
+ <p>When used with arbitrary tasks in Ant it is very likely the
+ task will directly go to the files and completely ignore the
+ mapped name, so it is not meant to be used as a general purpose
+ resource collection. It's primary purpose is to be used inside
+ of <a
href="componentbom.html#pureFileComponents"><code>componentbom</code>'s
<code>pureFileComponents</code></a>
+ child. <code>pureFileComponents</code> are commonly used to list
+ the contents of zip or tar archives that have
+ used <code>zipfileset</code>'s
+ or <code>tarfileset</code>'s <code>prefix</code> attribute. This
+ resource collection allows the components to be listed without
+ creating temporary folders holding the original contents with
+ adapted names.</p>
+
+ <p>Apart from Ant's <code>id/refid</code> this element doesn't
+ support any attributes.</p>
+
+ <h3>Nested elements</h3>
+
+ <h4>any
+ file-system <a
href="https://ant.apache.org/manual/Types/resources.html">resource</a>
+ or resource collection</h4>
+
+ <p>Specifies the files that make up the resource collection.</p>
+
+ <h4>mapper</h4>
+
+ <p>A
+ single <a
href="https://ant.apache.org/manual/Types/mapper.html">mapper</a>
+ can be used to map names. Either by using a
+ nested <code>mapper</code> element or by a built-in mapper
+ type.</p>
+
+ <p>If no mapper has been given (which doesn't make any sense,
+ honestly), an identity mapper will be used.</p>
+
+ <h3>Examples</h3>
+
+ <p>The following task adds all files contained in
+ the <code>src</code> directory to the SBOM as file resources,
+ calculating hashes from the file contents but prefixing all file
+ names by the value of the <code>prefix</code> property.:</p>
+
+ <pre>
+ <cdx:componentbom
+ ...
+ xmlns:cdx="antlib:org.apache.ant.cyclonedx">
+ ...
+ <pureFileComponents>
+ <cdx:fsonlymappedresources>
+ <fileset dir="src"/>
+ <globmapper from="*" to="${prefix}/*"/>
+ </cdx:fsonlymappedresources>
+ </pureFileComponents>
+ </cdx:componentbom>
+ </pre>
+</body></html>
+
+
diff --git a/docs/index.html b/docs/index.html
index 4346ad5..698e5c3 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -73,6 +73,7 @@ <h2>Tasks and Types provided by this Ant Library</h2>
<li><a href="license.html">license</a></li>
<li><a href="organization.html">organization</a></li>
<li><a href="propertyset.html">propertyset</a></li>
+ <li><a href="fsonlymappedresources.html">fsonlymappedresources</a></li>
</ul>
<h2>Requirements and Dependencies of this Ant Library</h2>
diff --git
a/src/main/org/apache/ant/cyclonedx/FilesystemOnlyMappedResourceCollection.java
b/src/main/org/apache/ant/cyclonedx/FilesystemOnlyMappedResourceCollection.java
new file mode 100644
index 0000000..0602d11
--- /dev/null
+++
b/src/main/org/apache/ant/cyclonedx/FilesystemOnlyMappedResourceCollection.java
@@ -0,0 +1,131 @@
+package org.apache.ant.cyclonedx;
+
+import java.util.Collections;
+import java.util.Iterator;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.MappedResourceCollection;
+import org.apache.tools.ant.types.resources.ResourceDecorator;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.IdentityMapper;
+import org.apache.tools.ant.util.MergingMapper;
+
+/**
+ * A variant of {@link MappedResourceCollection} that only accepts
+ * file-system resource collections as children and which returns
+ * resources that provide access to the underlying files (unlike
+ * {@link MappedResourceCollection} which prevents direct access.</p>
+ *
+ * <p>It wraps another resource collection and maps their names using
+ * the provided mapper when returning the resources.</p>
+ *
+ * <p>This type should not be used with arbitrary Ant tasks as the
+ * tasks may use the underlying File's name instead of the mapped name
+ * when iterating over the resources. It is useful when used with
+ * {@link ComponentBomTask}'s pure file components as all that is used
+ * there is the mapped name and the content of the actual file (to
+ * calculate hashes).</p>
+ *
+ * @since CycloneDX Antlib 0.2
+ */
+public final class FilesystemOnlyMappedResourceCollection
+ extends DataType implements ResourceCollection {
+
+ private Union nested = null;
+ private Mapper mapper = null;
+
+ /**
+ * Adds the resources to map.
+ */
+ public void add(ResourceCollection c) throws BuildException {
+ checkChildrenAllowed();
+ if (!c.isFilesystemOnly()) {
+ throw new BuildException("only file-system resources allowed as
children",
+ getLocation());
+ }
+ if (nested == null) {
+ nested = new Union(getProject());
+ }
+ nested.add(c);
+ }
+
+ /**
+ * Creates a nested mapper.
+ */
+ public Mapper createMapper() throws BuildException {
+ checkChildrenAllowed();
+ if (mapper != null) {
+ throw new BuildException("Cannot define more than one mapper",
+ getLocation());
+ }
+ mapper = new Mapper(getProject());
+ return mapper;
+ }
+
+ /**
+ * Creates a nested mapper by directly providing the implementation.
+ */
+ public void add(FileNameMapper fileNameMapper) {
+ createMapper().add(fileNameMapper);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isFilesystemOnly() {
+ if (isReference()) {
+ return getRef().isFilesystemOnly();
+ }
+ return true;
+ }
+
+ @Override
+ public Iterator<Resource> iterator() {
+ if (isReference()) {
+ return getRef().iterator();
+ }
+ if (nested == null) {
+ return Collections.emptyIterator();
+ }
+ FileNameMapper m =
+ mapper == null ? new IdentityMapper() : mapper.getImplementation();
+ return nested.stream().map(r -> (Resource) new MappedResource(r,
m)).iterator();
+ }
+
+ @Override
+ public int size() {
+ if (isReference()) {
+ return getRef().size();
+ }
+ if (nested == null) {
+ return 0;
+ }
+ return nested.size();
+ }
+
+ private FilesystemOnlyMappedResourceCollection getRef() {
+ return getCheckedRef(FilesystemOnlyMappedResourceCollection.class);
+ }
+
+ private static class MappedResource extends ResourceDecorator {
+ private final FileNameMapper mapper;
+
+ private MappedResource(Resource r, FileNameMapper m) {
+ super(r);
+ mapper = m;
+ }
+
+ @Override
+ public String getName() {
+ String name = getResource().getName();
+ String[] mapped = mapper.mapFileName(name);
+ return mapped != null && mapped.length == 1 ? mapped[0] : null;
+ }
+ }
+}
diff --git a/src/main/org/apache/ant/cyclonedx/antlib.xml
b/src/main/org/apache/ant/cyclonedx/antlib.xml
index 2e545bc..82a7f72 100644
--- a/src/main/org/apache/ant/cyclonedx/antlib.xml
+++ b/src/main/org/apache/ant/cyclonedx/antlib.xml
@@ -30,4 +30,6 @@ under the License.
classname="org.apache.ant.cyclonedx.ExternalReferenceSet"/>
<typedef name="propertyset"
classname="org.apache.ant.cyclonedx.PropertySet"/>
+ <typedef name="fsonlymappedresources"
+
classname="org.apache.ant.cyclonedx.FilesystemOnlyMappedResourceCollection"/>
</antlib>
diff --git a/src/tests/antunit/fsonlymappedresources-test.xml
b/src/tests/antunit/fsonlymappedresources-test.xml
new file mode 100644
index 0000000..6c011b2
--- /dev/null
+++ b/src/tests/antunit/fsonlymappedresources-test.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ 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.
+-->
+<project name="fsonlymappedresources-test" default="antunit">
+
+ <import file="shared.xml" />
+
+ <target
+ name="testFsonlyMappedResourcesDoesntAllowMultipleMappers">
+ <au:expectfailure
+ expectedMessage='Cannot define more than one mapper'
+ xmlns:au="antlib:org.apache.ant.antunit">
+ <cdx:fsonlymappedresources
+ xmlns:cdx="antlib:org.apache.ant.cyclonedx">
+ <identitymapper/>
+ <identitymapper/>
+ </cdx:fsonlymappedresources>
+ </au:expectfailure>
+ </target>
+
+ <target
+ name="testFsonlyMappedResourcesDoesntAllowNonFilesystemResources">
+ <au:expectfailure
+ expectedMessage='only file-system resources allowed as children'
+ xmlns:au="antlib:org.apache.ant.antunit">
+ <cdx:fsonlymappedresources
+ xmlns:cdx="antlib:org.apache.ant.cyclonedx">
+ <url url="https://example.org/"/>
+ </cdx:fsonlymappedresources>
+ </au:expectfailure>
+ </target>
+
+ <target
+ name="testFsonlyMappedResourcesWithRefIdDoesntAllowNestedChildren">
+ <cdx:fsonlymappedresources
+ id="test-fsonlymappedresources"
+ xmlns:cdx="antlib:org.apache.ant.cyclonedx">
+ <file file="${ant.file}"/>
+ </cdx:fsonlymappedresources>
+ <au:expectfailure
+ expectedMessage='You must not specify nested elements when using refid'
+ xmlns:au="antlib:org.apache.ant.antunit">
+ <cdx:fsonlymappedresources
+ refid="test-fsonlymappedresources"
+ xmlns:cdx="antlib:org.apache.ant.cyclonedx">
+ <file file="${ant.file}"/>
+ </cdx:fsonlymappedresources>
+ </au:expectfailure>
+ <au:expectfailure
+ expectedMessage='You must not specify nested elements when using refid'
+ xmlns:au="antlib:org.apache.ant.antunit">
+ <cdx:fsonlymappedresources
+ refid="test-fsonlymappedresources"
+ xmlns:cdx="antlib:org.apache.ant.cyclonedx">
+ <identitymapper/>
+ </cdx:fsonlymappedresources>
+ </au:expectfailure>
+ </target>
+
+ <target name="testFsonlyMappedResourcesAddsFileComponentsWithoutMapper">
+ <checksum property="ant.file.sha256" file="${ant.file}"
algorithm="SHA-256"/>
+ <cdx:componentbom outputdirectory="${output}" format="xml"
+ xmlns:cdx="antlib:org.apache.ant.cyclonedx">
+ <component name="testname"/>
+ <pureFileComponents>
+ <cdx:fsonlymappedresources
+ xmlns:cdx="antlib:org.apache.ant.cyclonedx">
+ <file file="${ant.file}"/>
+ </cdx:fsonlymappedresources>
+ </pureFileComponents>
+ </cdx:componentbom>
+ <xmlproperty file="${output}/bom.xml"/>
+ <au:assertPropertyEquals
+ xmlns:au="antlib:org.apache.ant.antunit"
+ name="bom.components.component.name"
+ value="fsonlymappedresources-test.xml"/>
+ <au:assertPropertyEquals
+ xmlns:au="antlib:org.apache.ant.antunit"
+ name="bom.components.component(type)"
+ value="file"/>
+ <au:assertResourceContains
+ xmlns:au="antlib:org.apache.ant.antunit"
+ resource="${output}/bom.xml"
+ value='<hash alg="SHA-256">${ant.file.sha256}</hash>'/>
+ </target>
+
+ <target name="testFsonlyMappedResourcesAddsFileComponentsWithMapper">
+ <checksum property="ant.file.sha256" file="${ant.file}"
algorithm="SHA-256"/>
+ <cdx:componentbom outputdirectory="${output}" format="xml"
+ xmlns:cdx="antlib:org.apache.ant.cyclonedx">
+ <component name="testname"/>
+ <pureFileComponents>
+ <cdx:fsonlymappedresources
+ xmlns:cdx="antlib:org.apache.ant.cyclonedx">
+ <file file="${ant.file}"/>
+ <globmapper from="*" to="foo/*"/>
+ </cdx:fsonlymappedresources>
+ </pureFileComponents>
+ </cdx:componentbom>
+ <xmlproperty file="${output}/bom.xml"/>
+ <au:assertPropertyEquals
+ xmlns:au="antlib:org.apache.ant.antunit"
+ name="bom.components.component.name"
+ value="foo/fsonlymappedresources-test.xml"/>
+ <au:assertPropertyEquals
+ xmlns:au="antlib:org.apache.ant.antunit"
+ name="bom.components.component(type)"
+ value="file"/>
+ <au:assertResourceContains
+ xmlns:au="antlib:org.apache.ant.antunit"
+ resource="${output}/bom.xml"
+ value='<hash alg="SHA-256">${ant.file.sha256}</hash>'/>
+ </target>
+</project>