diff --git a/commands/rm.go b/commands/rm.go
index ab19bbef..73f33be9 100644
--- a/commands/rm.go
+++ b/commands/rm.go
@@ -2,36 +2,53 @@ package commands
import (
"context"
+ "time"
"github.com/docker/buildx/store"
"github.com/docker/buildx/store/storeutil"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/moby/buildkit/util/appcontext"
+ "github.com/pkg/errors"
"github.com/spf13/cobra"
+ "golang.org/x/sync/errgroup"
)
type rmOptions struct {
- builder string
- keepState bool
- keepDaemon bool
+ builder string
+ keepState bool
+ keepDaemon bool
+ allInactive bool
+ force bool
}
+const (
+ rmInactiveWarning = `WARNING! This will remove all builders that are not in running state. Are you sure you want to continue?`
+)
+
func runRm(dockerCli command.Cli, in rmOptions) error {
ctx := appcontext.Context()
+ if in.allInactive && !in.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), rmInactiveWarning) {
+ return nil
+ }
+
txn, release, err := storeutil.GetStore(dockerCli)
if err != nil {
return err
}
defer release()
+ if in.allInactive {
+ return rmAllInactive(ctx, txn, dockerCli, in)
+ }
+
if in.builder != "" {
ng, err := storeutil.GetNodeGroup(txn, dockerCli, in.builder)
if err != nil {
return err
}
- err1 := rm(ctx, dockerCli, ng, in.keepState, in.keepDaemon)
+ err1 := rm(ctx, dockerCli, in, ng)
if err := txn.Remove(ng.Name); err != nil {
return err
}
@@ -43,7 +60,7 @@ func runRm(dockerCli command.Cli, in rmOptions) error {
return err
}
if ng != nil {
- err1 := rm(ctx, dockerCli, ng, in.keepState, in.keepDaemon)
+ err1 := rm(ctx, dockerCli, in, ng)
if err := txn.Remove(ng.Name); err != nil {
return err
}
@@ -63,6 +80,9 @@ func rmCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
options.builder = rootOpts.builder
if len(args) > 0 {
+ if options.allInactive {
+ return errors.New("cannot specify builder name when --all-inactive is set")
+ }
options.builder = args[0]
}
return runRm(dockerCli, options)
@@ -72,11 +92,13 @@ func rmCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
flags := cmd.Flags()
flags.BoolVar(&options.keepState, "keep-state", false, "Keep BuildKit state")
flags.BoolVar(&options.keepDaemon, "keep-daemon", false, "Keep the buildkitd daemon running")
+ flags.BoolVar(&options.allInactive, "all-inactive", false, "Remove all inactive builders")
+ flags.BoolVarP(&options.force, "force", "f", false, "Do not prompt for confirmation")
return cmd
}
-func rm(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, keepState, keepDaemon bool) error {
+func rm(ctx context.Context, dockerCli command.Cli, in rmOptions, ng *store.NodeGroup) error {
dis, err := driversForNodeGroup(ctx, dockerCli, ng, "")
if err != nil {
return err
@@ -86,12 +108,12 @@ func rm(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, keepSta
continue
}
// Do not stop the buildkitd daemon when --keep-daemon is provided
- if !keepDaemon {
+ if !in.keepDaemon {
if err := di.Driver.Stop(ctx, true); err != nil {
return err
}
}
- if err := di.Driver.Rm(ctx, true, !keepState, !keepDaemon); err != nil {
+ if err := di.Driver.Rm(ctx, true, !in.keepState, !in.keepDaemon); err != nil {
return err
}
if di.Err != nil {
@@ -100,3 +122,42 @@ func rm(ctx context.Context, dockerCli command.Cli, ng *store.NodeGroup, keepSta
}
return err
}
+
+func rmAllInactive(ctx context.Context, txn *store.Txn, dockerCli command.Cli, in rmOptions) error {
+ ctx, cancel := context.WithTimeout(ctx, 20*time.Second)
+ defer cancel()
+
+ ll, err := txn.List()
+ if err != nil {
+ return err
+ }
+
+ builders := make([]*nginfo, len(ll))
+ for i, ng := range ll {
+ builders[i] = &nginfo{ng: ng}
+ }
+
+ eg, _ := errgroup.WithContext(ctx)
+ for _, b := range builders {
+ func(b *nginfo) {
+ eg.Go(func() error {
+ if err := loadNodeGroupData(ctx, dockerCli, b); err != nil {
+ return errors.Wrapf(err, "cannot load %s", b.ng.Name)
+ }
+ if b.ng.Dynamic {
+ return nil
+ }
+ if b.inactive() {
+ rmerr := rm(ctx, dockerCli, in, b.ng)
+ if err := txn.Remove(b.ng.Name); err != nil {
+ return err
+ }
+ return rmerr
+ }
+ return nil
+ })
+ }(b)
+ }
+
+ return eg.Wait()
+}
diff --git a/commands/util.go b/commands/util.go
index d4ee40ad..03c28684 100644
--- a/commands/util.go
+++ b/commands/util.go
@@ -389,6 +389,17 @@ type nginfo struct {
err error
}
+// inactive checks if all nodes are inactive for this builder
+func (n *nginfo) inactive() bool {
+ for idx := range n.ng.Nodes {
+ d := n.drivers[idx]
+ if d.info != nil && d.info.Status == driver.Running {
+ return false
+ }
+ }
+ return true
+}
+
func boot(ctx context.Context, ngi *nginfo) (bool, error) {
toBoot := make([]int, 0, len(ngi.drivers))
for i, d := range ngi.drivers {
diff --git a/docs/reference/buildx_rm.md b/docs/reference/buildx_rm.md
index 28ac60cb..dba7a8f2 100644
--- a/docs/reference/buildx_rm.md
+++ b/docs/reference/buildx_rm.md
@@ -11,7 +11,9 @@ Remove a builder instance
| Name | Description |
| --- | --- |
+| [`--all-inactive`](#all-inactive) | Remove all inactive builders |
| [`--builder string`](#builder) | Override the configured builder instance |
+| [`-f`](#force), [`--force`](#force) | Do not prompt for confirmation |
| [`--keep-daemon`](#keep-daemon) | Keep the buildkitd daemon running |
| [`--keep-state`](#keep-state) | Keep BuildKit state |
@@ -25,16 +27,33 @@ default builder.
## Examples
+### Remove all inactive builders (--all-inactive)
+
+Remove builders that are not in running state.
+
+```console
+$ docker buildx rm --all-inactive
+WARNING! This will remove all builders that are not in running state. Are you sure you want to continue? [y/N] y
+```
+
### Override the configured builder instance (--builder)
Same as [`buildx --builder`](buildx.md#builder).
-### Keep BuildKit state (--keep-state)
+### Do not prompt for confirmation (--force)
-Keep BuildKit state, so it can be reused by a new builder with the same name.
-Currently, only supported by the [`docker-container` driver](buildx_create.md#driver).
+Do not prompt for confirmation before removing inactive builders.
+
+```console
+$ docker buildx rm --all-inactive --force
+```
### Keep the buildkitd daemon running (--keep-daemon)
Keep the buildkitd daemon running after the buildx context is removed. This is useful when you manage buildkitd daemons and buildx contexts independently.
Currently, only supported by the [`docker-container` and `kubernetes` drivers](buildx_create.md#driver).
+
+### Keep BuildKit state (--keep-state)
+
+Keep BuildKit state, so it can be reused by a new builder with the same name.
+Currently, only supported by the [`docker-container` driver](buildx_create.md#driver).