This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch support-ivy-as-component-source
in repository https://gitbox.apache.org/repos/asf/ant-antlibs-cyclonedx.git


The following commit(s) were added to 
refs/heads/support-ivy-as-component-source by this push:
     new 3e052f5  calculate hashes for Ivy dependencies retrieved
3e052f5 is described below

commit 3e052f53c3b7640b68e73974aa74d0eb453a26a9
Author: Stefan Bodewig <[email protected]>
AuthorDate: Fri Aug 7 16:17:21 2026 +0200

    calculate hashes for Ivy dependencies retrieved
---
 src/main/org/apache/ant/cyclonedx/Component.java   | 14 +++++
 .../ant/cyclonedx/IvyModuleComponentResolver.java  | 63 +++++++++++++++++++++-
 2 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/src/main/org/apache/ant/cyclonedx/Component.java 
b/src/main/org/apache/ant/cyclonedx/Component.java
index e3fc9f7..4b51d7a 100644
--- a/src/main/org/apache/ant/cyclonedx/Component.java
+++ b/src/main/org/apache/ant/cyclonedx/Component.java
@@ -1109,6 +1109,7 @@ public class Component extends DataType {
         private String externalConf;
         private String resolveId;
         private Reference antIvyEngineRef;
+        private String pattern;
 
         /**
          * Sets the configurations to include in the SBOM.
@@ -1191,5 +1192,18 @@ public class Component extends DataType {
         String getExternalConf() {
             return externalConf;
         }
+
+        /**
+         * The retrieve pattern usde for retrieving the dependnecy artifacts.
+         *
+         * <p>Defaults to {@code ${ivy.retrieve.pattern}}.</p>
+         */
+        public void setPattern(String pattern) {
+            this.pattern = pattern;
+        }
+
+        String getPattern() {
+            return pattern;
+        }
     }
 }
diff --git a/src/main/org/apache/ant/cyclonedx/IvyModuleComponentResolver.java 
b/src/main/org/apache/ant/cyclonedx/IvyModuleComponentResolver.java
index 79aca12..1c68e24 100644
--- a/src/main/org/apache/ant/cyclonedx/IvyModuleComponentResolver.java
+++ b/src/main/org/apache/ant/cyclonedx/IvyModuleComponentResolver.java
@@ -17,7 +17,9 @@
  */
 package org.apache.ant.cyclonedx;
 
+import java.io.File;
 import java.io.IOException;
+import java.text.ParseException;
 import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -32,16 +34,21 @@ import java.util.stream.Stream;
 
 import org.apache.ivy.Ivy;
 import org.apache.ivy.ant.IvyAntSettings;
+import org.apache.ivy.core.module.descriptor.Artifact;
 import org.apache.ivy.core.module.descriptor.License;
 import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
 import org.apache.ivy.core.module.id.ModuleRevisionId;
+import org.apache.ivy.core.report.ArtifactDownloadReport;
 import org.apache.ivy.core.report.ResolveReport;
 import org.apache.ivy.core.resolve.IvyNode;
 import org.apache.ivy.core.resolve.IvyNodeCallers.Caller;
+import org.apache.ivy.core.retrieve.RetrieveEngine;
+import org.apache.ivy.core.retrieve.RetrieveOptions;
 import org.apache.ivy.core.settings.IvySettings;
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.Project;
 import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.resources.FileResource;
 import org.apache.tools.ant.types.resources.URLResource;
 
 import org.cyclonedx.model.Component.Scope;
@@ -93,10 +100,11 @@ class IvyModuleComponentResolver {
             populateDependencyTree(settings, report, optionalModules, 
externalModules);
         fillFromModuleDescriptor(component, root, dependencyTree);
 
+        Map<ModuleRevisionId, File> componentFiles = 
findDownloadedArtifacts(ivy, settings, root.getModuleRevisionId());
         Collection<ModuleDescriptor> allDependencies = 
getDependencies(dependencyTree, root);
 
         return allDependencies.stream()
-            .map(d -> toComponent(d, dependencyTree, optionalModules, 
externalModules))
+            .map(d -> toComponent(d, dependencyTree, optionalModules, 
externalModules, componentFiles))
             .collect(Collectors.toList());
     }
 
@@ -167,7 +175,8 @@ class IvyModuleComponentResolver {
     private Component toComponent(ModuleDescriptor md,
                                   Map<ModuleRevisionId, Set<IvyNode>> 
dependencyTree,
                                   Set<ModuleRevisionId> optionalModules,
-                                  Set<ModuleRevisionId> externalModules) {
+                                  Set<ModuleRevisionId> externalModules,
+                                  Map<ModuleRevisionId, File> componentFiles) {
         Component c = new Component();
         c.setProject(project);
         fillFromModuleDescriptor(c, md, dependencyTree);
@@ -177,6 +186,10 @@ class IvyModuleComponentResolver {
             c.setScope(ComponentScope.from(Scope.OPTIONAL));
         }
         c.setIsExternal(externalModules.contains(mrid));
+        File f = componentFiles.get(mrid);
+        if (f != null) {
+            c.add(new FileResource(f));
+        }
         return c;
     }
 
@@ -295,6 +308,52 @@ class IvyModuleComponentResolver {
         }
     }
 
+    private Map<ModuleRevisionId, File> findDownloadedArtifacts(Ivy ivy,
+                                                                IvySettings 
settings,
+                                                                
ModuleRevisionId mrid) {
+        String pattern = ivyModule.getPattern();
+        if (pattern == null) {
+            pattern = settings.getVariable("ivy.retrieve.pattern");
+        }
+        if (pattern == null) {
+            project.log("no retrieve pattern, won't look for dependency 
artifact files");
+            return Collections.emptyMap();
+        }
+
+        RetrieveEngine retrieveEngine = ivy.getRetrieveEngine();
+        if (retrieveEngine == null) {
+            project.log("no RetrieveEngine, won't look for dependency artifact 
files");
+            return Collections.emptyMap();
+        }
+
+        RetrieveOptions opts = new RetrieveOptions();
+        String[] confs = includedConfigurations.isEmpty()
+            ? new String[] { "*" }
+            : includedConfigurations.toArray(new 
String[includedConfigurations.size()]);
+        opts.setConfs(confs);
+        String resolveId = ivyModule.getResolveId();
+        if (resolveId != null) {
+            opts.setResolveId(resolveId);
+        }
+
+        try {
+            Map<ArtifactDownloadReport, Set<String>> artifacts =
+                retrieveEngine.determineArtifactsToCopy(mrid, pattern, opts);
+            Map<ModuleRevisionId, File> result = new HashMap<>();
+            for (ArtifactDownloadReport ar : artifacts.keySet()) {
+                File f = ar.getLocalFile();
+                if (f != null) {
+                    Artifact a = ar.getArtifact();
+                    result.put(a.getModuleRevisionId(), f);
+                }
+            }
+            return result;
+        } catch (ParseException | IOException e) {
+            project.log(e.getMessage(), Project.MSG_ERR);
+            throw new BuildException("syntax errors in ivy file: " + e, e);
+        }
+    }
+
     private Set<String> confAsSet(String conf) {
         if (conf == null) {
             return Collections.emptySet();

Reply via email to