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>
+    &lt;cdx:componentbom
+        ...
+        xmlns:cdx="antlib:org.apache.ant.cyclonedx">
+      ...
+      &lt;pureFileComponents>
+        &lt;cdx:fsonlymappedresources>
+          &lt;fileset dir="src"/>
+          &lt;globmapper from="*" to="${prefix}/*"/>
+        &lt;/cdx:fsonlymappedresources>
+      &lt;/pureFileComponents>
+    &lt;/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='&lt;hash alg="SHA-256"&gt;${ant.file.sha256}&lt;/hash&gt;'/>
+  </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='&lt;hash alg="SHA-256"&gt;${ant.file.sha256}&lt;/hash&gt;'/>
+  </target>
+</project>

Reply via email to