Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions frontend/debug/handle_sources.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ func Sources(ctx context.Context, client gwclient.Client) (*gwclient.Result, err
return nil, nil, err
}

sources := dalec.Sources(spec, sOpt)

pg := dalec.ProgressGroup("Sources for " + targetKey + " rpm build: " + spec.Name)

sources := dalec.Sources(spec, sOpt, pg)

def, err := dalec.MergeAtPath(llb.Scratch(), dalec.SortedMapValues(sources), "/", pg).Marshal(ctx)
if err != nil {
return nil, nil, err
Expand Down
8 changes: 7 additions & 1 deletion frontend/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func GetBuildArg(client gwclient.Client, k string) (string, bool) {
}

func SourceOptFromUIClient(ctx context.Context, c gwclient.Client, dc *dockerui.Client, platform *ocispecs.Platform) dalec.SourceOpts {
return dalec.SourceOpts{
sOpt := dalec.SourceOpts{
TargetPlatform: platform,
Resolver: c,
Forward: ForwarderFromClient(ctx, c),
Expand All @@ -129,6 +129,12 @@ func SourceOptFromUIClient(ctx context.Context, c gwclient.Client, dc *dockerui.
},
GitCredHelperOpt: withCredHelper(c),
}

sOpt.SourceFilter = sync.OnceValues(func() (dalec.SourceFilterConfig, error) {
return loadSourceFilterConfig(ctx, c, sOpt.GetContext)
})

return sOpt
}

func SourceOptFromClient(ctx context.Context, c gwclient.Client, platform *ocispecs.Platform) (dalec.SourceOpts, error) {
Expand Down
70 changes: 57 additions & 13 deletions frontend/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,43 @@ func marshalDockerfile(ctx context.Context, dt []byte, opts ...llb.ConstraintsOp
}

func getSigningConfigFromContext(ctx context.Context, client gwclient.Client, cfgPath string, configCtxName string, sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) (*dalec.PackageSigner, error) {
dt, err := readConfigFromContext(ctx, client, cfgPath, configCtxName, sOpt, opts...)
if err != nil {
return nil, err
}

var pc dalec.PackageConfig
if err := yaml.Unmarshal(dt, &pc); err != nil {
return nil, err
}

return pc.Signer, nil
}

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) {
dt, err := readConfigFromContext(ctx, client, cfgPath, configCtxName, dalec.SourceOpts{
GetContext: getContext,
}, opts...)
if err != nil {
return dalec.SourceFilterConfig{}, err
}

return decodeSourceFilterConfig(ctx, dt)
}

func decodeSourceFilterConfig(ctx context.Context, dt []byte) (dalec.SourceFilterConfig, error) {
var cfg dalec.SourceFilterConfig
if err := yaml.UnmarshalContext(ctx, dt, &cfg, yaml.Strict()); err != nil {
return dalec.SourceFilterConfig{}, err
}
return cfg, nil
}

func readConfigFromContext(ctx context.Context, client gwclient.Client, cfgPath string, configCtxName string, sOpt dalec.SourceOpts, opts ...llb.ConstraintsOpt) ([]byte, error) {
src := dalec.Source{Path: cfgPath, Context: &dalec.SourceContext{Name: configCtxName}}
signConfigState := src.ToState("", sOpt, opts...)
configState := src.ToState("", dalec.SourceOpts{GetContext: sOpt.GetContext}, opts...)

scDef, err := signConfigState.Marshal(ctx)
scDef, err := configState.Marshal(ctx)
if err != nil {
return nil, err
}
Expand All @@ -162,19 +195,9 @@ func getSigningConfigFromContext(ctx context.Context, client gwclient.Client, cf
return nil, err
}

dt, err := ref.ReadFile(ctx, gwclient.ReadRequest{
return ref.ReadFile(ctx, gwclient.ReadRequest{
Filename: cfgPath,
})
if err != nil {
return nil, err
}

var pc dalec.PackageConfig
if err := yaml.Unmarshal(dt, &pc); err != nil {
return nil, err
}

return pc.Signer, nil
}

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

func getSourceFilterConfigPath(client gwclient.Client) string {
return client.BuildOpts().Opts["build-arg:"+dalec.BuildArgDalecSourceFilterConfigPath]
}

func getSourceFilterContextNameWithDefault(client gwclient.Client) string {
configCtxName := dalec.DefaultSourceOptionsContextName
if cn := client.BuildOpts().Opts["build-arg:"+dalec.BuildArgDalecSourceFilterContextName]; cn != "" {
configCtxName = cn
}
return configCtxName
}

func loadSourceFilterConfig(ctx context.Context, client gwclient.Client, getContext func(string, ...llb.LocalOption) (*llb.State, error)) (dalec.SourceFilterConfig, error) {
cfgPath := getSourceFilterConfigPath(client)
if cfgPath == "" {
return dalec.SourceFilterConfig{}, nil
}

return getSourceFilterConfigFromContext(ctx, client, cfgPath, getSourceFilterContextNameWithDefault(client), getContext)
}

func forwardToSigner(ctx context.Context, client gwclient.Client, cfg *dalec.PackageSigner, s llb.State, opts ...llb.ConstraintsOpt) (llb.State, error) {
const (
// See https://github.com/moby/buildkit/blob/d8d946b85c52095d34a52ce210960832f4e06775/frontend/dockerui/context.go#L29
Expand Down
1 change: 1 addition & 0 deletions generator_cargohome.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func (s *Spec) CargohomeDeps(sOpt SourceOpts, worker llb.State, opts ...llb.Cons
})
}

deps = deps.With(sourceFilter(sOpt, opts...))
return &deps
}

Expand Down
1 change: 1 addition & 0 deletions generator_gomod.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ func (s *Spec) GomodDeps(sOpt SourceOpts, worker llb.State, opts ...llb.Constrai
})
}

deps = deps.With(sourceFilter(sOpt, opts...))
Comment thread
cpuguy83 marked this conversation as resolved.
return &deps
}

