package publish import ( "context" "errors" "fmt" "os" "path/filepath" "sort" "strings" ) type Attempt struct { RecordPath string Evidence Evidence } type AttemptsResult struct { RecordDir string Attempts []Attempt Diagnostics []*RecoveryError } func ListAttempts(ctx context.Context, repositoryDir, override string) (AttemptsResult, error) { if repositoryDir == "" { repositoryDir = "." } result := AttemptsResult{Attempts: []Attempt{}, Diagnostics: []*RecoveryError{}} if err := ctx.Err(); err != nil { return result, recoveryFailure(ctx, "storage_enumeration", err) } var directory string { resolved, err := recordDirectoryFor(ctx, repositoryDir, override) if err != nil { return result, recoveryFailure(ctx, "storage_enumeration", err) } directory = resolved } result.RecordDir = directory if err := ctx.Err(); err != nil { return result, &RecoveryError{Kind: "canceled", cause: err} } entries, err := os.ReadDir(directory) if err != nil { return result, recoveryFailure(ctx, "storage_enumeration", fmt.Errorf("enumerate records in %q: %w", directory, err)) } paths := make([]string, 0, len(entries)) for _, entry := range entries { if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".json") { paths = append(paths, filepath.Join(directory, entry.Name())) } } sort.Strings(paths) for _, path := range paths { if err := ctx.Err(); err != nil { return result, &RecoveryError{Kind: "canceled", cause: err} } absolute, err := filepath.Abs(path) if err != nil { result.Diagnostics = append(result.Diagnostics, &RecoveryError{Kind: "record_read", RecordPath: path, cause: err}) continue } evidence, err := LoadEvidence(absolute) if err != nil { var recordError *RecoveryError if errors.As(err, &recordError) { result.Diagnostics = append(result.Diagnostics, recordError) } continue } result.Attempts = append(result.Attempts, Attempt{RecordPath: absolute, Evidence: evidence}) } return result, nil } func recordDirectoryFor(ctx context.Context, repositoryDir, override string) (string, error) { if filepath.IsAbs(override) { return filepath.Clean(override), nil } directory, _, err := resolveRecordDir(ctx, repositoryDir, override) return directory, err }