Skip to content

Commit 9c50b20

Browse files
authored
Merge pull request #332 from depot/feat/load-from-registry
feat: allow loading build from the depot registry
2 parents 5eafea3 + 890df91 commit 9c50b20

File tree

9 files changed

+474
-343
lines changed

9 files changed

+474
-343
lines changed

Diff for: pkg/build/build.go

+35
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ type Credential struct {
3535
Token string
3636
}
3737

38+
type PullInfo struct {
39+
Reference string
40+
Username string
41+
Password string
42+
}
43+
3844
func (b *Build) AdditionalTags() []string {
3945
if b.Response == nil || b.Response.Msg == nil {
4046
return []string{fmt.Sprintf("registry.depot.dev/%s:%s", b.projectID, b.ID)}
@@ -92,6 +98,19 @@ func (b *Build) BuildProject() string {
9298
return b.Response.Msg.ProjectId
9399
}
94100

101+
func (b *Build) LoadUsingRegistry() bool {
102+
if b.Response == nil || b.Response.Msg == nil {
103+
return false
104+
}
105+
106+
registry := b.Response.Msg.GetRegistry()
107+
if registry == nil {
108+
return false
109+
}
110+
111+
return registry.LoadUsingRegistry
112+
}
113+
95114
func NewBuild(ctx context.Context, req *cliv1.CreateBuildRequest, token string) (Build, error) {
96115
client := depotapi.NewBuildClient()
97116
res, err := client.CreateBuild(ctx, depotapi.WithAuthentication(connect.NewRequest(req), token))
@@ -157,6 +176,22 @@ func FromExistingBuild(ctx context.Context, buildID, token string, buildRes *con
157176

158177
}
159178

179+
func PullBuildInfo(ctx context.Context, buildID, token string) (*PullInfo, error) {
180+
// Download location and credentials of image save.
181+
client := depotapi.NewBuildClient()
182+
req := &cliv1.GetPullInfoRequest{BuildId: buildID}
183+
res, err := client.GetPullInfo(ctx, depotapi.WithAuthentication(connect.NewRequest(req), token))
184+
if err != nil {
185+
return nil, err
186+
}
187+
188+
return &PullInfo{
189+
Reference: res.Msg.Reference,
190+
Username: res.Msg.Username,
191+
Password: res.Msg.Password,
192+
}, nil
193+
}
194+
160195
type authProvider struct {
161196
credentials map[string]clitypes.AuthConfig
162197
dockerAuth driver.Auth

Diff for: pkg/buildx/commands/bake.go

+18-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"sync"
1111

1212
"github.com/containerd/containerd/platforms"
13+
depotbuild "github.com/depot/cli/pkg/build"
1314
"github.com/depot/cli/pkg/buildx/bake"
1415
"github.com/depot/cli/pkg/buildx/build"
1516
"github.com/depot/cli/pkg/buildx/builder"
@@ -102,6 +103,8 @@ func RunBake(dockerCli command.Cli, in BakeOptions, validator BakeValidator, pri
102103
BuildID: in.DepotOptions.buildID,
103104
IsBake: true,
104105
ProgressMode: in.progress,
106+
UseRegistry: in.DepotOptions.loadUsingRegistry,
107+
PullInfo: in.DepotOptions.pullInfo,
105108
},
106109
)
107110
}
@@ -179,7 +182,11 @@ func RunBake(dockerCli command.Cli, in BakeOptions, validator BakeValidator, pri
179182
if slices.Contains(requestedTargets, resp[i].Name) {
180183
reportingPrinter := progresshelper.NewReporter(ctx2, printer, in.buildID, in.token)
181184
defer reportingPrinter.Close()
182-
err = load.DepotFastLoad(ctx2, dockerCli.Client(), depotResponses, pullOpts, reportingPrinter)
185+
if in.DepotOptions.loadUsingRegistry && in.DepotOptions.pullInfo != nil {
186+
err = load.DepotLoadFromRegistry(ctx, dockerCli.Client(), in.DepotOptions.pullInfo.Reference, true, pullOpts, reportingPrinter)
187+
} else {
188+
err = load.DepotFastLoad(ctx2, dockerCli.Client(), depotResponses, pullOpts, reportingPrinter)
189+
}
183190
}
184191
load.DeleteExportLeases(ctx2, depotResponses)
185192
return err
@@ -318,6 +325,16 @@ func BakeCmd() *cobra.Command {
318325
if buildProject != "" {
319326
options.project = buildProject
320327
}
328+
loadUsingRegistry := build.LoadUsingRegistry()
329+
if options.exportLoad && loadUsingRegistry {
330+
options.save = true
331+
pullInfo, err := depotbuild.PullBuildInfo(context.Background(), build.ID, token)
332+
// if we cannot get pull info, dont fail; load as normal
333+
if err == nil {
334+
options.loadUsingRegistry = loadUsingRegistry
335+
options.pullInfo = pullInfo
336+
}
337+
}
321338
if options.save {
322339
options.additionalCredentials = build.AdditionalCredentials()
323340
options.additionalTags = build.AdditionalTags()

Diff for: pkg/buildx/commands/build.go

+21-1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ type DepotOptions struct {
123123
saveTags []string
124124
additionalTags []string
125125
additionalCredentials []depotbuild.Credential
126+
loadUsingRegistry bool
127+
pullInfo *depotbuild.PullInfo
126128

127129
lint bool
128130
lintFailOn string
@@ -232,6 +234,8 @@ func buildTargets(ctx context.Context, dockerCli command.Cli, nodes []builder.No
232234
BuildID: depotOpts.buildID,
233235
IsBake: false,
234236
ProgressMode: progressMode,
237+
UseRegistry: depotOpts.loadUsingRegistry,
238+
PullInfo: depotOpts.pullInfo,
235239
},
236240
)
237241
}
@@ -324,7 +328,13 @@ func buildTargets(ctx context.Context, dockerCli command.Cli, nodes []builder.No
324328

325329
// NOTE: the err is returned at the end of this function after the final prints.
326330
reportingPrinter := progresshelper.NewReporter(ctx, printer, depotOpts.buildID, depotOpts.token)
327-
err = load.DepotFastLoad(ctx, dockerCli.Client(), resp, pullOpts, reportingPrinter)
331+
332+
if depotOpts.loadUsingRegistry && depotOpts.pullInfo != nil {
333+
err = load.DepotLoadFromRegistry(ctx, dockerCli.Client(), depotOpts.pullInfo.Reference, false, pullOpts, reportingPrinter)
334+
} else {
335+
err = load.DepotFastLoad(ctx, dockerCli.Client(), resp, pullOpts, reportingPrinter)
336+
}
337+
328338
if err != nil && !errors.Is(err, context.Canceled) {
329339
// For now, we will fallback by rebuilding with load.
330340
if exportLoad {
@@ -680,6 +690,16 @@ func BuildCmd() *cobra.Command {
680690
if buildProject != "" {
681691
options.project = buildProject
682692
}
693+
loadUsingRegistry := build.LoadUsingRegistry()
694+
if options.exportLoad && loadUsingRegistry {
695+
options.save = true
696+
pullInfo, err := depotbuild.PullBuildInfo(context.Background(), build.ID, token)
697+
// if we cannot get pull info, dont fail; load as normal
698+
if err == nil {
699+
options.loadUsingRegistry = loadUsingRegistry
700+
options.pullInfo = pullInfo
701+
}
702+
}
683703
if options.save {
684704
options.additionalCredentials = build.AdditionalCredentials()
685705
options.additionalTags = build.AdditionalTags()

Diff for: pkg/cmd/pull/options.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ import (
1212
"golang.org/x/exp/slices"
1313
)
1414

15-
func isSavedBuild(options []*cliv1.BuildOptions) bool {
15+
func isSavedBuild(options []*cliv1.BuildOptions, savedForLoad bool) bool {
1616
for _, opt := range options {
1717
if opt.Save {
1818
return true
1919
}
2020
}
21-
return false
21+
return savedForLoad
2222
}
2323

2424
func isBake(options []*cliv1.BuildOptions) bool {

Diff for: pkg/cmd/pull/pull.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ func NewCmdPull() *cobra.Command {
103103
}
104104

105105
buildOptions := res.Msg.Options
106-
if len(buildOptions) > 0 && !isSavedBuild(buildOptions) {
106+
savedForLoad := res.Msg.SaveForLoad
107+
if len(buildOptions) > 0 && !isSavedBuild(buildOptions, savedForLoad) {
107108
return fmt.Errorf("build %s is not a saved build. To use the registry use --save when building", buildID)
108109
}
109110

Diff for: pkg/load/cli.go

+16-4
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,20 @@ import (
44
"fmt"
55
"strings"
66

7+
depotbuild "github.com/depot/cli/pkg/build"
78
"github.com/docker/buildx/build"
89
"github.com/docker/buildx/util/progress"
910
"github.com/moby/buildkit/client"
1011
)
1112

1213
// DepotLoadOptions are options to load images from the depot hosted registry.
1314
type DepotLoadOptions struct {
14-
Project string // Depot project name; used to tag images.
15-
BuildID string // Depot build ID; used to tag images.
16-
IsBake bool // If run from bake, we add the bake target to the image tag.
17-
ProgressMode string // ProgressMode quiet will not print progress.
15+
Project string // Depot project name; used to tag images.
16+
BuildID string // Depot build ID; used to tag images.
17+
IsBake bool // If run from bake, we add the bake target to the image tag.
18+
ProgressMode string // ProgressMode quiet will not print progress.
19+
UseRegistry bool // If UseRegistry, load build from registry instead of proxy
20+
PullInfo *depotbuild.PullInfo // If UseRegistry, the credentials for pulling from registry
1821
}
1922

2023
// Options to download from the Depot hosted registry and tag the image with the user provide tag.
@@ -69,6 +72,15 @@ func WithDepotImagePull(buildOpts map[string]build.Options, loadOpts DepotLoadOp
6972
UserTags: userTags,
7073
Quiet: loadOpts.ProgressMode == progress.PrinterModeQuiet,
7174
}
75+
76+
if loadOpts.UseRegistry && loadOpts.PullInfo != nil {
77+
serverAddress := "registry.depot.dev"
78+
pullOpt.KeepImage = true
79+
pullOpt.Username = &loadOpts.PullInfo.Username
80+
pullOpt.Password = &loadOpts.PullInfo.Password
81+
pullOpt.ServerAddress = &serverAddress
82+
}
83+
7284
toPull[target] = pullOpt
7385
}
7486
}

Diff for: pkg/load/load.go

+23
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,29 @@ func DepotFastLoad(ctx context.Context, dockerapi docker.APIClient, resp []depot
7575
return nil
7676
}
7777

78+
func DepotLoadFromRegistry(ctx context.Context, dockerapi docker.APIClient, reference string, isBake bool, pullOpts map[string]PullOptions, printer progress.Writer) error {
79+
if len(pullOpts) == 0 {
80+
return nil
81+
}
82+
83+
for target, pullOpt := range pullOpts {
84+
pw := progress.WithPrefix(printer, target, len(pullOpts) > 1)
85+
86+
imageName := reference
87+
88+
if isBake {
89+
imageName = fmt.Sprintf("%s-%s", reference, target)
90+
}
91+
92+
err := PullImages(ctx, dockerapi, imageName, pullOpt, pw)
93+
if err != nil {
94+
return fmt.Errorf("failed to pull image: %w", err)
95+
}
96+
}
97+
98+
return nil
99+
}
100+
78101
// For now if there is a multi-platform build we try to only download the
79102
// architecture of the depot CLI host. If there is not a node with the same
80103
// architecture as the depot CLI host, we take the first node in the list.

0 commit comments

Comments
 (0)