Skip to content

Commit ada44e8

Browse files
authored
Merge pull request #2900 from crazy-max/bake-list-flag
bake: replace --list-targets and --list-variables flags with --list flag
2 parents 16edf5d + 11c85b2 commit ada44e8

File tree

4 files changed

+136
-34
lines changed

4 files changed

+136
-34
lines changed

bake/hclparser/hclparser.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -579,9 +579,9 @@ func (p *parser) validateVariables(vars map[string]*variable, ectx *hcl.EvalCont
579579
}
580580

581581
type Variable struct {
582-
Name string
583-
Description string
584-
Value *string
582+
Name string `json:"name"`
583+
Description string `json:"description,omitempty"`
584+
Value *string `json:"value,omitempty"`
585585
}
586586

587587
type ParseMeta struct {

commands/bake.go

Lines changed: 130 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"github.com/docker/buildx/controller/pb"
2626
"github.com/docker/buildx/localstate"
2727
"github.com/docker/buildx/util/buildflags"
28-
"github.com/docker/buildx/util/cobrautil"
2928
"github.com/docker/buildx/util/cobrautil/completion"
3029
"github.com/docker/buildx/util/confutil"
3130
"github.com/docker/buildx/util/desktop"
@@ -38,24 +37,30 @@ import (
3837
"github.com/moby/buildkit/util/progress/progressui"
3938
"github.com/pkg/errors"
4039
"github.com/spf13/cobra"
40+
"github.com/tonistiigi/go-csvvalue"
4141
"go.opentelemetry.io/otel/attribute"
4242
)
4343

4444
type bakeOptions struct {
45-
files []string
46-
overrides []string
47-
printOnly bool
48-
listTargets bool
49-
listVars bool
50-
sbom string
51-
provenance string
52-
allow []string
45+
files []string
46+
overrides []string
47+
48+
sbom string
49+
provenance string
50+
allow []string
5351

5452
builder string
5553
metadataFile string
5654
exportPush bool
5755
exportLoad bool
5856
callFunc string
57+
58+
print bool
59+
list string
60+
61+
// TODO: remove deprecated flags
62+
listTargets bool
63+
listVars bool
5964
}
6065

6166
func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in bakeOptions, cFlags commonFlags) (err error) {
@@ -121,9 +126,13 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
121126
var nodes []builder.Node
122127
var progressConsoleDesc, progressTextDesc string
123128

129+
if in.print && in.list != "" {
130+
return errors.New("--print and --list are mutually exclusive")
131+
}
132+
124133
// instance only needed for reading remote bake files or building
125134
var driverType string
126-
if url != "" || !(in.printOnly || in.listTargets || in.listVars) {
135+
if url != "" || !(in.print || in.list != "") {
127136
b, err := builder.New(dockerCli,
128137
builder.WithName(in.builder),
129138
builder.WithContextPathHash(contextPathHash),
@@ -184,18 +193,23 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
184193
"BAKE_LOCAL_PLATFORM": platforms.Format(platforms.DefaultSpec()),
185194
}
186195

187-
if in.listTargets || in.listVars {
196+
if in.list != "" {
188197
cfg, pm, err := bake.ParseFiles(files, defaults)
189198
if err != nil {
190199
return err
191200
}
192201
if err = printer.Wait(); err != nil {
193202
return err
194203
}
195-
if in.listTargets {
196-
return printTargetList(dockerCli.Out(), cfg)
197-
} else if in.listVars {
198-
return printVars(dockerCli.Out(), pm.AllVariables)
204+
list, err := parseList(in.list)
205+
if err != nil {
206+
return err
207+
}
208+
switch list.Type {
209+
case "targets":
210+
return printTargetList(dockerCli.Out(), list.Format, cfg)
211+
case "variables":
212+
return printVars(dockerCli.Out(), list.Format, pm.AllVariables)
199213
}
200214
}
201215

@@ -231,7 +245,7 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
231245
Target: tgts,
232246
}
233247

234-
if in.printOnly {
248+
if in.print {
235249
if err = printer.Wait(); err != nil {
236250
return err
237251
}
@@ -427,6 +441,13 @@ func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
427441
if !cmd.Flags().Lookup("pull").Changed {
428442
cFlags.pull = nil
429443
}
444+
if options.list == "" {
445+
if options.listTargets {
446+
options.list = "targets"
447+
} else if options.listVars {
448+
options.list = "variables"
449+
}
450+
}
430451
options.builder = rootOpts.builder
431452
options.metadataFile = cFlags.metadataFile
432453
// Other common flags (noCache, pull and progress) are processed in runBake function.
@@ -439,7 +460,6 @@ func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
439460

440461
flags.StringArrayVarP(&options.files, "file", "f", []string{}, "Build definition file")
441462
flags.BoolVar(&options.exportLoad, "load", false, `Shorthand for "--set=*.output=type=docker"`)
442-
flags.BoolVar(&options.printOnly, "print", false, "Print the options without building")
443463
flags.BoolVar(&options.exportPush, "push", false, `Shorthand for "--set=*.output=type=registry"`)
444464
flags.StringVar(&options.sbom, "sbom", "", `Shorthand for "--set=*.attest=type=sbom"`)
445465
flags.StringVar(&options.provenance, "provenance", "", `Shorthand for "--set=*.attest=type=provenance"`)
@@ -450,13 +470,16 @@ func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
450470
flags.VarPF(callAlias(&options.callFunc, "check"), "check", "", `Shorthand for "--call=check"`)
451471
flags.Lookup("check").NoOptDefVal = "true"
452472

473+
flags.BoolVar(&options.print, "print", false, "Print the options without building")
474+
flags.StringVar(&options.list, "list", "", "List targets or variables")
475+
476+
// TODO: remove deprecated flags
453477
flags.BoolVar(&options.listTargets, "list-targets", false, "List available targets")
454-
cobrautil.MarkFlagsExperimental(flags, "list-targets")
455478
flags.MarkHidden("list-targets")
456-
479+
flags.MarkDeprecated("list-targets", "list-targets is deprecated, use list=targets instead")
457480
flags.BoolVar(&options.listVars, "list-variables", false, "List defined variables")
458-
cobrautil.MarkFlagsExperimental(flags, "list-variables")
459481
flags.MarkHidden("list-variables")
482+
flags.MarkDeprecated("list-variables", "list-variables is deprecated, use list=variables instead")
460483

461484
commonBuildFlags(&cFlags, flags)
462485

@@ -557,10 +580,70 @@ func readBakeFiles(ctx context.Context, nodes []builder.Node, url string, names
557580
return
558581
}
559582

560-
func printVars(w io.Writer, vars []*hclparser.Variable) error {
583+
type listEntry struct {
584+
Type string
585+
Format string
586+
}
587+
588+
func parseList(input string) (listEntry, error) {
589+
res := listEntry{}
590+
591+
fields, err := csvvalue.Fields(input, nil)
592+
if err != nil {
593+
return res, err
594+
}
595+
596+
if len(fields) == 1 && fields[0] == input && !strings.HasPrefix(input, "type=") {
597+
res.Type = input
598+
}
599+
600+
if res.Type == "" {
601+
for _, field := range fields {
602+
key, value, ok := strings.Cut(field, "=")
603+
if !ok {
604+
return res, errors.Errorf("invalid value %s", field)
605+
}
606+
key = strings.TrimSpace(strings.ToLower(key))
607+
switch key {
608+
case "type":
609+
res.Type = value
610+
case "format":
611+
res.Format = value
612+
default:
613+
return res, errors.Errorf("unexpected key '%s' in '%s'", key, field)
614+
}
615+
}
616+
}
617+
if res.Format == "" {
618+
res.Format = "table"
619+
}
620+
621+
switch res.Type {
622+
case "targets", "variables":
623+
default:
624+
return res, errors.Errorf("invalid list type %q", res.Type)
625+
}
626+
627+
switch res.Format {
628+
case "table", "json":
629+
default:
630+
return res, errors.Errorf("invalid list format %q", res.Format)
631+
}
632+
633+
return res, nil
634+
}
635+
636+
func printVars(w io.Writer, format string, vars []*hclparser.Variable) error {
561637
slices.SortFunc(vars, func(a, b *hclparser.Variable) int {
562638
return cmp.Compare(a.Name, b.Name)
563639
})
640+
641+
if format == "json" {
642+
enc := json.NewEncoder(w)
643+
enc.SetIndent("", " ")
644+
return enc.Encode(vars)
645+
}
646+
564647
tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
565648
defer tw.Flush()
566649

@@ -578,12 +661,7 @@ func printVars(w io.Writer, vars []*hclparser.Variable) error {
578661
return nil
579662
}
580663

581-
func printTargetList(w io.Writer, cfg *bake.Config) error {
582-
tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
583-
defer tw.Flush()
584-
585-
tw.Write([]byte("TARGET\tDESCRIPTION\n"))
586-
664+
func printTargetList(w io.Writer, format string, cfg *bake.Config) error {
587665
type targetOrGroup struct {
588666
name string
589667
target *bake.Target
@@ -602,6 +680,20 @@ func printTargetList(w io.Writer, cfg *bake.Config) error {
602680
return cmp.Compare(a.name, b.name)
603681
})
604682

683+
var tw *tabwriter.Writer
684+
if format == "table" {
685+
tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
686+
defer tw.Flush()
687+
tw.Write([]byte("TARGET\tDESCRIPTION\n"))
688+
}
689+
690+
type targetList struct {
691+
Name string `json:"name"`
692+
Description string `json:"description,omitempty"`
693+
Group bool `json:"group,omitempty"`
694+
}
695+
var targetsList []targetList
696+
605697
for _, tgt := range list {
606698
if strings.HasPrefix(tgt.name, "_") {
607699
// convention for a private target
@@ -610,9 +702,9 @@ func printTargetList(w io.Writer, cfg *bake.Config) error {
610702
var descr string
611703
if tgt.target != nil {
612704
descr = tgt.target.Description
705+
targetsList = append(targetsList, targetList{Name: tgt.name, Description: descr})
613706
} else if tgt.group != nil {
614707
descr = tgt.group.Description
615-
616708
if len(tgt.group.Targets) > 0 {
617709
slices.Sort(tgt.group.Targets)
618710
names := strings.Join(tgt.group.Targets, ", ")
@@ -622,8 +714,17 @@ func printTargetList(w io.Writer, cfg *bake.Config) error {
622714
descr = names
623715
}
624716
}
717+
targetsList = append(targetsList, targetList{Name: tgt.name, Description: descr, Group: true})
625718
}
626-
fmt.Fprintf(tw, "%s\t%s\n", tgt.name, descr)
719+
if format == "table" {
720+
fmt.Fprintf(tw, "%s\t%s\n", tgt.name, descr)
721+
}
722+
}
723+
724+
if format == "json" {
725+
enc := json.NewEncoder(w)
726+
enc.SetIndent("", " ")
727+
return enc.Encode(targetsList)
627728
}
628729

629730
return nil

docs/reference/buildx_bake.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Build from a file
2121
| [`--check`](#check) | `bool` | | Shorthand for `--call=check` |
2222
| `-D`, `--debug` | `bool` | | Enable debug logging |
2323
| [`-f`](#file), [`--file`](#file) | `stringArray` | | Build definition file |
24+
| `--list` | `string` | | List targets or variables |
2425
| `--load` | `bool` | | Shorthand for `--set=*.output=type=docker` |
2526
| [`--metadata-file`](#metadata-file) | `string` | | Write build result metadata to a file |
2627
| [`--no-cache`](#no-cache) | `bool` | | Do not use cache when building the image |

tests/bake.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,7 +1599,7 @@ target "abc" {
15991599
out, err := bakeCmd(
16001600
sb,
16011601
withDir(dir),
1602-
withArgs("--list-targets"),
1602+
withArgs("--list=targets"),
16031603
)
16041604
require.NoError(t, err, out)
16051605

@@ -1628,7 +1628,7 @@ target "default" {
16281628
out, err := bakeCmd(
16291629
sb,
16301630
withDir(dir),
1631-
withArgs("--list-variables"),
1631+
withArgs("--list=variables"),
16321632
)
16331633
require.NoError(t, err, out)
16341634

0 commit comments

Comments
 (0)