diff --git a/internal/worker/resolvepackage.go b/internal/worker/resolvepackage.go index 58e442b8..b9240b12 100644 --- a/internal/worker/resolvepackage.go +++ b/internal/worker/resolvepackage.go @@ -31,14 +31,14 @@ func ResolvePkg(manager *pkgmanager.PkgManager, name, version, localPath string) // ResolvePurl creates a Pkg object from the given purl // See https://github.com/package-url/purl-spec func ResolvePurl(purl packageurl.PackageURL) (*pkgmanager.Pkg, error) { - var ecosystem pkgecosystem.Ecosystem - if err := ecosystem.UnmarshalText([]byte(purl.Type)); err != nil { - return nil, fmt.Errorf("unsupported package ecosystem '%s'", purl.Type) + ecosystem, err := pkgecosystem.ParsePurlType(purl.Type) + if err != nil { + return nil, err } manager := pkgmanager.Manager(ecosystem) if manager == nil { - return nil, fmt.Errorf("unsupported package ecosystem '%s'", purl.Type) + return nil, pkgecosystem.Unsupported(purl.Type) } // Prepend package namespace to package name, if present diff --git a/pkg/api/pkgecosystem/ecosystem.go b/pkg/api/pkgecosystem/ecosystem.go index 718c6be0..8012afd4 100644 --- a/pkg/api/pkgecosystem/ecosystem.go +++ b/pkg/api/pkgecosystem/ecosystem.go @@ -1,4 +1,4 @@ -// The pkgecosystem package defines the open source ecosystems supported by Package Analysis. +// Package pkgecosystem defines the open source ecosystems supported by Package Analysis. package pkgecosystem import ( @@ -25,6 +25,12 @@ const ( // correspond to a defined ecosystem constant is passed in as a parameter. var ErrUnsupported = errors.New("ecosystem unsupported") +// Unsupported returns a new ErrUnsupported that adds the unsupported ecosystem name +// to the error message +func Unsupported(name string) error { + return fmt.Errorf("%w: %s", ErrUnsupported, name) +} + // SupportedEcosystems is a list of all the ecosystems supported. var SupportedEcosystems = []Ecosystem{ CratesIO, @@ -43,14 +49,14 @@ var SupportedEcosystemsStrings = EcosystemsAsStrings(SupportedEcosystems) // It will only succeed when unmarshaling ecosytems in SupportedEcosystems or // empty. func (e *Ecosystem) UnmarshalText(text []byte) error { - search := string(text) - for _, s := range append(SupportedEcosystems, None) { - if string(s) == search { - *e = s - return nil - } + ecosystem, err := Parse(string(text)) + + if err != nil { + return err } - return fmt.Errorf("%w: %s", ErrUnsupported, text) + + *e = ecosystem + return nil } // MarshalText implements the encoding.TextMarshaler interface. @@ -71,3 +77,33 @@ func EcosystemsAsStrings(es []Ecosystem) []string { } return s } + +// Parse returns an Ecosystem corresponding to the given string name, or +// the None ecosystem along with an error if there is no matching Ecosystem. +// If name == "", then the None ecosystem is returned with no error. +func Parse(name string) (Ecosystem, error) { + for _, s := range append(SupportedEcosystems, None) { + if string(s) == name { + return s, nil + } + } + + return None, Unsupported(name) +} + +// ParsePurlType converts from a Package URL type, defined at +// https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst +// to an Ecosystem object +func ParsePurlType(purlType string) (Ecosystem, error) { + switch purlType { + case "cargo": + return CratesIO, nil + case "composer": + return Packagist, nil + case "gem": + return RubyGems, nil + default: + // we use the same name for NPM and PyPI as the purl type string + return Parse(purlType) + } +}