Skip to content

Commit efcebc9

Browse files
committed
frontend: add build-time source filters
Add a source-options context that can provide a YAML source filter config at build time. The config currently supports global_excludes which can be used to filter out paths from all sources. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
1 parent 5751801 commit efcebc9

18 files changed

Lines changed: 667 additions & 33 deletions

frontend/debug/handle_sources.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ func Sources(ctx context.Context, client gwclient.Client) (*gwclient.Result, err
1818
return nil, nil, err
1919
}
2020

21-
sources := dalec.Sources(spec, sOpt)
22-
2321
pg := dalec.ProgressGroup("Sources for " + targetKey + " rpm build: " + spec.Name)
2422

23+
sources := dalec.Sources(spec, sOpt, pg)
24+
2525
def, err := dalec.MergeAtPath(llb.Scratch(), dalec.SortedMapValues(sources), "/", pg).Marshal(ctx)
2626
if err != nil {
2727
return nil, nil, err

frontend/gateway.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func GetBuildArg(client gwclient.Client, k string) (string, bool) {
103103
}
104104

105105
func SourceOptFromUIClient(ctx context.Context, c gwclient.Client, dc *dockerui.Client, platform *ocispecs.Platform) dalec.SourceOpts {
106-
return dalec.SourceOpts{
106+
sOpt := dalec.SourceOpts{
107107
TargetPlatform: platform,
108108
Resolver: c,
109109
Forward: ForwarderFromClient(ctx, c),
@@ -129,6 +129,12 @@ func SourceOptFromUIClient(ctx context.Context, c gwclient.Client, dc *dockerui.
129129
},
130130
GitCredHelperOpt: withCredHelper(c),
131131
}
132+
133+
sOpt.SourceFilter = sync.OnceValues(func() (dalec.SourceFilterConfig, error) {
134+
return loadSourceFilterConfig(ctx, c, sOpt.GetContext)
135+
})
136+
137+
return sOpt
132138
}
133139

134140
func SourceOptFromClient(ctx context.Context, c gwclient.Client, platform *ocispecs.Platform) (dalec.SourceOpts, error) {

frontend/request.go

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,43 @@ func marshalDockerfile(ctx context.Context, dt []byte, opts ...llb.ConstraintsOp
142142
}
143143

144144
func getSigningConfigFromContext(ctx context.Context, client gwclient.Client, cfgPath string, configCtxName string, sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) (*dalec.PackageSigner, error) {
145+
dt, err := readConfigFromContext(ctx, client, cfgPath, configCtxName, sOpt, opts...)
146+
if err != nil {
147+
return nil, err
148+
}
149+
150+
var pc dalec.PackageConfig
151+
if err := yaml.Unmarshal(dt, &pc); err != nil {
152+
return nil, err
153+
}
154+
155+
return pc.Signer, nil
156+
}
157+
158+
func getSourceFilterConfigFromContext(ctx context.Context, client gwclient.Client, cfgPath string, configCtxName string, getContext func(string, ...llb.LocalOption) (*llb.State, error), opts ...llb.ConstraintsOpt) (dalec.SourceFilterConfig, error) {
159+
dt, err := readConfigFromContext(ctx, client, cfgPath, configCtxName, dalec.SourceOpts{
160+
GetContext: getContext,
161+
}, opts...)
162+
if err != nil {
163+
return dalec.SourceFilterConfig{}, err
164+
}
165+
166+
return decodeSourceFilterConfig(ctx, dt)
167+
}
168+
169+
func decodeSourceFilterConfig(ctx context.Context, dt []byte) (dalec.SourceFilterConfig, error) {
170+
var cfg dalec.SourceFilterConfig
171+
if err := yaml.UnmarshalContext(ctx, dt, &cfg, yaml.Strict()); err != nil {
172+
return dalec.SourceFilterConfig{}, err
173+
}
174+
return cfg, nil
175+
}
176+
177+
func readConfigFromContext(ctx context.Context, client gwclient.Client, cfgPath string, configCtxName string, sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) ([]byte, error) {
145178
src := dalec.Source{Path: cfgPath, Context: &dalec.SourceContext{Name: configCtxName}}
146-
signConfigState := src.ToState("", sOpt, opts...)
179+
configState := src.ToState("", dalec.SourceOpts{GetContext: sOpt.GetContext}, opts...)
147180

148-
scDef, err := signConfigState.Marshal(ctx)
181+
scDef, err := configState.Marshal(ctx)
149182
if err != nil {
150183
return nil, err
151184
}
@@ -162,19 +195,9 @@ func getSigningConfigFromContext(ctx context.Context, client gwclient.Client, cf
162195
return nil, err
163196
}
164197

165-
dt, err := ref.ReadFile(ctx, gwclient.ReadRequest{
198+
return ref.ReadFile(ctx, gwclient.ReadRequest{
166199
Filename: cfgPath,
167200
})
168-
if err != nil {
169-
return nil, err
170-
}
171-
172-
var pc dalec.PackageConfig
173-
if err := yaml.Unmarshal(dt, &pc); err != nil {
174-
return nil, err
175-
}
176-
177-
return pc.Signer, nil
178201
}
179202

180203
func MaybeSign(ctx context.Context, client gwclient.Client, st llb.State, spec *dalec.Spec, targetKey string, sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) llb.State {
@@ -242,6 +265,27 @@ func getSignConfigCtxName(client gwclient.Client) string {
242265
return client.BuildOpts().Opts["build-arg:"+buildArgDalecSigningConfigContextName]
243266
}
244267

268+
func getSourceFilterConfigPath(client gwclient.Client) string {
269+
return client.BuildOpts().Opts["build-arg:"+dalec.BuildArgDalecSourceFilterConfigPath]
270+
}
271+
272+
func getSourceFilterContextNameWithDefault(client gwclient.Client) string {
273+
configCtxName := dalec.DefaultSourceOptionsContextName
274+
if cn := client.BuildOpts().Opts["build-arg:"+dalec.BuildArgDalecSourceFilterContextName]; cn != "" {
275+
configCtxName = cn
276+
}
277+
return configCtxName
278+
}
279+
280+
func loadSourceFilterConfig(ctx context.Context, client gwclient.Client, getContext func(string, ...llb.LocalOption) (*llb.State, error)) (dalec.SourceFilterConfig, error) {
281+
cfgPath := getSourceFilterConfigPath(client)
282+
if cfgPath == "" {
283+
return dalec.SourceFilterConfig{}, nil
284+
}
285+
286+
return getSourceFilterConfigFromContext(ctx, client, cfgPath, getSourceFilterContextNameWithDefault(client), getContext)
287+
}
288+
245289
func forwardToSigner(ctx context.Context, client gwclient.Client, cfg *dalec.PackageSigner, s llb.State, opts ...llb.ConstraintsOpt) (llb.State, error) {
246290
const (
247291
// See https://github.com/moby/buildkit/blob/d8d946b85c52095d34a52ce210960832f4e06775/frontend/dockerui/context.go#L29

generator_cargohome.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ func (s *Spec) CargohomeDeps(sOpt SourceOpts, worker llb.State, opts ...llb.Cons
101101
})
102102
}
103103

104+
deps = deps.With(sourceFilter(sOpt, opts...))
104105
return &deps
105106
}
106107

generator_gomod.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ func (s *Spec) GomodDeps(sOpt SourceOpts, worker llb.State, opts ...llb.Constrai
245245
})
246246
}
247247

248+
deps = deps.With(sourceFilter(sOpt, opts...))
248249
return &deps
249250
}
250251

generator_nodemodules.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func (s *Spec) NodeModDeps(sOpt SourceOpts, worker llb.State, opts ...llb.Constr
104104
}
105105
merged = merged.With(withNodeMod(gen, worker, key, opts...))
106106
}
107-
result[key] = merged
107+
result[key] = merged.With(sourceFilterAtPath(sOpt, key, opts...))
108108
}
109109
return result
110110
}

