From 6c2f7089b65c5e3eb5c3e65210abc0147f97ff45 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Tue, 2 Jun 2026 15:50:30 +0900 Subject: [PATCH] internal/pkg: destroy unreachable status entries These must be destroyed alongside their corresponding identifier or substitute entries to avoid inconsistent state. Signed-off-by: Ophestra --- internal/pkg/clean.go | 14 ++++++++++++++ internal/pkg/clean_test.go | 31 ++++++++++++++++--------------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/internal/pkg/clean.go b/internal/pkg/clean.go index addcd32d..efeb40de 100644 --- a/internal/pkg/clean.go +++ b/internal/pkg/clean.go @@ -80,6 +80,13 @@ func (c *Cache) Clean(dry, inputs bool, keep ...Artifact) ( destroyedIdents := make([]unique.Handle[ID], 0, len(idents)) for _, pair := range idents { if !dry { + if err = os.Remove(c.base.Append( + dirStatus, + pair.name, + ).String()); err != nil && !errors.Is(err, os.ErrNotExist) { + return destroyedIdents, nil, err + } + if err = os.Remove(c.base.Append( dirIdentifier, pair.name, @@ -125,6 +132,13 @@ func (c *Cache) Clean(dry, inputs bool, keep ...Artifact) ( c.msg.Verbosef("destroying substitute %s...", name) if !dry { + if err = os.Remove(c.base.Append( + dirStatus, + name, + ).String()); err != nil && !errors.Is(err, os.ErrNotExist) { + return destroyedIdents, nil, err + } + if err = os.Remove(c.base.Append( dirSubstitute, name, diff --git a/internal/pkg/clean_test.go b/internal/pkg/clean_test.go index 9b71a777..4b2385a3 100644 --- a/internal/pkg/clean_test.go +++ b/internal/pkg/clean_test.go @@ -143,13 +143,6 @@ func TestClean(t *testing.T) { deps: []pkg.Artifact{ pkg.NewFile("destroyed-input", []byte("destroyed")), }, - cure: func(f *pkg.FContext) error { - p := f.GetWorkDir() - if err := os.MkdirAll(p.String(), 0755); err != nil { - return err - } - return os.WriteFile(p.Append("result").String(), nil, 0444) - }, }), }, []unique.Handle[pkg.Checksum]{ unique.Make(sha512.Sum384([]byte("destroyed"))), @@ -163,6 +156,12 @@ func TestClean(t *testing.T) { pkg.NewFile("destroyed-input", []byte("destroyed")), }, cure: func(f *pkg.FContext) error { + if w, err := f.GetStatusWriter(); err != nil { + return err + } else if _, err = w.Write([]byte("destroyed")); err != nil { + return err + } + p := f.GetWorkDir() if err := os.MkdirAll(p.String(), 0755); err != nil { return err @@ -178,6 +177,12 @@ func TestClean(t *testing.T) { pkg.NewFile("kept-input", []byte("kept")), }, cure: func(f *pkg.FContext) error { + if w, err := f.GetStatusWriter(); err != nil { + return err + } else if _, err = w.Write([]byte("kept")); err != nil { + return err + } + p := f.GetWorkDir() if err := os.MkdirAll(p.String(), 0755); err != nil { return err @@ -199,7 +204,10 @@ func TestClean(t *testing.T) { "lock": {Mode: 0644}, "variant": {Mode: 0400}, - "status": {Mode: fs.ModeDir | 0700}, + + "status": {Mode: fs.ModeDir | 0700}, + "status/4bjS-QjGcSV4nth-W6Vg3-wolKmKgiq4Ld2oRIWcOfy6Wi41XXLAWPoo8FcDx6BH": {Mode: 0400, Data: []byte(statusHeader + "kept")}, + "status/xoIGLemzLF227e-w_AJcf_1Sgqh2gs3KFgqvOIWUQE-9P_y2vHBMBytL4GRGQqTb": {Mode: 0400, Data: []byte(statusHeader + "kept")}, "substitute": {Mode: fs.ModeDir | 0700}, "substitute/4bjS-QjGcSV4nth-W6Vg3-wolKmKgiq4Ld2oRIWcOfy6Wi41XXLAWPoo8FcDx6BH": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CyDnDvF-LaeGPcSW70tPosNCoclByWkTjznUUF1DcgzlIwkN9yzz1ZFME1TlPj6W")}, @@ -214,13 +222,6 @@ func TestClean(t *testing.T) { deps: []pkg.Artifact{ pkg.NewFile("destroyed-input", []byte("destroyed")), }, - cure: func(f *pkg.FContext) error { - p := f.GetWorkDir() - if err := os.MkdirAll(p.String(), 0755); err != nil { - return err - } - return os.WriteFile(p.Append("result").String(), nil, 0444) - }, }), }, []unique.Handle[pkg.Checksum]{ unique.Make(expectsFS{