1010import static eu .maveniverse .maven .toolbox .shared .internal .ToolboxCommandoImpl .humanReadableByteCountBin ;
1111import static java .util .Objects .requireNonNull ;
1212
13+ import com .github .packageurl .PackageURL ;
1314import eu .maveniverse .maven .toolbox .shared .ArtifactMapper ;
1415import eu .maveniverse .maven .toolbox .shared .ArtifactMatcher ;
1516import eu .maveniverse .maven .toolbox .shared .ArtifactNameMapper ;
@@ -580,6 +581,7 @@ public static class StatArtifactSink implements Artifacts.Sink {
580581 private final ModuleDescriptorExtractingSink moduleDescriptorExtractingSink ;
581582 private final ChecksumArtifactSink checksumArtifactSink ;
582583 private final ArtifactUriSink artifactUriSink ;
584+ private final ArtifactPurlSink artifactPurlSink ;
583585 private final Map <Artifact , BytecodeVersions > bytecodeVersions ;
584586
585587 private StatArtifactSink (int level , boolean list , boolean details , Output output , ToolboxCommando tc ) {
@@ -590,6 +592,7 @@ private StatArtifactSink(int level, boolean list, boolean details, Output output
590592 this .moduleDescriptorExtractingSink = details ? new ModuleDescriptorExtractingSink (output ) : null ;
591593 this .checksumArtifactSink = details ? checksumArtifactSink () : null ;
592594 this .artifactUriSink = details ? artifactUriSink (output , tc , false ) : null ;
595+ this .artifactPurlSink = details ? modulePurlSink (output , tc , false ) : null ;
593596 this .bytecodeVersions = details ? new HashMap <>() : null ;
594597 }
595598
@@ -610,6 +613,7 @@ public void accept(Artifact artifact) throws IOException {
610613 moduleDescriptorExtractingSink .accept (artifact );
611614 checksumArtifactSink .accept (artifact );
612615 artifactUriSink .accept (artifact );
616+ artifactPurlSink .accept (artifact );
613617 if (artifact .getFile () != null ) {
614618 bytecodeVersions .put (
615619 artifact ,
@@ -685,6 +689,10 @@ public void close() throws Exception {
685689 if (artifactUri != null ) {
686690 output .tell ("{} -- Origin URI: {}" , indent , artifactUri .toASCIIString ());
687691 }
692+ PackageURL artifactPurl = artifactPurlSink .getPurl (artifact );
693+ if (artifactPurl != null ) {
694+ output .tell ("{} -- PURL: {}" , indent , artifactPurl .canonicalize ());
695+ }
688696 }
689697 }
690698 output .tell ("{}------------------------------" , indent );
@@ -761,4 +769,48 @@ public void close() throws IOException {
761769 }
762770 }
763771 }
772+
773+ /**
774+ * Creates an "Artifact -> PURL" artifact sink.
775+ */
776+ public static ArtifactPurlSink modulePurlSink (Output output , ToolboxCommando toolboxCommando , boolean dumpOnClose ) {
777+ return new ArtifactPurlSink (output , toolboxCommando , dumpOnClose );
778+ }
779+
780+ public static class ArtifactPurlSink implements Artifacts .Sink {
781+ private final Output output ;
782+ private final ToolboxCommando toolboxCommando ;
783+ private final ConcurrentMap <Artifact , PackageURL > purls = new ConcurrentHashMap <>();
784+ private final boolean dumpOnClose ;
785+
786+ public ArtifactPurlSink (Output output , ToolboxCommando toolboxCommando , boolean dumpOnClose ) {
787+ this .output = requireNonNull (output , "output" );
788+ this .toolboxCommando = requireNonNull (toolboxCommando , "toolboxCommando" );
789+ this .dumpOnClose = dumpOnClose ;
790+ }
791+
792+ @ Override
793+ public void accept (Artifact artifact ) throws IOException {
794+ String origin = artifact .getProperty ("origin" , null );
795+ if (origin != null ) {
796+ toolboxCommando
797+ .remoteRepository (origin )
798+ .flatMap (r -> toolboxCommando .artifactPurl (r , artifact ))
799+ .ifPresent (uri -> purls .put (artifact , uri ));
800+ }
801+ }
802+
803+ public PackageURL getPurl (Artifact artifact ) {
804+ return purls .get (artifact );
805+ }
806+
807+ @ Override
808+ public void close () throws IOException {
809+ if (dumpOnClose ) {
810+ for (Map .Entry <Artifact , PackageURL > entry : purls .entrySet ()) {
811+ output .tell ("{} -> {}" , entry .getKey (), entry .getValue ());
812+ }
813+ }
814+ }
815+ }
764816}
0 commit comments