From c834ba1389791628783d2b6948f21605fa9afcb5 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Fri, 5 Aug 2022 00:25:39 -0700 Subject: [PATCH] add formatting support to print function Signed-off-by: Tonis Tiigi --- build/build.go | 15 ++++++++++----- commands/build.go | 37 +++++++++++++++++++++++++++++++++++-- commands/print.go | 35 ++++++++++++++++++++++++----------- 3 files changed, 69 insertions(+), 18 deletions(-) diff --git a/build/build.go b/build/build.go index fcda564f..25726184 100644 --- a/build/build.go +++ b/build/build.go @@ -87,7 +87,12 @@ type Options struct { // Linked marks this target as exclusively linked (not requested by the user). Linked bool - PrintFunc string + PrintFunc *PrintFunc +} + +type PrintFunc struct { + Name string + Format string } type Inputs struct { @@ -1050,13 +1055,13 @@ func BuildWithResultHandler(ctx context.Context, drivers []DriverInfo, opt map[s var isFallback bool var origErr error for { - if opt.PrintFunc != "" { + if opt.PrintFunc != nil { if _, ok := req.FrontendOpt["frontend.caps"]; !ok { req.FrontendOpt["frontend.caps"] = "moby.buildkit.frontend.subrequests+forward" } else { req.FrontendOpt["frontend.caps"] += ",moby.buildkit.frontend.subrequests+forward" } - req.FrontendOpt["requestid"] = "frontend." + opt.PrintFunc + req.FrontendOpt["requestid"] = "frontend." + opt.PrintFunc.Name if isFallback { req.FrontendOpt["build-arg:BUILDKIT_SYNTAX"] = printFallbackImage } @@ -1086,7 +1091,7 @@ func BuildWithResultHandler(ctx context.Context, drivers []DriverInfo, opt map[s } return nil, err } - if opt.PrintFunc != "" { + if opt.PrintFunc != nil { printRes = res.Metadata } results.Set(resultKey(dp.driverIndex, k), res) @@ -1686,7 +1691,7 @@ func tryNodeIdentifier(configDir string) (out string) { func noPrintFunc(opt map[string]Options) bool { for _, v := range opt { - if v.PrintFunc != "" { + if v.PrintFunc != nil { return false } } diff --git a/commands/build.go b/commands/build.go index d1d15dd4..50520874 100644 --- a/commands/build.go +++ b/commands/build.go @@ -123,6 +123,11 @@ func runBuild(dockerCli command.Cli, in buildOptions) (err error) { return err } + printFunc, err := parsePrintFunc(in.printFunc) + if err != nil { + return err + } + opts := build.Options{ Inputs: build.Inputs{ ContextPath: in.contextPath, @@ -142,7 +147,7 @@ func runBuild(dockerCli command.Cli, in buildOptions) (err error) { Tags: in.tags, Target: in.target, Ulimits: in.ulimits, - PrintFunc: in.printFunc, + PrintFunc: printFunc, } platforms, err := platformutil.Parse(in.platforms) @@ -310,7 +315,7 @@ func buildTargets(ctx context.Context, dockerCli command.Cli, opts map[string]bu printWarnings(os.Stderr, printer.Warnings(), progressMode) for k := range resp { - if opts[k].PrintFunc != "" { + if opts[k].PrintFunc != nil { if err := printResult(opts[k].PrintFunc, resp[k].ExporterResponse); err != nil { return "", nil, err } @@ -610,6 +615,34 @@ func parseContextNames(values []string) (map[string]build.NamedContext, error) { return result, nil } +func parsePrintFunc(str string) (*build.PrintFunc, error) { + if str == "" { + return nil, nil + } + csvReader := csv.NewReader(strings.NewReader(str)) + fields, err := csvReader.Read() + if err != nil { + return nil, err + } + f := &build.PrintFunc{} + for _, field := range fields { + parts := strings.SplitN(field, "=", 2) + if len(parts) == 2 { + if parts[0] == "format" { + f.Format = parts[1] + } else { + return nil, errors.Errorf("invalid print field: %s", field) + } + } else { + if f.Name != "" { + return nil, errors.Errorf("invalid print value: %s", str) + } + f.Name = field + } + } + return f, nil +} + func writeMetadataFile(filename string, dt interface{}) error { b, err := json.MarshalIndent(dt, "", " ") if err != nil { diff --git a/commands/print.go b/commands/print.go index 856470e2..9c7f9460 100644 --- a/commands/print.go +++ b/commands/print.go @@ -2,28 +2,25 @@ package commands import ( "fmt" + "io" "log" "os" + "github.com/docker/buildx/build" + "github.com/docker/docker/api/types/versions" "github.com/moby/buildkit/frontend/subrequests" "github.com/moby/buildkit/frontend/subrequests/outline" "github.com/moby/buildkit/frontend/subrequests/targets" ) -func printResult(f string, res map[string]string) error { - switch f { +func printResult(f *build.PrintFunc, res map[string]string) error { + switch f.Name { case "outline": - if err := outline.PrintOutline([]byte(res["result.json"]), os.Stdout); err != nil { - return err - } + return printValue(outline.PrintOutline, outline.SubrequestsOutlineDefinition.Version, f.Format, res) case "targets": - if err := targets.PrintTargets([]byte(res["result.json"]), os.Stdout); err != nil { - return err - } + return printValue(targets.PrintTargets, targets.SubrequestsTargetsDefinition.Version, f.Format, res) case "subrequests.describe": - if err := subrequests.PrintDescribe([]byte(res["result.json"]), os.Stdout); err != nil { - return err - } + return printValue(subrequests.PrintDescribe, subrequests.SubrequestsDescribeDefinition.Version, f.Format, res) default: if dt, ok := res["result.txt"]; ok { fmt.Print(dt) @@ -33,3 +30,19 @@ func printResult(f string, res map[string]string) error { } return nil } + +type printFunc func([]byte, io.Writer) error + +func printValue(printer printFunc, version string, format string, res map[string]string) error { + if format == "json" { + fmt.Fprintln(os.Stdout, res["result.json"]) + return nil + } + + if res["version"] != "" && versions.LessThan(version, res["version"]) && res["result.txt"] != "" { + // structure is too new and we don't know how to print it + fmt.Fprint(os.Stdout, res["result.txt"]) + return nil + } + return printer([]byte(res["result.json"]), os.Stdout) +}