Skip to content

Commit ef6b9ce

Browse files
committed
Add buildx history command
These commands allow working with build records of completed and running builds. Signed-off-by: Tonis Tiigi <[email protected]>
1 parent 206bd6c commit ef6b9ce

29 files changed

+1258
-9
lines changed

commands/history/inspect.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package history
2+
3+
import (
4+
"context"
5+
"log"
6+
"slices"
7+
8+
"github.com/docker/buildx/builder"
9+
"github.com/docker/buildx/localstate"
10+
"github.com/docker/buildx/util/cobrautil/completion"
11+
"github.com/docker/buildx/util/confutil"
12+
"github.com/docker/cli/cli/command"
13+
"github.com/pkg/errors"
14+
"github.com/spf13/cobra"
15+
)
16+
17+
type inspectOptions struct {
18+
builder string
19+
ref string
20+
}
21+
22+
func runInspect(ctx context.Context, dockerCli command.Cli, opts inspectOptions) error {
23+
b, err := builder.New(dockerCli, builder.WithName(opts.builder))
24+
if err != nil {
25+
return err
26+
}
27+
28+
nodes, err := b.LoadNodes(ctx)
29+
if err != nil {
30+
return err
31+
}
32+
for _, node := range nodes {
33+
if node.Err != nil {
34+
return node.Err
35+
}
36+
}
37+
38+
recs, err := queryRecords(ctx, opts.ref, nodes)
39+
if err != nil {
40+
return err
41+
}
42+
43+
if len(recs) == 0 {
44+
if opts.ref == "" {
45+
return errors.New("no records found")
46+
}
47+
return errors.Errorf("no record found for ref %q", opts.ref)
48+
}
49+
50+
if opts.ref == "" {
51+
slices.SortFunc(recs, func(a, b historyRecord) int {
52+
return b.CreatedAt.AsTime().Compare(a.CreatedAt.AsTime())
53+
})
54+
}
55+
56+
rec := &recs[0]
57+
58+
ls, err := localstate.New(confutil.NewConfig(dockerCli))
59+
if err != nil {
60+
return err
61+
}
62+
st, _ := ls.ReadRef(rec.node.Builder, rec.node.Name, rec.Ref)
63+
64+
log.Printf("rec %+v", rec)
65+
log.Printf("st %+v", st)
66+
67+
// Context
68+
// Dockerfile
69+
// Target
70+
// VCS Repo / Commit
71+
// Platform
72+
73+
// Started
74+
// Duration
75+
// Number of steps
76+
// Cached steps
77+
// Status
78+
79+
// build-args
80+
// exporters (image)
81+
82+
// commands
83+
// error
84+
// materials
85+
86+
return nil
87+
}
88+
89+
func inspectCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
90+
var options inspectOptions
91+
92+
cmd := &cobra.Command{
93+
Use: "inspect [OPTIONS] [REF]",
94+
Short: "Inspect a build",
95+
Args: cobra.MaximumNArgs(1),
96+
RunE: func(cmd *cobra.Command, args []string) error {
97+
if len(args) > 0 {
98+
options.ref = args[0]
99+
}
100+
options.builder = *rootOpts.Builder
101+
return runInspect(cmd.Context(), dockerCli, options)
102+
},
103+
ValidArgsFunction: completion.Disable,
104+
}
105+
106+
// flags := cmd.Flags()
107+
108+
return cmd
109+
}

commands/history/logs.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package history
2+
3+
import (
4+
"context"
5+
"io"
6+
"os"
7+
"slices"
8+
9+
"github.com/docker/buildx/builder"
10+
"github.com/docker/buildx/util/cobrautil/completion"
11+
"github.com/docker/buildx/util/progress"
12+
"github.com/docker/cli/cli/command"
13+
controlapi "github.com/moby/buildkit/api/services/control"
14+
"github.com/moby/buildkit/client"
15+
"github.com/moby/buildkit/util/progress/progressui"
16+
"github.com/pkg/errors"
17+
"github.com/spf13/cobra"
18+
)
19+
20+
type logsOptions struct {
21+
builder string
22+
ref string
23+
progress string
24+
}
25+
26+
func runLogs(ctx context.Context, dockerCli command.Cli, opts logsOptions) error {
27+
b, err := builder.New(dockerCli, builder.WithName(opts.builder))
28+
if err != nil {
29+
return err
30+
}
31+
32+
nodes, err := b.LoadNodes(ctx)
33+
if err != nil {
34+
return err
35+
}
36+
for _, node := range nodes {
37+
if node.Err != nil {
38+
return node.Err
39+
}
40+
}
41+
42+
recs, err := queryRecords(ctx, opts.ref, nodes)
43+
if err != nil {
44+
return err
45+
}
46+
47+
if len(recs) == 0 {
48+
if opts.ref == "" {
49+
return errors.New("no records found")
50+
}
51+
return errors.Errorf("no record found for ref %q", opts.ref)
52+
}
53+
54+
if opts.ref == "" {
55+
slices.SortFunc(recs, func(a, b historyRecord) int {
56+
return b.CreatedAt.AsTime().Compare(a.CreatedAt.AsTime())
57+
})
58+
}
59+
60+
rec := &recs[0]
61+
c, err := rec.node.Driver.Client(ctx)
62+
if err != nil {
63+
return err
64+
}
65+
66+
cl, err := c.ControlClient().Status(ctx, &controlapi.StatusRequest{
67+
Ref: rec.Ref,
68+
})
69+
if err != nil {
70+
return err
71+
}
72+
73+
var mode progressui.DisplayMode = progressui.DisplayMode(opts.progress)
74+
if mode == progressui.AutoMode {
75+
mode = progressui.PlainMode
76+
}
77+
printer, err := progress.NewPrinter(context.TODO(), os.Stderr, mode)
78+
if err != nil {
79+
return err
80+
}
81+
82+
loop0:
83+
for {
84+
select {
85+
case <-ctx.Done():
86+
cl.CloseSend()
87+
return ctx.Err()
88+
default:
89+
ev, err := cl.Recv()
90+
if err != nil {
91+
if errors.Is(err, io.EOF) {
92+
break loop0
93+
}
94+
return err
95+
}
96+
printer.Write(client.NewSolveStatus(ev))
97+
}
98+
}
99+
100+
return printer.Wait()
101+
}
102+
103+
func logsCmd(dockerCli command.Cli, rootOpts RootOptions) *cobra.Command {
104+
var options logsOptions
105+
106+
cmd := &cobra.Command{
107+
Use: "logs [OPTIONS] [REF]",
108+
Short: "Print the logs of a build",
109+
Args: cobra.MaximumNArgs(1),
110+
RunE: func(cmd *cobra.Command, args []string) error {
111+
if len(args) > 0 {
112+
options.ref = args[0]
113+
}
114+
options.builder = *rootOpts.Builder
115+
return runLogs(cmd.Context(), dockerCli, options)
116+
},
117+
ValidArgsFunction: completion.Disable,
118+
}
119+
120+
flags := cmd.Flags()
121+
flags.StringVar(&options.progress, "progress", "plain", "Set type of progress output (plain, rawjson, tty)")
122+
123+
return cmd
124+
}

0 commit comments

Comments
 (0)