add basic format abstraction

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2021-10-10 18:28:40 -07:00
parent 9189ed68df
commit 9ded1c4c22
No known key found for this signature in database
GPG Key ID: 5CB45AE22BAB7EA7
6 changed files with 177 additions and 0 deletions

12
syft/format/decoder.go Normal file
View File

@ -0,0 +1,12 @@
package format
import (
"io"
"github.com/anchore/syft/syft/distro"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
type Decoder func(reader io.Reader) (*pkg.Catalog, *source.Metadata, *distro.Distro, error)

22
syft/format/encoder.go Normal file
View File

@ -0,0 +1,22 @@
package format
import (
"io"
"github.com/anchore/syft/syft/distro"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
// TODO: this should probably be a helper function to return the bytes
//func using() {
// var buff bytes.Buffer
// var encoder Encoder // = ...
//
// _:=encoder(&buff, nil, nil, nil)
//
// bytes.NewReader(buff.Bytes())
//
//}
type Encoder func(io.Writer, *pkg.Catalog, *source.Metadata, *distro.Distro) error

65
syft/format/format.go Normal file
View File

@ -0,0 +1,65 @@
package format
import (
"bytes"
"errors"
"io"
"github.com/anchore/syft/syft/distro"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
var (
ErrEncodingNotSupported = errors.New("encoding not supported")
ErrDecodingNotSupported = errors.New("decoding not supported")
)
type Format struct {
Option Option
encoder Encoder
decoder Decoder
validator Validator
}
func NewFormat(option Option, encoder Encoder, decoder Decoder, validator Validator) Format {
return Format{
Option: option,
encoder: encoder,
decoder: decoder,
validator: validator,
}
}
func (f Format) Encode(output io.Writer, catalog *pkg.Catalog, d *distro.Distro, metadata *source.Metadata) error {
if f.encoder == nil {
return ErrEncodingNotSupported
}
return f.encoder(output, catalog, metadata, d)
}
func (f Format) Decode(reader io.Reader) (*pkg.Catalog, *source.Metadata, *distro.Distro, error) {
if f.decoder == nil {
return nil, nil, nil, ErrDecodingNotSupported
}
return f.decoder(reader)
}
func (f Format) Detect(b []byte) bool {
if f.validator == nil {
return false
}
if err := f.validator(bytes.NewReader(b)); err != nil {
return false
}
return true
}
func (f Format) Presenter(catalog *pkg.Catalog, metadata *source.Metadata, d *distro.Distro) *Presenter {
if f.encoder == nil {
return nil
}
return NewPresenter(f.encoder, catalog, metadata, d)
}

43
syft/format/option.go Normal file
View File

@ -0,0 +1,43 @@
package format
import "strings"
const (
UnknownOption Option = "UnknownFormatOption"
JSONOption Option = "json"
TextOption Option = "text"
TableOption Option = "table"
CycloneDxOption Option = "cyclonedx"
SPDXTagValueOption Option = "spdx-tag-value"
SPDXJSONOption Option = "spdx-json"
)
var AllOptions = []Option{
JSONOption,
TextOption,
TableOption,
CycloneDxOption,
SPDXTagValueOption,
SPDXJSONOption,
}
type Option string
func ParseOption(userStr string) Option {
switch strings.ToLower(userStr) {
case string(JSONOption), "syft-json":
return JSONOption
case string(TextOption):
return TextOption
case string(TableOption):
return TableOption
case string(CycloneDxOption), "cyclone", "cyclone-dx":
return CycloneDxOption
case string(SPDXTagValueOption), "spdx", "spdx-tagvalue", "spdxtagvalue", "spdx-tv", "spdxtv":
return SPDXTagValueOption
case string(SPDXJSONOption), "spdxjson":
return SPDXJSONOption
default:
return UnknownOption
}
}

30
syft/format/presenter.go Normal file
View File

@ -0,0 +1,30 @@
package format
import (
"io"
"github.com/anchore/syft/syft/distro"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
type Presenter struct {
catalog *pkg.Catalog
srcMetadata *source.Metadata
distro *distro.Distro
encoder Encoder
}
func NewPresenter(encoder Encoder, catalog *pkg.Catalog, srcMetadata *source.Metadata, d *distro.Distro) *Presenter {
return &Presenter{
catalog: catalog,
srcMetadata: srcMetadata,
distro: d,
encoder: encoder,
}
}
func (pres *Presenter) Present(output io.Writer) error {
return pres.encoder(output, pres.catalog, pres.srcMetadata, pres.distro)
}

5
syft/format/validator.go Normal file
View File

@ -0,0 +1,5 @@
package format
import "io"
type Validator func(reader io.Reader) error