mirror of
https://github.com/anchore/syft
synced 2024-11-10 06:14:16 +00:00
commit
1f272c2bda
13 changed files with 97 additions and 35 deletions
|
@ -68,5 +68,6 @@ func doRunCmd(cmd *cobra.Command, args []string) int {
|
||||||
log.Errorf("could not format catalog results: %w", err)
|
log.Errorf("could not format catalog results: %w", err)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
3
go.mod
3
go.mod
|
@ -8,6 +8,7 @@ require (
|
||||||
github.com/anchore/stereoscope v0.0.0-20200523232006-be5f3c18958f
|
github.com/anchore/stereoscope v0.0.0-20200523232006-be5f3c18958f
|
||||||
github.com/go-test/deep v1.0.6
|
github.com/go-test/deep v1.0.6
|
||||||
github.com/google/go-containerregistry v0.0.0-20200521151920-a873a21aff23 // indirect
|
github.com/google/go-containerregistry v0.0.0-20200521151920-a873a21aff23 // indirect
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.0
|
github.com/hashicorp/go-multierror v1.1.0
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/mitchellh/mapstructure v1.3.1
|
github.com/mitchellh/mapstructure v1.3.1
|
||||||
|
@ -16,6 +17,6 @@ require (
|
||||||
github.com/spf13/viper v1.7.0
|
github.com/spf13/viper v1.7.0
|
||||||
go.uber.org/zap v1.15.0
|
go.uber.org/zap v1.15.0
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121 // indirect
|
golang.org/x/sys v0.0.0-20200523222454-059865788121 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20200521103424-e9a78aa275b7 // indirect
|
google.golang.org/protobuf v1.24.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.3.0
|
gopkg.in/yaml.v2 v2.3.0
|
||||||
)
|
)
|
||||||
|
|
9
go.sum
9
go.sum
|
@ -210,6 +210,8 @@ github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTV
|
||||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
@ -628,8 +630,8 @@ google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84 h1:pSLkPbrjnPyLDYU
|
||||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200519141106-08726f379972 h1:6ydLqG65DIMNJf6p97WudGsmd1w3Ickm/LiZnBrREPI=
|
google.golang.org/genproto v0.0.0-20200519141106-08726f379972 h1:6ydLqG65DIMNJf6p97WudGsmd1w3Ickm/LiZnBrREPI=
|
||||||
google.golang.org/genproto v0.0.0-20200519141106-08726f379972/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
google.golang.org/genproto v0.0.0-20200519141106-08726f379972/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||||
google.golang.org/genproto v0.0.0-20200521103424-e9a78aa275b7 h1:JUs1uIDQ46c7iI0QuMPzAHqXaSmqKF0f9freFMk2ivs=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||||
google.golang.org/genproto v0.0.0-20200521103424-e9a78aa275b7/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
@ -650,6 +652,9 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
|
||||||
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|
|
@ -18,7 +18,7 @@ func init() {
|
||||||
controllerInstance.add(dpkg.NewAnalyzer())
|
controllerInstance.add(dpkg.NewAnalyzer())
|
||||||
}
|
}
|
||||||
|
|
||||||
func Analyze(s scope.Scope) (pkg.Catalog, error) {
|
func Analyze(s scope.Scope) (*pkg.Catalog, error) {
|
||||||
return controllerInstance.analyze(s)
|
return controllerInstance.analyze(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ func (c *controller) add(a Analyzer) {
|
||||||
c.analyzers = append(c.analyzers, a)
|
c.analyzers = append(c.analyzers, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) analyze(s scope.Scope) (pkg.Catalog, error) {
|
func (c *controller) analyze(s scope.Scope) (*pkg.Catalog, error) {
|
||||||
catalog := pkg.NewCatalog()
|
catalog := pkg.NewCatalog()
|
||||||
fileSelection := make([]file.Reference, 0)
|
fileSelection := make([]file.Reference, 0)
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ func (c *controller) analyze(s scope.Scope) (pkg.Catalog, error) {
|
||||||
// fetch contents for requested selection by analyzers
|
// fetch contents for requested selection by analyzers
|
||||||
contents, err := s.Image.MultipleFileContentsByRef(fileSelection...)
|
contents, err := s.Image.MultipleFileContentsByRef(fileSelection...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return pkg.Catalog{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform analysis, accumulating errors for each failed analysis
|
// perform analysis, accumulating errors for each failed analysis
|
||||||
|
@ -65,7 +65,7 @@ func (c *controller) analyze(s scope.Scope) (pkg.Catalog, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if errs != nil {
|
if errs != nil {
|
||||||
return pkg.Catalog{}, errs
|
return nil, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
return catalog, nil
|
return catalog, nil
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
)
|
)
|
||||||
|
|
||||||
var endOfPackages = fmt.Errorf("no more packages to read")
|
var errEndOfPackages = fmt.Errorf("no more packages to read")
|
||||||
|
|
||||||
func ParseEntries(reader io.Reader) ([]pkg.DpkgMetadata, error) {
|
func ParseEntries(reader io.Reader) ([]pkg.DpkgMetadata, error) {
|
||||||
buffedReader := bufio.NewReader(reader)
|
buffedReader := bufio.NewReader(reader)
|
||||||
|
@ -19,7 +19,7 @@ func ParseEntries(reader io.Reader) ([]pkg.DpkgMetadata, error) {
|
||||||
for {
|
for {
|
||||||
entry, err := parseEntry(buffedReader)
|
entry, err := parseEntry(buffedReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == endOfPackages {
|
if err == errEndOfPackages {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -38,7 +38,7 @@ func parseEntry(reader *bufio.Reader) (entry pkg.DpkgMetadata, err error) {
|
||||||
line, err := reader.ReadString('\n')
|
line, err := reader.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
return pkg.DpkgMetadata{}, endOfPackages
|
return pkg.DpkgMetadata{}, errEndOfPackages
|
||||||
}
|
}
|
||||||
return pkg.DpkgMetadata{}, err
|
return pkg.DpkgMetadata{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: add os detection results as return value
|
// TODO: add os detection results as return value
|
||||||
func CatalogImage(img *image.Image, o scope.Option) (pkg.Catalog, error) {
|
func CatalogImage(img *image.Image, o scope.Option) (*pkg.Catalog, error) {
|
||||||
s, err := scope.NewScope(img, o)
|
s, err := scope.NewScope(img, o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return pkg.Catalog{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add OS detection here...
|
// TODO: add OS detection here...
|
||||||
|
|
|
@ -1,31 +1,75 @@
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/anchore/imgbom/internal/log"
|
||||||
|
"github.com/anchore/stereoscope/pkg/file"
|
||||||
|
)
|
||||||
|
|
||||||
// TODO: add reader methods (by type, id, fuzzy search, etc)
|
// TODO: add reader methods (by type, id, fuzzy search, etc)
|
||||||
|
|
||||||
|
var nextPackageID int64
|
||||||
|
|
||||||
type Catalog struct {
|
type Catalog struct {
|
||||||
// TODO: catalog by package ID for potential indexing
|
byID map[ID]*Package
|
||||||
packages map[Type][]Package
|
byType map[Type][]*Package
|
||||||
|
byFile map[file.Reference][]*Package
|
||||||
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCatalog() Catalog {
|
func NewCatalog() *Catalog {
|
||||||
return Catalog{
|
return &Catalog{
|
||||||
packages: make(map[Type][]Package),
|
byID: make(map[ID]*Package),
|
||||||
|
byType: make(map[Type][]*Package),
|
||||||
|
byFile: make(map[file.Reference][]*Package),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Catalog) Package(id ID) *Package {
|
||||||
|
return c.byID[id]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Catalog) PackagesByFile(ref file.Reference) []*Package {
|
||||||
|
return c.byFile[ref]
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Catalog) Add(p Package) {
|
func (c *Catalog) Add(p Package) {
|
||||||
_, ok := c.packages[p.Type]
|
if p.id != 0 {
|
||||||
if !ok {
|
log.Errorf("package already added to catalog: %s", p)
|
||||||
c.packages[p.Type] = make([]Package, 0)
|
return
|
||||||
|
}
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
|
p.id = ID(nextPackageID)
|
||||||
|
nextPackageID++
|
||||||
|
|
||||||
|
// store by package ID
|
||||||
|
c.byID[p.id] = &p
|
||||||
|
|
||||||
|
// store by package type
|
||||||
|
_, ok := c.byType[p.Type]
|
||||||
|
if !ok {
|
||||||
|
c.byType[p.Type] = make([]*Package, 0)
|
||||||
|
}
|
||||||
|
c.byType[p.Type] = append(c.byType[p.Type], &p)
|
||||||
|
|
||||||
|
// store by file references
|
||||||
|
for _, s := range p.Source {
|
||||||
|
_, ok := c.byFile[s]
|
||||||
|
if !ok {
|
||||||
|
c.byFile[s] = make([]*Package, 0)
|
||||||
|
}
|
||||||
|
c.byFile[s] = append(c.byFile[s], &p)
|
||||||
}
|
}
|
||||||
c.packages[p.Type] = append(c.packages[p.Type], p)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Catalog) Enumerate(types ...Type) <-chan Package {
|
func (c *Catalog) Enumerate(types ...Type) <-chan *Package {
|
||||||
channel := make(chan Package)
|
channel := make(chan *Package)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(channel)
|
defer close(channel)
|
||||||
for ty, packages := range c.packages {
|
for ty, packages := range c.byType {
|
||||||
if len(types) != 0 {
|
if len(types) != 0 {
|
||||||
found := false
|
found := false
|
||||||
typeCheck:
|
typeCheck:
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
import "github.com/anchore/stereoscope/pkg/file"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
// TODO: add package ID (random/incremental)
|
"github.com/anchore/stereoscope/pkg/file"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ID int64
|
||||||
|
|
||||||
// TODO: add field to trace which analyzer detected this
|
// TODO: add field to trace which analyzer detected this
|
||||||
type Package struct {
|
type Package struct {
|
||||||
|
id ID
|
||||||
Name string
|
Name string
|
||||||
Version string
|
Version string
|
||||||
Source []file.Reference
|
Source []file.Reference
|
||||||
|
@ -14,4 +19,10 @@ type Package struct {
|
||||||
Metadata interface{}
|
Metadata interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: stringer...
|
func (p Package) ID() ID {
|
||||||
|
return p.id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Package) String() string {
|
||||||
|
return fmt.Sprintf("Pkg(type=%s, name=%s, version=%s)", p.Type, p.Name, p.Version)
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ const (
|
||||||
ApkPkg
|
ApkPkg
|
||||||
DebPkg
|
DebPkg
|
||||||
JavaPkg
|
JavaPkg
|
||||||
NodePkg
|
JavaScriptPkg
|
||||||
PacmanPkg
|
PacmanPkg
|
||||||
PythonPkg
|
PythonPkg
|
||||||
RpmPkg
|
RpmPkg
|
||||||
|
@ -19,7 +19,7 @@ var typeStr = []string{
|
||||||
"apk",
|
"apk",
|
||||||
"deb",
|
"deb",
|
||||||
"java",
|
"java",
|
||||||
"node",
|
"javascript",
|
||||||
"pacman",
|
"pacman",
|
||||||
"python",
|
"python",
|
||||||
"rpm",
|
"rpm",
|
||||||
|
|
|
@ -49,7 +49,7 @@ type artifact struct {
|
||||||
Metadata interface{} `json:"metadata"`
|
Metadata interface{} `json:"metadata"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pres *Presenter) Present(output io.Writer, img *stereoscopeImg.Image, catalog pkg.Catalog) error {
|
func (pres *Presenter) Present(output io.Writer, img *stereoscopeImg.Image, catalog *pkg.Catalog) error {
|
||||||
tags := make([]string, len(img.Metadata.Tags))
|
tags := make([]string, len(img.Metadata.Tags))
|
||||||
for idx, tag := range img.Metadata.Tags {
|
for idx, tag := range img.Metadata.Tags {
|
||||||
tags[idx] = tag.String()
|
tags[idx] = tag.String()
|
||||||
|
|
|
@ -16,7 +16,7 @@ var Options = []Option{
|
||||||
JSONPresenter,
|
JSONPresenter,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Option uint
|
type Option int
|
||||||
|
|
||||||
func ParseOption(userStr string) Option {
|
func ParseOption(userStr string) Option {
|
||||||
switch strings.ToLower(userStr) {
|
switch strings.ToLower(userStr) {
|
||||||
|
@ -28,7 +28,7 @@ func ParseOption(userStr string) Option {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Option) String() string {
|
func (o Option) String() string {
|
||||||
if int(o) >= len(optionStr) {
|
if int(o) >= len(optionStr) || o < 0 {
|
||||||
return optionStr[0]
|
return optionStr[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Presenter interface {
|
type Presenter interface {
|
||||||
Present(io.Writer, *image.Image, pkg.Catalog) error
|
Present(io.Writer, *image.Image, *pkg.Catalog) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPresenter(option Option) Presenter {
|
func GetPresenter(option Option) Presenter {
|
||||||
|
|
|
@ -8,7 +8,7 @@ const (
|
||||||
AllLayersScope
|
AllLayersScope
|
||||||
)
|
)
|
||||||
|
|
||||||
type Option uint
|
type Option int
|
||||||
|
|
||||||
var optionStr = []string{
|
var optionStr = []string{
|
||||||
"UnknownScope",
|
"UnknownScope",
|
||||||
|
@ -32,7 +32,7 @@ func ParseOption(userStr string) Option {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Option) String() string {
|
func (o Option) String() string {
|
||||||
if int(o) >= len(optionStr) {
|
if int(o) >= len(optionStr) || o < 0 {
|
||||||
return optionStr[0]
|
return optionStr[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue