Skip to content

Commit 959e6d6

Browse files
authored
Merge pull request moby#3498 from AkihiroSuda/list-refs
buildctl: add `buildctl debug histories, buildctl prune-histories`
2 parents fd0c25c + 167d6c3 commit 959e6d6

File tree

4 files changed

+220
-0
lines changed

4 files changed

+220
-0
lines changed

cmd/buildctl/debug.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ var debugCommand = cli.Command{
1717
debug.LogsCommand,
1818
debug.CtlCommand,
1919
debug.GetCommand,
20+
debug.HistoriesCommand,
2021
},
2122
}

cmd/buildctl/debug/histories.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package debug
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"text/tabwriter"
7+
"time"
8+
9+
controlapi "github.com/moby/buildkit/api/services/control"
10+
bccommon "github.com/moby/buildkit/cmd/buildctl/common"
11+
"github.com/moby/buildkit/util/appcontext"
12+
"github.com/pkg/errors"
13+
"github.com/urfave/cli"
14+
)
15+
16+
var HistoriesCommand = cli.Command{
17+
Name: "histories",
18+
Usage: "list build records",
19+
Action: histories,
20+
Flags: []cli.Flag{
21+
cli.StringFlag{
22+
Name: "format",
23+
Usage: "Format the output using the given Go template, e.g, '{{json .}}'",
24+
},
25+
},
26+
}
27+
28+
func histories(clicontext *cli.Context) error {
29+
c, err := bccommon.ResolveClient(clicontext)
30+
if err != nil {
31+
return err
32+
}
33+
34+
ctx := appcontext.Context()
35+
resp, err := c.ControlClient().ListenBuildHistory(ctx, &controlapi.BuildHistoryRequest{
36+
EarlyExit: true,
37+
})
38+
if err != nil {
39+
return err
40+
}
41+
42+
if format := clicontext.String("format"); format != "" {
43+
tmpl, err := bccommon.ParseTemplate(format)
44+
if err != nil {
45+
return err
46+
}
47+
for {
48+
ev, err := resp.Recv()
49+
if errors.Is(err, io.EOF) {
50+
break
51+
} else if err != nil {
52+
return err
53+
}
54+
if err := tmpl.Execute(clicontext.App.Writer, ev); err != nil {
55+
return err
56+
}
57+
if _, err = fmt.Fprintf(clicontext.App.Writer, "\n"); err != nil {
58+
return err
59+
}
60+
}
61+
return nil
62+
}
63+
return printRecordsTable(clicontext.App.Writer, resp)
64+
}
65+
66+
func printRecordsTable(w io.Writer, eventReceiver controlapi.Control_ListenBuildHistoryClient) error {
67+
tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
68+
fmt.Fprintln(tw, "TYPE\tREF\tCREATED\tCOMPLETED\tGENERATION\tPINNED")
69+
for {
70+
ev, err := eventReceiver.Recv()
71+
if errors.Is(err, io.EOF) {
72+
break
73+
} else if err != nil {
74+
return err
75+
}
76+
var (
77+
ref string
78+
createdAt string
79+
completedAt string
80+
generation int32
81+
pinned string
82+
)
83+
if r := ev.Record; r != nil {
84+
ref = r.Ref
85+
if r.CreatedAt != nil {
86+
createdAt = r.CreatedAt.Local().Format(time.RFC3339)
87+
}
88+
if r.CompletedAt != nil {
89+
completedAt = r.CompletedAt.Local().Format(time.RFC3339)
90+
}
91+
generation = r.Generation
92+
if r.Pinned {
93+
pinned = "*"
94+
}
95+
}
96+
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%d\t%s\n", ev.Type, ref, createdAt, completedAt, generation, pinned)
97+
tw.Flush()
98+
}
99+
return tw.Flush()
100+
}

