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

     1  package format
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/go-multierror"
     7  
     8  	"github.com/anchore/syft/syft/format/cyclonedxjson"
     9  	"github.com/anchore/syft/syft/format/cyclonedxxml"
    10  	"github.com/anchore/syft/syft/format/github"
    11  	"github.com/anchore/syft/syft/format/purls"
    12  	"github.com/anchore/syft/syft/format/spdxjson"
    13  	"github.com/anchore/syft/syft/format/spdxtagvalue"
    14  	"github.com/anchore/syft/syft/format/syftjson"
    15  	"github.com/anchore/syft/syft/format/table"
    16  	"github.com/anchore/syft/syft/format/template"
    17  	"github.com/anchore/syft/syft/format/text"
    18  	"github.com/anchore/syft/syft/sbom"
    19  )
    20  
    21  const AllVersions = "all-versions"
    22  
    23  type EncodersConfig struct {
    24  	Template      template.EncoderConfig
    25  	SyftJSON      syftjson.EncoderConfig
    26  	SPDXJSON      spdxjson.EncoderConfig
    27  	SPDXTagValue  spdxtagvalue.EncoderConfig
    28  	CyclonedxJSON cyclonedxjson.EncoderConfig
    29  	CyclonedxXML  cyclonedxxml.EncoderConfig
    30  }
    31  
    32  func Encoders() []sbom.FormatEncoder {
    33  	encs, _ := DefaultEncodersConfig().Encoders()
    34  	return encs
    35  }
    36  
    37  func DefaultEncodersConfig() EncodersConfig {
    38  	cfg := EncodersConfig{
    39  		Template:      template.DefaultEncoderConfig(),
    40  		SyftJSON:      syftjson.DefaultEncoderConfig(),
    41  		SPDXJSON:      spdxjson.DefaultEncoderConfig(),
    42  		SPDXTagValue:  spdxtagvalue.DefaultEncoderConfig(),
    43  		CyclonedxJSON: cyclonedxjson.DefaultEncoderConfig(),
    44  		CyclonedxXML:  cyclonedxxml.DefaultEncoderConfig(),
    45  	}
    46  
    47  	// empty value means to support all versions
    48  	cfg.SPDXJSON.Version = AllVersions
    49  	cfg.SPDXTagValue.Version = AllVersions
    50  	cfg.CyclonedxJSON.Version = AllVersions
    51  	cfg.CyclonedxXML.Version = AllVersions
    52  
    53  	return cfg
    54  }
    55  
    56  func (o EncodersConfig) Encoders() ([]sbom.FormatEncoder, error) {
    57  	var l encodersList
    58  
    59  	if o.Template.TemplatePath != "" {
    60  		l.addWithErr(template.ID)(o.templateEncoders())
    61  	}
    62  
    63  	l.addWithErr(syftjson.ID)(o.syftJSONEncoders())
    64  	l.add(table.ID)(table.NewFormatEncoder())
    65  	l.add(text.ID)(text.NewFormatEncoder())
    66  	l.add(purls.ID)(purls.NewFormatEncoder())
    67  	l.add(github.ID)(github.NewFormatEncoder())
    68  	l.addWithErr(cyclonedxxml.ID)(o.cyclonedxXMLEncoders())
    69  	l.addWithErr(cyclonedxjson.ID)(o.cyclonedxJSONEncoders())
    70  	l.addWithErr(spdxjson.ID)(o.spdxJSONEncoders())
    71  	l.addWithErr(spdxtagvalue.ID)(o.spdxTagValueEncoders())
    72  
    73  	return l.encoders, l.err
    74  }
    75  
    76  func (o EncodersConfig) templateEncoders() ([]sbom.FormatEncoder, error) {
    77  	enc, err := template.NewFormatEncoder(o.Template)
    78  	return []sbom.FormatEncoder{enc}, err
    79  }
    80  
    81  func (o EncodersConfig) syftJSONEncoders() ([]sbom.FormatEncoder, error) {
    82  	enc, err := syftjson.NewFormatEncoderWithConfig(o.SyftJSON)
    83  	return []sbom.FormatEncoder{enc}, err
    84  }
    85  
    86  func (o EncodersConfig) cyclonedxXMLEncoders() ([]sbom.FormatEncoder, error) {
    87  	var (
    88  		encs []sbom.FormatEncoder
    89  		errs error
    90  	)
    91  
    92  	cfg := o.CyclonedxXML
    93  
    94  	var versions []string
    95  	if cfg.Version == AllVersions {
    96  		versions = cyclonedxxml.SupportedVersions()
    97  	} else {
    98  		versions = []string{cfg.Version}
    99  	}
   100  
   101  	for _, v := range versions {
   102  		cfg.Version = v
   103  		enc, err := cyclonedxxml.NewFormatEncoderWithConfig(cfg)
   104  		if err != nil {
   105  			errs = multierror.Append(errs, err)
   106  		} else {
   107  			encs = append(encs, enc)
   108  		}
   109  	}
   110  	return encs, errs
   111  }
   112  
   113  func (o EncodersConfig) cyclonedxJSONEncoders() ([]sbom.FormatEncoder, error) {
   114  	var (
   115  		encs []sbom.FormatEncoder
   116  		errs error
   117  	)
   118  
   119  	cfg := o.CyclonedxJSON
   120  
   121  	var versions []string
   122  	if cfg.Version == AllVersions {
   123  		versions = cyclonedxjson.SupportedVersions()
   124  	} else {
   125  		versions = []string{cfg.Version}
   126  	}
   127  
   128  	for _, v := range versions {
   129  		cfg.Version = v
   130  		enc, err := cyclonedxjson.NewFormatEncoderWithConfig(cfg)
   131  		if err != nil {
   132  			errs = multierror.Append(errs, err)
   133  		} else {
   134  			encs = append(encs, enc)
   135  		}
   136  	}
   137  	return encs, errs
   138  }
   139  
   140  func (o EncodersConfig) spdxJSONEncoders() ([]sbom.FormatEncoder, error) {
   141  	var (
   142  		encs []sbom.FormatEncoder
   143  		errs error
   144  	)
   145  
   146  	cfg := o.SPDXJSON
   147  
   148  	var versions []string
   149  	if cfg.Version == AllVersions {
   150  		versions = spdxjson.SupportedVersions()
   151  	} else {
   152  		versions = []string{cfg.Version}
   153  	}
   154  
   155  	for _, v := range versions {
   156  		cfg.Version = v
   157  		enc, err := spdxjson.NewFormatEncoderWithConfig(cfg)
   158  		if err != nil {
   159  			errs = multierror.Append(errs, err)
   160  		} else {
   161  			encs = append(encs, enc)
   162  		}
   163  	}
   164  	return encs, errs
   165  }
   166  
   167  func (o EncodersConfig) spdxTagValueEncoders() ([]sbom.FormatEncoder, error) {
   168  	var (
   169  		encs []sbom.FormatEncoder
   170  		errs error
   171  	)
   172  
   173  	cfg := o.SPDXTagValue
   174  
   175  	var versions []string
   176  	if cfg.Version == AllVersions {
   177  		versions = spdxtagvalue.SupportedVersions()
   178  	} else {
   179  		versions = []string{cfg.Version}
   180  	}
   181  
   182  	for _, v := range versions {
   183  		cfg.Version = v
   184  		enc, err := spdxtagvalue.NewFormatEncoderWithConfig(cfg)
   185  		if err != nil {
   186  			errs = multierror.Append(errs, err)
   187  		} else {
   188  			encs = append(encs, enc)
   189  		}
   190  	}
   191  	return encs, errs
   192  }
   193  
   194  type encodersList struct {
   195  	encoders []sbom.FormatEncoder
   196  	err      error
   197  }
   198  
   199  func (l *encodersList) addWithErr(name sbom.FormatID) func([]sbom.FormatEncoder, error) {
   200  	return func(encs []sbom.FormatEncoder, err error) {
   201  		if err != nil {
   202  			l.err = multierror.Append(l.err, fmt.Errorf("unable to configure %q format encoder: %w", name, err))
   203  			return
   204  		}
   205  		for _, enc := range encs {
   206  			if enc == nil {
   207  				l.err = multierror.Append(l.err, fmt.Errorf("unable to configure %q format encoder: nil encoder returned", name))
   208  				continue
   209  			}
   210  			l.encoders = append(l.encoders, enc)
   211  		}
   212  	}
   213  }
   214  
   215  func (l *encodersList) add(name sbom.FormatID) func(...sbom.FormatEncoder) {
   216  	return func(encs ...sbom.FormatEncoder) {
   217  		for _, enc := range encs {
   218  			if enc == nil {
   219  				l.err = multierror.Append(l.err, fmt.Errorf("unable to configure %q format encoder: nil encoder returned", name))
   220  				continue
   221  			}
   222  			l.encoders = append(l.encoders, enc)
   223  		}
   224  	}
   225  }