generator_pip.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ func (s *Spec) PipDeps(sOpt SourceOpts, worker llb.State, opts ...llb.Constraint
133133

134134
// Merge all cache states into a single state
135135
merged := MergeAtPath(llb.Scratch(), cacheStates, "/", opts...)
136+
merged = merged.With(sourceFilter(sOpt, opts...))
136137
return &merged
137138
}
138139

load.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ func knownArg(key string) bool {
3939
return true
4040
case "DALEC_SKIP_TESTS":
4141
return true
42+
case "DALEC_SOURCE_FILTER_CONFIG_PATH":
43+
return true
44+
case "DALEC_SOURCE_FILTER_CONFIG_CONTEXT_NAME":
45+
return true
4246
case KeyDalecTarget:
4347
return true
4448
}

packaging/linux/rpm/buildroot.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import (
1111
)
1212

1313
func RPMSpec(spec *dalec.Spec, in llb.State, targetKey, dir string, opts ...llb.ConstraintsOpt) llb.State {
14+
return RPMSpecWithSourceFilter(spec, in, targetKey, dir, dalec.SourceFilterConfig{}, opts...)
15+
}
16+
17+
func RPMSpecWithSourceFilter(spec *dalec.Spec, in llb.State, targetKey, dir string, filter dalec.SourceFilterConfig, opts ...llb.ConstraintsOpt) llb.State {
1418
if err := ValidateSpec(spec); err != nil {
1519
return dalec.ErrorState(llb.Scratch(), fmt.Errorf("invalid spec: %w", err))
1620
}
@@ -20,7 +24,7 @@ func RPMSpec(spec *dalec.Spec, in llb.State, targetKey, dir string, opts ...llb.
2024
buf.WriteString("# Automatically generated by " + info.Main.Path + "\n")
2125
buf.WriteString("\n")
2226

23-
if err := WriteSpec(spec, targetKey, buf); err != nil {
27+
if err := WriteSpecWithSourceFilter(spec, targetKey, filter, buf); err != nil {
2428
return dalec.ErrorState(llb.Scratch(), err)
2529
}
2630

@@ -36,5 +40,9 @@ func RPMSpec(spec *dalec.Spec, in llb.State, targetKey, dir string, opts ...llb.
3640
func BuildRoot(worker llb.State, spec *dalec.Spec, sOpt dalec.SourceOpts, targetKey string, opts ...llb.ConstraintsOpt) llb.State {
3741
opts = append(opts, dalec.ProgressGroup("Create RPM buildroot"))
3842
sources := Sources(worker, spec, sOpt, opts...)
39-
return RPMSpec(spec, dalec.MergeAtPath(llb.Scratch(), sources, "SOURCES", opts...), targetKey, "", opts...)
43+
filter, err := sOpt.GetSourceFilter()
44+
if err != nil {
45+
return dalec.ErrorState(llb.Scratch(), err)
46+
}
47+
return RPMSpecWithSourceFilter(spec, dalec.MergeAtPath(llb.Scratch(), sources, "SOURCES", opts...), targetKey, "", filter, opts...)
4048
}

packaging/linux/rpm/template.go

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ var tmplFuncs = map[string]any{
6767

6868
type specWrapper struct {
6969
*dalec.Spec
70-
Target string
70+
Target string
71+
SourceFilter dalec.SourceFilterConfig
7172
}
7273

7374
func (w *specWrapper) Changelog() (fmt.Stringer, error) {
@@ -337,21 +338,46 @@ func (w *specWrapper) Sources() (fmt.Stringer, error) {
337338
if scanner.Err() != nil {
338339
return nil, scanner.Err()
339340
}
341+
if !w.SourceFilter.IsEmpty() && isDir {
342+
if err := docSourceFilter(b, "Exclusions", w.SourceFilter.GlobalExcludes); err != nil {
343+
return nil, err
344+
}
345+
}
340346
fmt.Fprintf(b, "Source%d: %s\n", idx, ref)
341347
}
342348

343349
sourceIdx := len(keys)
344350

345351
if w.Spec.HasGomods() {
352+
if !w.SourceFilter.IsEmpty() {
353+
if err := docSourceFilter(b, "Exclusions", w.SourceFilter.GlobalExcludes); err != nil {
354+
return nil, err
355+
}
356+
}
346357
fmt.Fprintf(b, "Source%d: %s.tar.gz\n", sourceIdx, gomodsName)
347358
sourceIdx += 1
348359
}
349360

350361
if w.Spec.HasCargohomes() {
362+
if !w.SourceFilter.IsEmpty() {
363+
if err := docSourceFilter(b, "Exclusions", w.SourceFilter.GlobalExcludes); err != nil {
364+
return nil, err
365+
}
366+
}
351367
fmt.Fprintf(b, "Source%d: %s.tar.gz\n", sourceIdx, cargohomeName)
352368
sourceIdx += 1
353369
}
354370

371+
if w.Spec.HasPips() {
372+
if !w.SourceFilter.IsEmpty() {
373+
if err := docSourceFilter(b, "Exclusions", w.SourceFilter.GlobalExcludes); err != nil {
374+
return nil, err
375+
}
376+
}
377+
fmt.Fprintf(b, "Source%d: %s.tar.gz\n", sourceIdx, pipDepsName)
378+
sourceIdx += 1
379+
}
380+
355381
if len(w.Spec.Build.Steps) > 0 {
356382
fmt.Fprintf(b, "Source%d: %s\n", sourceIdx, buildScriptName)
357383
}
@@ -362,6 +388,24 @@ func (w *specWrapper) Sources() (fmt.Stringer, error) {
362388
return b, nil
363389
}
364390

391+
func docSourceFilter(w io.Writer, name string, values []string) error {
392+
if _, err := fmt.Fprintf(w, "# %s:\n", name); err != nil {
393+
return err
394+
}
395+
for _, value := range values {
396+
scanner := bufio.NewScanner(strings.NewReader(value))
397+
for scanner.Scan() {
398+
if _, err := fmt.Fprintf(w, "# \t%s\n", scanner.Text()); err != nil {
399+
return err
400+
}
401+
}
402+
if err := scanner.Err(); err != nil {
403+
return err
404+
}
405+
}
406+
return nil
407+
}
408+
365409
func (w *specWrapper) Release() string {
366410
if w.Spec.Revision == "" {
367411
return "1"
@@ -1133,7 +1177,11 @@ func (w *specWrapper) DisableAutoReq() string {
11331177

11341178
// WriteSpec generates an rpm spec from the provided [dalec.Spec] and distro target and writes it to the passed in writer
11351179
func WriteSpec(spec *dalec.Spec, target string, w io.Writer) error {
1136-
s := &specWrapper{spec, target}
1180+
return WriteSpecWithSourceFilter(spec, target, dalec.SourceFilterConfig{}, w)
1181+
}
1182+
1183+
func WriteSpecWithSourceFilter(spec *dalec.Spec, target string, filter dalec.SourceFilterConfig, w io.Writer) error {
1184+
s := &specWrapper{Spec: spec, Target: target, SourceFilter: filter}
11371185

11381186
err := specTmpl.Execute(w, s)
11391187
if err != nil {

0 commit comments

Comments
 (0)