github.com/anchore/syft@v1.38.2/syft/format/purls/encoder.go (about)

     1  package purls
     2  
     3  import (
     4  	"io"
     5  	"strings"
     6  
     7  	"github.com/scylladb/go-set/strset"
     8  
     9  	"github.com/anchore/packageurl-go"
    10  	"github.com/anchore/syft/internal/log"
    11  	"github.com/anchore/syft/syft/sbom"
    12  )
    13  
    14  const ID sbom.FormatID = "purls"
    15  const version = "1"
    16  
    17  type encoder struct {
    18  }
    19  
    20  func NewFormatEncoder() sbom.FormatEncoder {
    21  	return encoder{}
    22  }
    23  
    24  func (e encoder) ID() sbom.FormatID {
    25  	return ID
    26  }
    27  
    28  func (e encoder) Aliases() []string {
    29  	return []string{
    30  		"purl",
    31  	}
    32  }
    33  
    34  func (e encoder) Version() string {
    35  	return sbom.AnyVersion
    36  }
    37  
    38  func (e encoder) Encode(writer io.Writer, s sbom.SBOM) error {
    39  	output := strset.New()
    40  	for _, p := range s.Artifacts.Packages.Sorted() {
    41  		purl := strings.TrimSpace(p.PURL)
    42  		if purl == "" || output.Has(purl) {
    43  			continue
    44  		}
    45  		// ensure syft doesn't output invalid PURLs in this format
    46  		_, err := packageurl.FromString(purl)
    47  		if err != nil {
    48  			log.Debugf("invalid purl: %q", purl)
    49  			continue
    50  		}
    51  		output.Add(purl)
    52  		_, err = writer.Write([]byte(purl))
    53  		if err != nil {
    54  			return err
    55  		}
    56  		_, err = writer.Write([]byte("\n"))
    57  		if err != nil {
    58  			return err
    59  		}
    60  	}
    61  	return nil
    62  }