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