Skip to content

Commit a7ac3b0

Browse files
committed
feat: provision platform context dynamically
Provision platforms on demand, without relying on a static list from the buildkit. Signed-off-by: Andrey Smirnov <[email protected]>
1 parent 40aea38 commit a7ac3b0

File tree

1 file changed

+80
-44
lines changed

1 file changed

+80
-44
lines changed

internal/pkg/pkgfile/build.go

Lines changed: 80 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"fmt"
1111
"strconv"
1212
"strings"
13+
"sync"
1314
"time"
1415

1516
ctrplatforms "github.com/containerd/containerd/platforms"
@@ -48,15 +49,81 @@ type platformContext struct {
4849
options environment.Options
4950
}
5051

52+
type platformContextCache struct { //nolint:govet
53+
mu sync.Mutex
54+
cache map[string]platformContext
55+
56+
baseOptions environment.Options
57+
exportMap bool
58+
c client.Client
59+
}
60+
61+
func newPlatformContextCache(baseOptions environment.Options, exportMap bool, c client.Client) *platformContextCache {
62+
return &platformContextCache{
63+
cache: make(map[string]platformContext),
64+
65+
baseOptions: baseOptions,
66+
exportMap: exportMap,
67+
c: c,
68+
}
69+
}
70+
71+
func (cache *platformContextCache) get(ctx context.Context, platform environment.Platform) (platformContext, error) {
72+
cache.mu.Lock()
73+
defer cache.mu.Unlock()
74+
75+
if pc, ok := cache.cache[platform.ID]; ok {
76+
return pc, nil
77+
}
78+
79+
options := cache.baseOptions
80+
options.BuildPlatform = platform
81+
options.TargetPlatform = platform
82+
83+
if cache.exportMap {
84+
options.CommonPrefix = fmt.Sprintf("%s ", platform.ID)
85+
}
86+
87+
pkgRef, err := fetchPkgs(ctx, cache.c)
88+
if err != nil {
89+
return platformContext{}, fmt.Errorf("error loading packages for %s: %w", platform, err)
90+
}
91+
92+
opts := cache.c.BuildOpts().Opts
93+
94+
buildContext := options.GetVariables().Copy()
95+
// push build arguments as `BUILD_ARGS_` prefixed variables
96+
buildContext.Merge(prefix(filter(opts, buildArgPrefix), "BUILD_ARG_"))
97+
98+
loader := solver.BuildkitFrontendLoader{
99+
Context: buildContext,
100+
Ref: pkgRef,
101+
Ctx: ctx,
102+
}
103+
104+
packages, err := solver.NewPackages(&loader)
105+
if err != nil {
106+
return platformContext{}, fmt.Errorf("error loading packages for %s: %w", platform, err)
107+
}
108+
109+
cache.cache[platform.ID] = platformContext{
110+
options: options,
111+
packages: packages,
112+
}
113+
114+
return cache.cache[platform.ID], nil
115+
}
116+
51117
func solveTarget(
52-
platformContexts map[string]platformContext, c client.Client, cacheImports []client.CacheOptionsEntry,
118+
platformContextCache *platformContextCache, c client.Client, cacheImports []client.CacheOptionsEntry,
53119
) func(ctx context.Context, platform environment.Platform, target string) (*client.Result, error) {
54120
return func(ctx context.Context, platform environment.Platform, target string) (*client.Result, error) {
55-
if _, ok := platformContexts[platform.ID]; !ok {
56-
return nil, fmt.Errorf("platform %s not found", platform)
121+
platformContext, err := platformContextCache.get(ctx, platform)
122+
if err != nil {
123+
return nil, fmt.Errorf("failed to get platform context for %s: %w", platform, err)
57124
}
58125

59-
options, packages := platformContexts[platform.ID].options, platformContexts[platform.ID].packages
126+
options, packages := platformContext.options, platformContext.packages
60127

61128
if target == "" {
62129
target = options.Target
@@ -67,7 +134,7 @@ func solveTarget(
67134
return nil, fmt.Errorf("failed to resolve packages for platform %s and target %s: %w", platform, target, err)
68135
}
69136

70-
def, err := convert.MarshalLLB(ctx, graph, solveTarget(platformContexts, c, cacheImports), &options)
137+
def, err := convert.MarshalLLB(ctx, graph, solveTarget(platformContextCache, c, cacheImports), &options)
71138
if err != nil {
72139
return nil, fmt.Errorf("failed to marshal LLB for platform %s and target %s: %w", platform, target, err)
73140
}
@@ -175,44 +242,8 @@ func Build(ctx context.Context, c client.Client, options *environment.Options) (
175242
}
176243

177244
// prepare platform contexts
178-
platformContexts := make(map[string]platformContext, len(platforms))
179-
180-
for _, platform := range platforms {
181-
options := *options
182-
options.BuildPlatform = platform
183-
options.TargetPlatform = platform
184-
185-
if exportMap {
186-
options.CommonPrefix = fmt.Sprintf("%s ", platform.ID)
187-
}
188-
189-
pkgRef, err := fetchPkgs(ctx, c)
190-
if err != nil {
191-
return nil, fmt.Errorf("error loading packages for %s: %w", platform, err)
192-
}
193-
194-
buildContext := options.GetVariables().Copy()
195-
// push build arguments as `BUILD_ARGS_` prefixed variables
196-
buildContext.Merge(prefix(filter(opts, buildArgPrefix), "BUILD_ARG_"))
197-
198-
loader := solver.BuildkitFrontendLoader{
199-
Context: buildContext,
200-
Ref: pkgRef,
201-
Ctx: ctx,
202-
}
203-
204-
packages, err := solver.NewPackages(&loader)
205-
if err != nil {
206-
return nil, fmt.Errorf("error loading packages for %s: %w", platform, err)
207-
}
208-
209-
platformContexts[platform.ID] = platformContext{
210-
options: options,
211-
packages: packages,
212-
}
213-
}
214-
215-
solveTarget := solveTarget(platformContexts, c, cacheImports)
245+
platformContextCache := newPlatformContextCache(*options, exportMap, c)
246+
solveTarget := solveTarget(platformContextCache, c, cacheImports)
216247

217248
var eg *errgroup.Group
218249
eg, ctx = errgroup.WithContext(ctx)
@@ -232,6 +263,11 @@ func Build(ctx context.Context, c client.Client, options *environment.Options) (
232263
return err
233264
}
234265

266+
platformContext, err := platformContextCache.get(ctx, platform)
267+
if err != nil {
268+
return fmt.Errorf("failed to get platform context for %s: %w", platform, err)
269+
}
270+
235271
img := image.Image{
236272
Image: specs.Image{
237273
Platform: specs.Platform{
@@ -245,7 +281,7 @@ func Build(ctx context.Context, c client.Client, options *environment.Options) (
245281
},
246282
Config: image.ImageConfig{
247283
ImageConfig: specs.ImageConfig{
248-
Labels: platformContexts[platform.ID].packages.ImageLabels(),
284+
Labels: platformContext.packages.ImageLabels(),
249285
},
250286
},
251287
}

0 commit comments

Comments
 (0)