Skip to content

Commit 68c2f6b

Browse files
committed
Don't unlazy the build
This breaks some assumptions for clients and breaks "docker buildx dap build", which we are relying on for debugging work. Before the change this is also technically solving multiple times, even though the subsequent solves are cached. The main culprit of unlazying the build is the test runner, which needs to run commands and inspect filesystem state to return errors. With this change the test runner is now executed as part of the normal LLB graph. All checks occur inside a buildkit container. The frontend now has an extra set of subcommands for executing certain checks. The frontend binary gets mounted into the test container and it executes those subcommands to perform the various checks. In order to preserve source mapping each test check is run in separate exec ops. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
1 parent e0dee58 commit 68c2f6b

File tree

26 files changed

+1307
-686
lines changed

26 files changed

+1307
-686
lines changed

cmd/frontend/git_credential_helper.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,26 @@ package main
33
import (
44
"bufio"
55
"bytes"
6+
"context"
67
"encoding/base64"
78
"flag"
89
"fmt"
910
"io"
1011
"os"
1112
"path/filepath"
1213
"strings"
14+
15+
"github.com/project-dalec/dalec/internal/commands"
16+
"github.com/project-dalec/dalec/internal/plugins"
1317
)
1418

19+
func init() {
20+
commands.RegisterPlugin(credHelperSubcmd, plugins.CmdHandlerFunc(credentialHelperCmd))
21+
}
22+
1523
const (
24+
credHelperSubcmd = "credential-helper"
25+
1626
keyProtocol = "protocol"
1727
keyHost = "host"
1828
keyPath = "path"
@@ -71,7 +81,7 @@ type credConfig struct {
7181
kind string
7282
}
7383

74-
func gomodMain(args []string) {
84+
func credentialHelperCmd(ctx context.Context, args []string) {
7585
var cfg credConfig
7686
fs := flag.NewFlagSet(credHelperSubcmd, flag.ExitOnError)
7787
fs.Func("kind", "the kind of secret to retrieve (token or header)", readKind(&cfg.kind))

cmd/frontend/main.go

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
package main
22

33
import (
4+
"context"
45
_ "embed"
56
"flag"
67
"fmt"
78
"os"
9+
"path/filepath"
810

11+
"github.com/containerd/plugin"
912
"github.com/moby/buildkit/frontend/gateway/grpcclient"
1013
"github.com/moby/buildkit/util/appcontext"
1114
"github.com/moby/buildkit/util/bklog"
1215
"github.com/project-dalec/dalec/frontend"
1316
"github.com/project-dalec/dalec/internal/frontendapi"
14-
"github.com/project-dalec/dalec/internal/testrunner"
17+
"github.com/project-dalec/dalec/internal/plugins"
1518
"github.com/sirupsen/logrus"
1619
"google.golang.org/grpc/grpclog"
20+
21+
_ "github.com/project-dalec/dalec/internal/commands"
1722
)
1823

1924
const (
2025
Package = "github.com/project-dalec/dalec/cmd/frontend"
21-
22-
credHelperSubcmd = "credential-helper"
2326
)
2427

2528
func init() {
@@ -28,40 +31,62 @@ func init() {
2831
}
2932

3033
func main() {
31-
fs := flag.CommandLine
32-
fs.Usage = func() {
33-
fmt.Fprintf(os.Stderr, `usage: %s [subcommand [args...]]`, os.Args[0])
34-
}
34+
flags := flag.NewFlagSet(filepath.Base(os.Args[0]), flag.ExitOnError)
3535

36-
if err := fs.Parse(os.Args); err != nil {
36+
if err := flags.Parse(os.Args[1:]); err != nil {
3737
bklog.L.WithError(err).Fatal("error parsing frontend args")
3838
os.Exit(70) // 70 is EX_SOFTWARE, meaning internal software error occurred
39+
}
3940

41+
ctx := appcontext.Context()
42+
if flags.NArg() == 0 {
43+
dalecMain(ctx)
44+
return
4045
}
4146

42-
subCmd := fs.Arg(1)
43-
44-
// NOTE: for subcommands we take args[2:]
45-
// skip args[0] (the executable) and args[1] (the subcommand)
46-
47-
// each "sub-main" function handles its own exit
48-
switch subCmd {
49-
case credHelperSubcmd:
50-
args := flag.Args()[2:]
51-
gomodMain(args)
52-
case testrunner.StepRunnerCmdName:
53-
args := flag.Args()[2:]
54-
testrunner.StepCmd(args)
55-
case testrunner.CheckFilesCmdName:
56-
args := flag.Args()[2:]
57-
testrunner.CheckFilesCmd(args)
58-
default:
59-
dalecMain()
47+
h, err := lookupCmd(ctx, flags.Arg(0))
48+
if err != nil {
49+
bklog.L.WithError(err).Fatal("error handling command")
50+
os.Exit(70) // 70 is EX_SOFTWARE, meaning internal software error occurred
51+
}
52+
53+
if h == nil {
54+
fmt.Fprintln(os.Stderr, "unknown subcommand:", flags.Arg(1))
55+
fmt.Fprintln(os.Stderr, "full args:", flag.Args())
56+
fmt.Fprintln(os.Stderr, "If you see this message this is probably a bug in dalec.")
57+
os.Exit(64) // 64 is EX_USAGE, meaning command line usage error
6058
}
59+
60+
h.HandleCmd(ctx, flags.Args()[1:])
6161
}
6262

63-
func dalecMain() {
64-
ctx := appcontext.Context()
63+
func lookupCmd(ctx context.Context, cmd string) (plugins.CmdHandler, error) {
64+
set := plugin.NewPluginSet()
65+
filter := func(r *plugins.Registration) bool {
66+
return r.Type != plugins.TypeCmd || r.ID != cmd
67+
}
68+
69+
for _, r := range plugins.Graph(filter) {
70+
cfg := plugin.NewContext(ctx, set, nil)
71+
72+
p := r.Init(cfg)
73+
74+
v, err := p.Instance()
75+
if plugin.IsSkipPlugin(err) {
76+
continue
77+
}
78+
79+
if err != nil {
80+
return nil, err
81+
}
82+
83+
return v.(plugins.CmdHandler), nil
84+
}
85+
86+
return nil, nil
87+
}
88+
89+
func dalecMain(ctx context.Context) {
6590
mux, err := frontendapi.NewBuildRouter(ctx)
6691
if err != nil {
6792
bklog.L.WithError(err).Fatal("error creating frontend router")

frontend/build.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func LoadSpec(ctx context.Context, client *dockerui.Client, platform *ocispecs.P
5454
o(&cfg)
5555
}
5656

57-
src, err := client.ReadEntrypoint(ctx, "Dockerfile")
57+
src, err := client.ReadEntrypoint(ctx, "dalec")
5858
if err != nil {
5959
return nil, fmt.Errorf("could not read spec file: %w", err)
6060
}
@@ -218,26 +218,26 @@ func (c *clientWithPlatform) BuildOpts() gwclient.BuildOpts {
218218
return opts
219219
}
220220

221-
func GetCurrentFrontend(client gwclient.Client) (llb.State, error) {
221+
func GetCurrentFrontend(client gwclient.Client) llb.State {
222+
return *getCurrentFrontend(client)
223+
}
224+
225+
func getCurrentFrontend(client gwclient.Client) *llb.State {
222226
f, err := client.(frontendClient).CurrentFrontend()
223227
if err != nil {
224-
return llb.Scratch(), err
228+
panic(err)
225229
}
226230

227231
if f == nil {
228-
return llb.Scratch(), fmt.Errorf("nil frontend state returned")
232+
panic("nil frontend state returned -- this should never happen")
229233
}
230234

231-
return *f, nil
235+
return f
232236
}
233237

234238
func withCredHelper(c gwclient.Client) func() (llb.RunOption, error) {
235239
return func() (llb.RunOption, error) {
236-
f, err := GetCurrentFrontend(c)
237-
if err != nil {
238-
return nil, err
239-
}
240-
240+
f := GetCurrentFrontend(c)
241241
return dalec.RunOptFunc(func(ei *llb.ExecInfo) {
242242
llb.AddMount("/usr/local/bin/frontend", f, llb.SourcePath("/frontend")).SetRunOption(ei)
243243
}), nil

0 commit comments

Comments
 (0)