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