package packagelock import ( _ "embed" "fmt" "os" "path/filepath" "sort" "cuelang.org/go/cue" "cuelang.org/go/cue/cuecontext" "cuelang.org/go/encoding/gocode/gocodec" "cuelang.org/go/encoding/yaml" "edge-infra.dev/pkg/edge/yamlfmt" "edge-infra.dev/pkg/lib/build/bazel" ) var ( Packagelock = "packagelock" //go:embed package-lock-rules.cue rulesFile []byte ) type Version struct { Digest string `json:"digest" yaml:"digest"` Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"` } type LockPackage struct { Name string `json:"name" yaml:"name"` Versions []Version `json:"versions,omitempty" yaml:"versions,omitempty"` } type Packages []LockPackage func (p Packages) Sort() { sort.Slice(p, func(i, j int) bool { return p[i].Name < p[j].Name }) } type PackageLock struct { Packages Packages `json:"packages" yaml:"packages"` } type Rules struct { codec *gocodec.Codec ruleValue cue.Value } func NewRules() (Rules, error) { c := cuecontext.New() ruleValue := c.CompileBytes(rulesFile) if ruleValue.Err() != nil { return Rules{}, ruleValue.Err() } codec := gocodec.New(c, nil) return Rules{codec: codec, ruleValue: ruleValue}, nil } func (plr Rules) ParsePackageLock(path string) (PackageLock, error) { pl := &PackageLock{} if bazel.IsBazelRun() { if !filepath.IsAbs(path) { path = filepath.Join(os.Getenv(bazel.BuildWorkspaceDir), path) } } plReader, err := os.Open(path) if err != nil { return PackageLock{}, fmt.Errorf("failed to open file, err: %w", err) } plCueFile, err := yaml.Extract(path, plReader) if err != nil { return PackageLock{}, fmt.Errorf("failed to extract yaml, err: %w", err) } plReader.Close() plCueValue, err := plr.codec.Decode(plCueFile) if err != nil { return PackageLock{}, err } err = plr.codec.Encode(plCueValue, pl) if err != nil { return PackageLock{}, err } err = plr.codec.Validate(plr.ruleValue, pl) if err != nil { return PackageLock{}, err } return *pl, nil } func (plr Rules) MarshalPackageLockYAML(pl PackageLock) ([]byte, error) { pl.Packages.Sort() plValue, err := plr.codec.Decode(pl) if err != nil { return nil, err } err = plr.codec.Validate(plr.ruleValue, plValue) if err != nil { return nil, err } plBytes, err := yaml.Encode(plValue) if err != nil { return nil, err } formatter := yamlfmt.NewByteFormatter() formattedBytes, err := formatter.FormatBytes(plBytes) if err != nil { return nil, err } return formattedBytes, nil }