| 1 | package workspacestate |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "encoding/json" |
| 6 | "slices" |
| 7 | "strings" |
| 8 | ) |
| 9 | |
| 10 | // PurgeSourceCleanup records the exact adopted sources eligible for an explicit |
| 11 | // deletion request. Older purge journals without this request retain originals. |
| 12 | // Multi-file legacy DAGs are retained: their independent heads and artifacts |
| 13 | // cannot be deleted as one canonical session directory. |
| 14 | type PurgeSourceCleanup struct { |
| 15 | Version int `json:"sourceCleanupVersion"` |
| 16 | Sources []SourceMapping `json:"sources"` |
| 17 | } |
| 18 | |
| 19 | func (s *Store) BeginPurgeWithSources(ctx context.Context, id string, expected uint64) error { |
| 20 | return s.beginOrResumePurge(ctx, id, expected, nil, true) |
| 21 | } |
| 22 | |
| 23 | func purgeSourceCleanupRequest(state State, id string) (json.RawMessage, error) { |
| 24 | plan := PurgeSourceCleanup{Version: 1} |
| 25 | for _, mapping := range state.SourceMappings { |
| 26 | if mapping.SessionID == id && mapping.Format == "canonical" && mapping.HeadID == "" { |
| 27 | mapping.RetainedArtifacts = nil |
| 28 | plan.Sources = append(plan.Sources, mapping) |
| 29 | } |
| 30 | } |
| 31 | slices.SortFunc(plan.Sources, func(a, b SourceMapping) int { return strings.Compare(a.SourceKey, b.SourceKey) }) |
| 32 | return json.Marshal(plan) |
| 33 | } |
| 34 |