package depot import ( "fmt" "os" "path/filepath" "regexp" "gopkg.in/yaml.v3" ) type manifestFile struct { Assets []struct { Path string `yaml:"path"` SHA256 string `yaml:"sha256"` Size int64 `yaml:"size"` } `yaml:"assets"` } var sha256Pattern = regexp.MustCompile(`^[0-9a-f]{64}$`) func ValidSHA(s string) bool { return sha256Pattern.MatchString(s) } func BlobKey(sha string) string { return fmt.Sprintf("sha256/%s/%s/%s", sha[0:2], sha[2:4], sha) } func ReferencedSHAs(dir string) (map[string]int64, error) { entries, err := os.ReadDir(dir) if err != nil { return nil, err } result := make(map[string]int64) foundAny := false for _, entry := range entries { if entry.IsDir() { continue } if filepath.Ext(entry.Name()) != ".yml" { continue } foundAny = true path := filepath.Join(dir, entry.Name()) data, err := os.ReadFile(path) if err != nil { return nil, err } var manifest manifestFile if err := yaml.Unmarshal(data, &manifest); err != nil { return nil, err } for _, asset := range manifest.Assets { if !ValidSHA(asset.SHA256) { return nil, fmt.Errorf("%s: asset %q: invalid sha256 %q", entry.Name(), asset.Path, asset.SHA256) } // Keep the largest size for each sha if asset.Size > result[asset.SHA256] { result[asset.SHA256] = asset.Size } } } if !foundAny { return nil, fmt.Errorf("no *.yml files found in %s", dir) } return result, nil }