github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/haskell/parse_stack_lock.go (about) 1 package haskell 2 3 import ( 4 "fmt" 5 "io" 6 "strings" 7 8 "gopkg.in/yaml.v3" 9 10 "github.com/anchore/syft/syft/artifact" 11 "github.com/anchore/syft/syft/file" 12 "github.com/anchore/syft/syft/pkg" 13 "github.com/anchore/syft/syft/pkg/cataloger/generic" 14 ) 15 16 var _ generic.Parser = parseStackLock 17 18 type stackLock struct { 19 Packages []stackPackage `yaml:"packages"` 20 Snapshots []stackSnapshot `yaml:"snapshots"` 21 } 22 23 type stackPackage struct { 24 Completed completedPackage `yaml:"completed"` 25 } 26 27 type completedPackage struct { 28 Hackage string `yaml:"hackage"` 29 } 30 31 type stackSnapshot struct { 32 Completed completedSnapshot `yaml:"completed"` 33 } 34 35 type completedSnapshot struct { 36 URL string `yaml:"url"` 37 Sha string `yaml:"sha256"` 38 } 39 40 // parseStackLock is a parser function for stack.yaml.lock contents, returning all packages discovered. 41 func parseStackLock(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { 42 bytes, err := io.ReadAll(reader) 43 if err != nil { 44 return nil, nil, fmt.Errorf("failed to load stack.yaml.lock file: %w", err) 45 } 46 47 var lockFile stackLock 48 49 if err := yaml.Unmarshal(bytes, &lockFile); err != nil { 50 return nil, nil, fmt.Errorf("failed to parse stack.yaml.lock file: %w", err) 51 } 52 53 var ( 54 pkgs []pkg.Package 55 snapshotURL string 56 ) 57 58 for _, snap := range lockFile.Snapshots { 59 // TODO: handle multiple snapshots (split the metadata struct into more distinct structs and types) 60 snapshotURL = snap.Completed.URL 61 } 62 63 for _, pack := range lockFile.Packages { 64 pkgName, pkgVersion, pkgHash := parseStackPackageEncoding(pack.Completed.Hackage) 65 pkgs = append( 66 pkgs, 67 newPackage( 68 pkgName, 69 pkgVersion, 70 &pkg.HackageMetadata{ 71 PkgHash: pkgHash, 72 SnapshotURL: snapshotURL, 73 }, 74 reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 75 ), 76 ) 77 } 78 79 return pkgs, nil, nil 80 } 81 func parseStackPackageEncoding(pkgEncoding string) (name, version, hash string) { 82 lastDashIdx := strings.LastIndex(pkgEncoding, "-") 83 name = pkgEncoding[:lastDashIdx] 84 remainingEncoding := pkgEncoding[lastDashIdx+1:] 85 encodingSplits := strings.Split(remainingEncoding, "@") 86 version = encodingSplits[0] 87 startHash, endHash := strings.Index(encodingSplits[1], ":")+1, strings.Index(encodingSplits[1], ",") 88 hash = encodingSplits[1][startHash:endHash] 89 return 90 }