cmd/buildctl/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ func main() {
9292
app.Commands = []cli.Command{
9393
diskUsageCommand,
9494
pruneCommand,
95+
pruneHistoriesCommand,
9596
buildCommand,
9697
debugCommand,
9798
dialStdioCommand,

cmd/buildctl/prunehistories.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
"text/tabwriter"
8+
"time"
9+
10+
"github.com/hashicorp/go-multierror"
11+
controlapi "github.com/moby/buildkit/api/services/control"
12+
bccommon "github.com/moby/buildkit/cmd/buildctl/common"
13+
"github.com/moby/buildkit/util/appcontext"
14+
"github.com/pkg/errors"
15+
"github.com/urfave/cli"
16+
)
17+
18+
var pruneHistoriesCommand = cli.Command{
19+
Name: "prune-histories",
20+
Usage: "clean up build histories",
21+
Action: pruneHistories,
22+
Flags: []cli.Flag{
23+
cli.StringFlag{
24+
Name: "format",
25+
Usage: "Format the output using the given Go template, e.g, '{{json .}}'",
26+
},
27+
},
28+
}
29+
30+
func pruneHistories(clicontext *cli.Context) error {
31+
c, err := bccommon.ResolveClient(clicontext)
32+
if err != nil {
33+
return err
34+
}
35+
36+
ctx := appcontext.Context()
37+
controlClient := c.ControlClient()
38+
resp, err := controlClient.ListenBuildHistory(ctx, &controlapi.BuildHistoryRequest{
39+
EarlyExit: true,
40+
})
41+
if err != nil {
42+
return err
43+
}
44+
45+
var rerr error
46+
if format := clicontext.String("format"); format != "" {
47+
tmpl, err := bccommon.ParseTemplate(format)
48+
if err != nil {
49+
return err
50+
}
51+
for {
52+
ev, err := resp.Recv()
53+
if errors.Is(err, io.EOF) {
54+
break
55+
} else if err != nil {
56+
return err
57+
}
58+
if ev.Record == nil || ev.Record.Pinned {
59+
continue
60+
}
61+
if _, err := controlClient.UpdateBuildHistory(ctx, &controlapi.UpdateBuildHistoryRequest{
62+
Ref: ev.Record.Ref,
63+
Delete: true,
64+
}); err != nil {
65+
rerr = multierror.Append(rerr, err).ErrorOrNil()
66+
continue
67+
}
68+
if err := tmpl.Execute(clicontext.App.Writer, ev); err != nil {
69+
return err
70+
}
71+
if _, err = fmt.Fprintf(clicontext.App.Writer, "\n"); err != nil {
72+
return err
73+
}
74+
}
75+
return rerr
76+
}
77+
return pruneHistoriesWithTableOutput(ctx, clicontext.App.Writer, controlClient, resp)
78+
}
79+
80+
func pruneHistoriesWithTableOutput(ctx context.Context, w io.Writer, controlClient controlapi.ControlClient,
81+
eventReceiver controlapi.Control_ListenBuildHistoryClient) error {
82+
tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
83+
fmt.Fprintln(tw, "TYPE\tREF\tCREATED\tCOMPLETED\tGENERATION")
84+
var rerr error
85+
for {
86+
ev, err := eventReceiver.Recv()
87+
if errors.Is(err, io.EOF) {
88+
break
89+
} else if err != nil {
90+
return err
91+
}
92+
r := ev.Record
93+
if r == nil || r.Pinned {
94+
continue
95+
}
96+
if _, err := controlClient.UpdateBuildHistory(ctx, &controlapi.UpdateBuildHistoryRequest{
97+
Ref: ev.Record.Ref,
98+
Delete: true,
99+
}); err != nil {
100+
rerr = multierror.Append(rerr, err).ErrorOrNil()
101+
continue
102+
}
103+
var (
104+
createdAt string
105+
completedAt string
106+
)
107+
if r.CreatedAt != nil {
108+
createdAt = r.CreatedAt.Local().Format(time.RFC3339)
109+
}
110+
if r.CompletedAt != nil {
111+
completedAt = r.CompletedAt.Local().Format(time.RFC3339)
112+
}
113+
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%d\n", ev.Type, r.Ref, createdAt, completedAt, r.Generation)
114+
tw.Flush()
115+
}
116+
tw.Flush()
117+
return rerr
118+
}

0 commit comments

Comments
 (0)