Repository: moby/moby
File: client/build_prune.go (Go)

Code before:
package client

import (
	"context"
	"encoding/json"
	"fmt"
	"net/url"
	"strconv"

	"github.com/moby/moby/api/types/build"
	"github.com/moby/moby/api/types/filters"
)

// BuildCachePruneOptions hold parameters to prune the build cache.
type BuildCachePruneOptions struct {
	All           bool
	ReservedSpace int64
	MaxUsedSpace  int64
	MinFreeSpace  int64
	Filters       filters.Args

	KeepStorage int64 // Deprecated: deprecated in API 1.48.
}

// BuildCachePrune requests the daemon to delete unused cache data.
func (cli *Client) BuildCachePrune(ctx context.Context, opts BuildCachePruneOptions) (*build.CachePruneReport, error) {
	if err := cli.NewVersionError(ctx, "1.31", "build prune"); err != nil {
		return nil, err
	}

	query := url.Values{}
	if opts.All {
		query.Set("all", "1")
	}

	if opts.KeepStorage != 0 {
		query.Set("keep-storage", strconv.Itoa(int(opts.KeepStorage)))
	}
	if opts.ReservedSpace != 0 {
		query.Set("reserved-space", strconv.Itoa(int(opts.ReservedSpace)))
	}
	if opts.MaxUsedSpace != 0 {
		query.Set("max-used-space", strconv.Itoa(int(opts.MaxUsedSpace)))
	}
	if opts.MinFreeSpace != 0 {
		query.Set("min-free-space", strconv.Itoa(int(opts.MinFreeSpace)))
	}

Review comment (bug):
Wondering if there's any mapping possible from the above options to the old option.

i.e., thinking if we can somehow keep the `KeepStorage` an internal implementation detail and set it automatically based on the other options when talking to an older API. 

Actually, I"m not even sure now if we even use any of these (bear with me);

When running with buildx installed,  `docker builder prune` is executed by `buildx`;



```console
docker builder prune --help
Usage:  docker buildx prune

Remove build cache

Options:
  -a, --all                    Include internal/frontend images
      --builder string         Override the configured builder instance (default "desktop-linux")
  -D, --debug                  Enable debug logging
      --filter filter          Provide filter values (e.g., "until=24h")
  -f, --force                  Do not prompt for confirmation
      --max-used-space bytes   Maximum amount of disk space allowed to keep for cache
      --min-free-space bytes   Target amount of free disk space after pruning
      --reserved-space bytes   Amount of disk space always allowed to keep for cache
      --verbose                Provide a more verbose output
```

When buildx is missing, or explicitly disabled, only then we get the `docker builder prune` command from the CLI itself;

```bash
DOCKER_BUILDKIT=0 docker builder prune --help
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
            BuildKit is currently disabled; enable it by removing the DOCKER_BUILDKIT=0
            environment-variable.

Usage:  docker builder prune

Remove build cache

Options:
  -a, --all                  Remove all unused build cache, not just dangling ones
      --filter filter        Provide filter values (e.g. "until=24h")
  -f, --force                Do not prompt for confirmation
      --keep-storage bytes   Amount of disk space to keep for cache
```

But I don't think "pruning build cache" makes sense if you don't have buildkit 🤔 


### so are we _never_ using it?

Well, we are, but only as part of `docker system prune`, because that also calls the "builder prune" endpoint through the REST API;

https://github.com/docker/cli/blob/v28.3.3/cli/command/system/prune.go#L44-L45
https://github.com/docker/cli/blob/v28.3.3/cli/command/system/prune.go#L96-L98


But honestly, not even sure if that should be called if BuildKit is disabled (only if enabled), and it does not allow options to be passed, or only very limited.


When running `docker buildx prune` (or the `docker builder prune` alias) with BuildKit enabled (so now `docker buildx` is executed), I don't think we even hit the REST API. This could also mean that running `docker buildx prune` won't trigger docker daemon events 🤔 https://github.com/docker/buildx/blob/v0.27.0/commands/prune.go#L43-L47


(thinking about https://github.com/moby/moby/pull/50725 where Docker Desktop didn't receive some events)







Code after:
package client

import (
	"context"
	"encoding/json"
	"fmt"
	"net/url"
	"strconv"

	"github.com/moby/moby/api/types/build"
	"github.com/moby/moby/api/types/filters"
	"github.com/moby/moby/api/types/versions"
)

// BuildCachePruneOptions hold parameters to prune the build cache.
type BuildCachePruneOptions struct {
	All           bool
	ReservedSpace int64
	MaxUsedSpace  int64
	MinFreeSpace  int64
	Filters       filters.Args
}

// BuildCachePrune requests the daemon to delete unused cache data.
func (cli *Client) BuildCachePrune(ctx context.Context, opts BuildCachePruneOptions) (*build.CachePruneReport, error) {
	if err := cli.NewVersionError(ctx, "1.31", "build prune"); err != nil {
		return nil, err
	}

	query := url.Values{}
	if opts.All {
		query.Set("all", "1")
	}

	if opts.ReservedSpace != 0 {
		// Prior to API v1.48, 'keep-storage' was used to set the reserved space for the build cache.
		// TODO(austinvazquez): remove once API v1.47 is no longer supported. See https://github.com/moby/moby/issues/50902
		if versions.LessThanOrEqualTo(cli.version, "1.47") {
			query.Set("keep-storage", strconv.Itoa(int(opts.ReservedSpace)))
		} else {
			query.Set("reserved-space", strconv.Itoa(int(opts.ReservedSpace)))
		}
	}
	if opts.MaxUsedSpace != 0 {
		query.Set("max-used-space", strconv.Itoa(int(opts.MaxUsedSpace)))
	}
	if opts.MinFreeSpace != 0 {