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"` } func ValidSHA(s string) bool { if len(s) != 64 { return false } match, _ := regexp.MatchString("^[0-9a-f]{64}$", s) return match } 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 !hasYAMLExt(entry.Name()) { 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: invalid sha256 hash", entry.Name()) } // 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 } func hasYAMLExt(name string) bool { return filepath.Ext(name) == ".yml" || filepath.Ext(name) == ".yaml" }