Expand Down
2 changes: 1 addition & 1 deletion generator_nodemodules.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func (s *Spec) NodeModDeps(sOpt SourceOpts, worker llb.State, opts ...llb.Constr
}
merged = merged.With(withNodeMod(gen, worker, key, opts...))
}
result[key] = merged
result[key] = merged.With(sourceFilterAtPath(sOpt, key, opts...))
}
return result
}
Expand Down
1 change: 1 addition & 0 deletions generator_pip.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ func (s *Spec) PipDeps(sOpt SourceOpts, worker llb.State, opts ...llb.Constraint

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

Expand Down
4 changes: 4 additions & 0 deletions load.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ func knownArg(key string) bool {
return true
case "DALEC_SKIP_TESTS":
return true
case "DALEC_SOURCE_FILTER_CONFIG_PATH":
return true
case "DALEC_SOURCE_FILTER_CONFIG_CONTEXT_NAME":
return true
case KeyDalecTarget:
return true
}
Expand Down
12 changes: 10 additions & 2 deletions packaging/linux/rpm/buildroot.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import (
)

func RPMSpec(spec *dalec.Spec, in llb.State, targetKey, dir string, opts ...llb.ConstraintsOpt) llb.State {
return RPMSpecWithSourceFilter(spec, in, targetKey, dir, dalec.SourceFilterConfig{}, opts...)
}

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

if err := WriteSpec(spec, targetKey, buf); err != nil {
if err := WriteSpecWithSourceFilter(spec, targetKey, filter, buf); err != nil {
return dalec.ErrorState(llb.Scratch(), err)
}

Expand All @@ -36,5 +40,9 @@ func RPMSpec(spec *dalec.Spec, in llb.State, targetKey, dir string, opts ...llb.
func BuildRoot(worker llb.State, spec *dalec.Spec, sOpt dalec.SourceOpts, targetKey string, opts ...llb.ConstraintsOpt) llb.State {
opts = append(opts, dalec.ProgressGroup("Create RPM buildroot"))
sources := Sources(worker, spec, sOpt, opts...)
return RPMSpec(spec, dalec.MergeAtPath(llb.Scratch(), sources, "SOURCES", opts...), targetKey, "", opts...)
filter, err := sOpt.GetSourceFilter()
if err != nil {
return dalec.ErrorState(llb.Scratch(), err)
}
return RPMSpecWithSourceFilter(spec, dalec.MergeAtPath(llb.Scratch(), sources, "SOURCES", opts...), targetKey, "", filter, opts...)
}
52 changes: 50 additions & 2 deletions packaging/linux/rpm/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ var tmplFuncs = map[string]any{

type specWrapper struct {
*dalec.Spec
Target string
Target string
SourceFilter dalec.SourceFilterConfig
}

func (w *specWrapper) Changelog() (fmt.Stringer, error) {
Expand Down Expand Up @@ -337,21 +338,46 @@ func (w *specWrapper) Sources() (fmt.Stringer, error) {
if scanner.Err() != nil {
return nil, scanner.Err()
}
if !w.SourceFilter.IsEmpty() && isDir {
if err := docSourceFilter(b, "Exclusions", w.SourceFilter.GlobalExcludes); err != nil {
return nil, err
}
}
fmt.Fprintf(b, "Source%d: %s\n", idx, ref)
}

sourceIdx := len(keys)

if w.Spec.HasGomods() {
if !w.SourceFilter.IsEmpty() {
if err := docSourceFilter(b, "Exclusions", w.SourceFilter.GlobalExcludes); err != nil {
return nil, err
}
}
fmt.Fprintf(b, "Source%d: %s.tar.gz\n", sourceIdx, gomodsName)
sourceIdx += 1
}

if w.Spec.HasCargohomes() {
if !w.SourceFilter.IsEmpty() {
if err := docSourceFilter(b, "Exclusions", w.SourceFilter.GlobalExcludes); err != nil {
return nil, err
}
}
fmt.Fprintf(b, "Source%d: %s.tar.gz\n", sourceIdx, cargohomeName)
sourceIdx += 1
}

if w.Spec.HasPips() {
if !w.SourceFilter.IsEmpty() {
if err := docSourceFilter(b, "Exclusions", w.SourceFilter.GlobalExcludes); err != nil {
return nil, err
}
}
fmt.Fprintf(b, "Source%d: %s.tar.gz\n", sourceIdx, pipDepsName)
sourceIdx += 1
}

if len(w.Spec.Build.Steps) > 0 {
fmt.Fprintf(b, "Source%d: %s\n", sourceIdx, buildScriptName)
}
Expand All @@ -362,6 +388,24 @@ func (w *specWrapper) Sources() (fmt.Stringer, error) {
return b, nil
}

func docSourceFilter(w io.Writer, name string, values []string) error {
if _, err := fmt.Fprintf(w, "# %s:\n", name); err != nil {
return err
}
for _, value := range values {
scanner := bufio.NewScanner(strings.NewReader(value))
for scanner.Scan() {
if _, err := fmt.Fprintf(w, "# \t%s\n", scanner.Text()); err != nil {
return err
}
}
if err := scanner.Err(); err != nil {
return err
}
}
return nil
}

func (w *specWrapper) Release() string {
if w.Spec.Revision == "" {
return "1"
Expand Down Expand Up @@ -1133,7 +1177,11 @@ func (w *specWrapper) DisableAutoReq() string {

// WriteSpec generates an rpm spec from the provided [dalec.Spec] and distro target and writes it to the passed in writer
func WriteSpec(spec *dalec.Spec, target string, w io.Writer) error {
s := &specWrapper{spec, target}
return WriteSpecWithSourceFilter(spec, target, dalec.SourceFilterConfig{}, w)
}

func WriteSpecWithSourceFilter(spec *dalec.Spec, target string, filter dalec.SourceFilterConfig, w io.Writer) error {
s := &specWrapper{Spec: spec, Target: target, SourceFilter: filter}

err := specTmpl.Execute(w, s)
if err != nil {
Expand Down
60 changes: 55 additions & 5 deletions packaging/linux/rpm/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,16 @@ func TestTemplateSources(t *testing.T) {
t.Fatalf("unexpected error: %v", err)
}
s2 := out2.String()
if s2 != s {
t.Fatalf("expected no additional sources for pip, got: %q", s2)
// trim last newline from the first output since that has shifted
s3 := s[:len(s)-1]
if !strings.HasPrefix(s2, s3) {
t.Fatalf("expected output to start with %q, got %q", s, out2.String())
}

s2 = strings.TrimPrefix(out2.String(), s3)
expected := "Source1: " + pipDepsName + ".tar.gz\n\n"
if s2 != expected {
t.Fatalf("unexpected sources: expected %q, got: %q", expected, s2)
}
})

Expand Down Expand Up @@ -253,11 +261,10 @@ func TestTemplateSources(t *testing.T) {
s = s[len(expected):]
}

// Now we should have entries for gomods and cargohome.
// Now we should have entries for gomods, cargohome, and pip deps.
// Note there are 2 gomod sources but they should be combined into one entry.
// Pip no longer creates a separate cache source.

expected := "Source7: " + gomodsName + ".tar.gz\nSource8: " + cargohomeName + ".tar.gz\n\n"
expected := "Source7: " + gomodsName + ".tar.gz\nSource8: " + cargohomeName + ".tar.gz\nSource9: " + pipDepsName + ".tar.gz\n\n"
if s != expected {
t.Fatalf("generators: unexpected sources: expected %q, got: %q", expected, s)
}
Expand All @@ -266,6 +273,49 @@ func TestTemplateSources(t *testing.T) {
t.Fatalf("unexpected trailing sources: %q", s)
}
})

t.Run("source filter docs", func(t *testing.T) {
w := &specWrapper{
Spec: &dalec.Spec{
Sources: map[string]dalec.Source{
"src1": {
Includes: []string{"cmd/**"},
Excludes: []string{"testdata/**"},
Inline: &dalec.SourceInline{
Dir: &dalec.SourceInlineDir{},
},
},
},
},
SourceFilter: dalec.SourceFilterConfig{GlobalExcludes: []string{"vendor/**"}},
}

out, err := w.Sources()
assert.NilError(t, err)
s := out.String()
assert.Check(t, strings.Contains(s, "# \tIncludes:\n# \t\t cmd/**\n"))
assert.Check(t, strings.Contains(s, "# \tExcludes:\n# \t\t testdata/**\n"))
assert.Check(t, strings.Contains(s, "# Exclusions:\n# \tvendor/**\n"))
})

t.Run("source filter docs multiline exclusion", func(t *testing.T) {
w := &specWrapper{
Spec: &dalec.Spec{
Sources: map[string]dalec.Source{
"src1": {
Inline: &dalec.SourceInline{Dir: &dalec.SourceInlineDir{}},
},
},
},
SourceFilter: dalec.SourceFilterConfig{GlobalExcludes: []string{"vendor/**\nmalicious: value"}},
}

out, err := w.Sources()
assert.NilError(t, err)
s := out.String()
assert.Check(t, strings.Contains(s, "# Exclusions:\n# \tvendor/**\n# \tmalicious: value\n"))
assert.Check(t, !strings.Contains(s, "\nmalicious: value\n"))
})
}

func TestTemplate_Artifacts(t *testing.T) {
Expand Down
Loading