Skip to content

Commit 1e4d420

Browse files
committed
frontend: fix gwclient.Client wrappers losing CurrentFrontend interface
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
1 parent fbdd125 commit 1e4d420

File tree

4 files changed

+78
-28
lines changed

4 files changed

+78
-28
lines changed

frontend/build.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@ type LoadConfig struct {
2323

2424
type LoadOpt func(*LoadConfig)
2525

26-
type frontendClient interface {
27-
CurrentFrontend() (*llb.State, error)
28-
}
29-
3026
func WithAllowArgs(args ...string) LoadOpt {
3127
return func(cfg *LoadConfig) {
3228
set := make(map[string]struct{}, len(args))
@@ -199,14 +195,16 @@ func WithDefaultPlatform(platform ocispecs.Platform, build gwclient.BuildFunc) g
199195
if client.BuildOpts().Opts["platform"] != "" {
200196
return build(ctx, client)
201197
}
202-
client = &clientWithPlatform{
198+
client = withCurrentFrontend(client, &clientWithPlatform{
203199
Client: client,
204200
platform: &platform,
205-
}
201+
})
206202
return build(ctx, client)
207203
}
208204
}
209205

206+
var _ gwclient.Client = (*clientWithPlatform)(nil)
207+
210208
type clientWithPlatform struct {
211209
gwclient.Client
212210
platform *ocispecs.Platform
@@ -219,7 +217,7 @@ func (c *clientWithPlatform) BuildOpts() gwclient.BuildOpts {
219217
}
220218

221219
func GetCurrentFrontend(client gwclient.Client) (llb.State, error) {
222-
f, err := client.(frontendClient).CurrentFrontend()
220+
f, err := client.(currentFrontend).CurrentFrontend()
223221
if err != nil {
224222
return llb.Scratch(), err
225223
}

frontend/client.go

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88

99
"github.com/containerd/platforms"
1010
"github.com/goccy/go-yaml"
11-
"github.com/moby/buildkit/client/llb"
1211
"github.com/moby/buildkit/frontend/dockerui"
1312
gwclient "github.com/moby/buildkit/frontend/gateway/client"
1413
"github.com/project-dalec/dalec"
@@ -39,15 +38,8 @@ func (err *noSuchHandlerError) Error() string {
3938
return fmt.Sprintf("no such handler for target %q: available targets: %s", err.Target, strings.Join(err.Available, ", "))
4039
}
4140

42-
// CurrentFrontend is an interface typically implemented by a [gwclient.Client].
43-
// This is used to get the rootfs of the current frontend.
44-
type CurrentFrontend interface {
45-
CurrentFrontend() (*llb.State, error)
46-
}
47-
4841
var (
4942
_ gwclient.Client = (*clientWithCustomOpts)(nil)
50-
_ CurrentFrontend = (*clientWithCustomOpts)(nil)
5143
)
5244

5345
type clientWithCustomOpts struct {
@@ -59,20 +51,16 @@ func (d *clientWithCustomOpts) BuildOpts() gwclient.BuildOpts {
5951
return d.opts
6052
}
6153

62-
func (d *clientWithCustomOpts) CurrentFrontend() (*llb.State, error) {
63-
return d.Client.(CurrentFrontend).CurrentFrontend()
64-
}
65-
66-
func setClientOptOption(client gwclient.Client, extraOpts map[string]string) *clientWithCustomOpts {
54+
func setClientOptOption(client gwclient.Client, extraOpts map[string]string) gwclient.Client {
6755
opts := client.BuildOpts()
6856

6957
for key, value := range extraOpts {
7058
opts.Opts[key] = value
7159
}
72-
return &clientWithCustomOpts{
60+
return withCurrentFrontend(client, &clientWithCustomOpts{
7361
Client: client,
7462
opts: opts,
75-
}
63+
})
7664
}
7765

7866
func maybeSetDalecTargetKey(client gwclient.Client, key string) gwclient.Client {
@@ -82,13 +70,13 @@ func maybeSetDalecTargetKey(client gwclient.Client, key string) gwclient.Client
8270
return client
8371
}
8472

85-
// optimization to help prevent unnecessary grpc requests
73+
// Optimization to help prevent unnecessary grpc requests.
8674
// The gateway client will make a grpc request to get the build opts from the gateway.
8775
// This just caches those opts locally.
8876
// If the client is already a clientWithCustomOpts, then the opts are already cached.
8977
if _, ok := client.(*clientWithCustomOpts); !ok {
9078
// this forces the client to use our cached opts from above
91-
client = &clientWithCustomOpts{opts: opts, Client: client}
79+
client = withCurrentFrontend(client, &clientWithCustomOpts{opts: opts, Client: client})
9280
}
9381
return setClientOptOption(client, map[string]string{keyTopLevelTarget: key, "build-arg:" + dalec.KeyDalecTarget: key})
9482
}

frontend/gwutil.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package frontend
2+
3+
import (
4+
"github.com/moby/buildkit/client/llb"
5+
gwclient "github.com/moby/buildkit/frontend/gateway/client"
6+
)
7+
8+
// currentFrontend is an interface typically implemented by a [gwclient.Client].
9+
// This is used to get the rootfs of the current frontend.
10+
type currentFrontend interface {
11+
CurrentFrontend() (*llb.State, error)
12+
}
13+
14+
// withCurrentFrontend wraps a [gwclient.Client] to ensure that [currentFrontend]
15+
// is not lost when the client is wrapped.
16+
//
17+
// If inner does not implement [currentFrontend], wrapper is returned as-is.
18+
func withCurrentFrontend(inner gwclient.Client, wrapper gwclient.Client) gwclient.Client {
19+
cf, ok := inner.(currentFrontend)
20+
if !ok {
21+
return wrapper
22+
}
23+
24+
return &clientWithCurrentFrontend{Client: wrapper, cf: cf}
25+
}
26+
27+
// clientWithCurrentFrontend wraps a gwclient.Client and forwards
28+
// CurrentFrontend calls to the inner client.
29+
type clientWithCurrentFrontend struct {
30+
gwclient.Client
31+
cf currentFrontend
32+
}
33+
34+
var _ gwclient.Client = (*clientWithCurrentFrontend)(nil)
35+
36+
func (c *clientWithCurrentFrontend) CurrentFrontend() (*llb.State, error) {
37+
return c.cf.CurrentFrontend()
38+
}

test/testenv/buildx.go

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818

1919
"github.com/cpuguy83/dockercfg"
2020
"github.com/moby/buildkit/client"
21+
"github.com/moby/buildkit/client/llb"
2122
gwclient "github.com/moby/buildkit/frontend/gateway/client"
2223
"github.com/moby/buildkit/session/auth"
2324
"github.com/moby/buildkit/session/secrets/secretsprovider"
@@ -398,7 +399,7 @@ func (b *BuildxEnv) RunTest(ctx context.Context, t *testing.T, f TestFunc, opts
398399
}
399400

400401
_, err = c.Build(ctx, so, "", func(ctx context.Context, gwc gwclient.Client) (*gwclient.Result, error) {
401-
gwc = &clientForceDalecWithInput{gwc}
402+
gwc = withCurrentFrontend(gwc, &clientForceDalecWithInput{gwc})
402403

403404
b.mu.Lock()
404405
for id, f := range b.refs {
@@ -441,12 +442,12 @@ type gwClientInputInject struct {
441442
f gwclient.BuildFunc
442443
}
443444

444-
func wrapWithInput(c gwclient.Client, id string, f gwclient.BuildFunc) *gwClientInputInject {
445-
return &gwClientInputInject{
445+
func wrapWithInput(c gwclient.Client, id string, f gwclient.BuildFunc) gwclient.Client {
446+
return withCurrentFrontend(c, &gwClientInputInject{
446447
Client: c,
447448
id: id,
448449
f: f,
449-
}
450+
})
450451
}
451452

452453
func (c *gwClientInputInject) Solve(ctx context.Context, req gwclient.SolveRequest) (*gwclient.Result, error) {
@@ -539,3 +540,28 @@ func (ap *authProvider) VerifyTokenAuthority(ctx context.Context, req *auth.Veri
539540
func (ap *authProvider) Register(server *grpc.Server) {
540541
auth.RegisterAuthServer(server, ap)
541542
}
543+
544+
// currentFrontend is the interface for obtaining the current frontend's rootfs.
545+
// This mirrors the unexported interface in the frontend package.
546+
type currentFrontend interface {
547+
CurrentFrontend() (*llb.State, error)
548+
}
549+
550+
// withCurrentFrontend wraps a gwclient.Client to preserve the currentFrontend
551+
// interface through client wrapping.
552+
func withCurrentFrontend(inner gwclient.Client, wrapper gwclient.Client) gwclient.Client {
553+
cf, ok := inner.(currentFrontend)
554+
if !ok {
555+
return wrapper
556+
}
557+
return &clientWithCurrentFrontend{Client: wrapper, cf: cf}
558+
}
559+
560+
type clientWithCurrentFrontend struct {
561+
gwclient.Client
562+
cf currentFrontend
563+
}
564+
565+
func (c *clientWithCurrentFrontend) CurrentFrontend() (*llb.State, error) {
566+
return c.cf.CurrentFrontend()
567+
}

0 commit comments

Comments
 (0)