github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/build/image_reaper.go (about) 1 package build 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "github.com/pkg/errors" 9 "golang.org/x/sync/errgroup" 10 11 "github.com/distribution/reference" 12 "github.com/docker/docker/api/types" 13 "github.com/docker/docker/api/types/filters" 14 "github.com/docker/docker/client" 15 16 "github.com/tilt-dev/tilt/internal/docker" 17 "github.com/tilt-dev/tilt/internal/dockerfile" 18 ) 19 20 type ImageReaper struct { 21 docker docker.Client 22 } 23 24 func FilterByLabel(label dockerfile.Label) filters.KeyValuePair { 25 return filters.Arg("label", string(label)) 26 } 27 28 func FilterByLabelValue(label dockerfile.Label, val dockerfile.LabelValue) filters.KeyValuePair { 29 return filters.Arg("label", fmt.Sprintf("%s=%s", label, val)) 30 } 31 32 func FilterByRefName(ref reference.Named) filters.KeyValuePair { 33 return filters.Arg("reference", fmt.Sprintf("%s:*", ref.Name())) 34 } 35 36 func NewImageReaper(docker docker.Client) ImageReaper { 37 return ImageReaper{ 38 docker: docker, 39 } 40 } 41 42 // Delete all Tilt builds 43 // 44 // For safety reasons, we only delete images with the tilt.buildMode label, 45 // but we let the caller set additional filters. 46 func (r ImageReaper) RemoveTiltImages(ctx context.Context, createdBefore time.Time, force bool, extraFilters ...filters.KeyValuePair) error { 47 defaultFilter := FilterByLabel(BuildMode) 48 filterList := append([]filters.KeyValuePair{defaultFilter}, extraFilters...) 49 listOptions := types.ImageListOptions{ 50 Filters: filters.NewArgs(filterList...), 51 } 52 53 summaries, err := r.docker.ImageList(ctx, listOptions) 54 if err != nil { 55 return errors.Wrap(err, "RemoveTiltImages") 56 } 57 58 g, ctx := errgroup.WithContext(ctx) 59 rmOptions := types.ImageRemoveOptions{ 60 PruneChildren: true, 61 Force: force, 62 } 63 for _, summary := range summaries { 64 id := summary.ID 65 created := time.Unix(summary.Created, 0) 66 if !created.Before(createdBefore) { 67 continue 68 } 69 70 g.Go(func() error { 71 _, err := r.docker.ImageRemove(ctx, id, rmOptions) 72 if client.IsErrNotFound(err) { 73 return nil 74 } 75 return err 76 }) 77 } 78 79 err = g.Wait() 80 if err != nil { 81 return errors.Wrap(err, "RemoveTiltImages") 82 } 83 return err 84 }