github.com/google/osv-scalibr@v0.4.1/semantic/parse.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package semantic provides version parsing and comparison for various ecosystems,
    16  // matching the native versioning rules of each ecosystem.
    17  package semantic
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"strings"
    23  )
    24  
    25  // ErrUnsupportedEcosystem is returned for unsupported ecosystems.
    26  var ErrUnsupportedEcosystem = errors.New("unsupported ecosystem")
    27  
    28  // ErrInvalidVersion is returned for malformed version strings.
    29  var ErrInvalidVersion = errors.New("invalid version")
    30  
    31  // MustParse is like Parse but panics if the ecosystem is not supported.
    32  func MustParse(str string, ecosystem string) Version {
    33  	v, err := Parse(str, ecosystem)
    34  
    35  	if err != nil {
    36  		panic(err)
    37  	}
    38  
    39  	return v
    40  }
    41  
    42  // Parse attempts to parse the given string as a version for the specified ecosystem,
    43  // returning an ErrUnsupportedEcosystem error if the ecosystem is not supported.
    44  func Parse(str string, ecosystem string) (Version, error) {
    45  	// Remove the version suffix from the ecosystem name.
    46  	parts := strings.Split(ecosystem, ":")
    47  	if len(parts) > 1 {
    48  		ecosystem = parts[0]
    49  	}
    50  
    51  	// TODO(#457): support more ecosystems
    52  	switch ecosystem {
    53  	case "AlmaLinux":
    54  		return parseRedHatVersion(str), nil
    55  	case "Alpaquita":
    56  		return parseAlpineVersion(str)
    57  	case "Alpine":
    58  		return parseAlpineVersion(str)
    59  	case "BellSoft Hardened Containers":
    60  		return parseAlpineVersion(str)
    61  	case "Bitnami":
    62  		return parseSemverVersion(str), nil
    63  	case "Bioconductor":
    64  		return parseSemverVersion(str), nil
    65  	case "Chainguard":
    66  		return parseAlpineVersion(str)
    67  	case "ConanCenter":
    68  		return parseSemverVersion(str), nil
    69  	case "CRAN":
    70  		return parseCRANVersion(str)
    71  	case "crates.io":
    72  		return parseSemverVersion(str), nil
    73  	case "Debian":
    74  		return parseDebianVersion(str)
    75  	case "GHC":
    76  		return parseSemverVersion(str), nil
    77  	case "Go":
    78  		return parseSemverVersion(str), nil
    79  	case "Hackage":
    80  		return parseHackageVersion(str)
    81  	case "Hex":
    82  		return parseSemverVersion(str), nil
    83  	case "Julia":
    84  		return parseSemverVersion(str), nil
    85  	case "Mageia":
    86  		return parseRedHatVersion(str), nil
    87  	case "Maven":
    88  		return parseMavenVersion(str), nil
    89  	case "MinimOS":
    90  		return parseAlpineVersion(str)
    91  	case "npm":
    92  		return parseSemverVersion(str), nil
    93  	case "NuGet":
    94  		return parseNuGetVersion(str), nil
    95  	case "openEuler":
    96  		return parseRedHatVersion(str), nil
    97  	case "openSUSE":
    98  		return parseRedHatVersion(str), nil
    99  	case "Packagist":
   100  		return parsePackagistVersion(str), nil
   101  	case "Pub":
   102  		return parsePubVersion(str), nil
   103  	case "PyPI":
   104  		return parsePyPIVersion(str)
   105  	case "Red Hat":
   106  		return parseRedHatVersion(str), nil
   107  	case "Rocky Linux":
   108  		return parseRedHatVersion(str), nil
   109  	case "RubyGems":
   110  		return parseRubyGemsVersion(str), nil
   111  	case "SUSE":
   112  		return parseRedHatVersion(str), nil
   113  	case "SwiftURL":
   114  		return parseSemverVersion(str), nil
   115  	case "Ubuntu":
   116  		return parseDebianVersion(str)
   117  	case "Wolfi":
   118  		return parseAlpineVersion(str)
   119  	}
   120  
   121  	return nil, fmt.Errorf("%w %s", ErrUnsupportedEcosystem, ecosystem)
   122  }