Skip to content

Commit fc365c4

Browse files
burak-okcpuguy83
authored andcommitted
fix: correct series file entries and sort patch keys in deb target
Fix two bugs in the deb patch handling: 1. sourcePatchesDir wrote the target source name instead of the patch source name to the series file, causing incorrect documentation. 2. createPatchScript iterated over the Patches map without sorting, causing non-deterministic patch application order unlike the RPM target which sorts keys. Add unit tests for both issues. Signed-off-by: Burak Ok <burakok@microsoft.com>
1 parent e655e03 commit fc365c4

2 files changed

Lines changed: 107 additions & 3 deletions

File tree

packaging/linux/deb/debroot.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func sourcePatchesDir(sOpt dalec.SourceOpts, base llb.State, dir, name string, s
6767
st := src.ToState(patchStateName, sOpt, opts...)
6868

6969
st = base.File(llb.Copy(st, copySrc, filepath.Join(patchesPath, patch.Source)), opts...)
70-
seriesBuf.WriteString(name + "\n")
70+
seriesBuf.WriteString(patch.Source + "\n")
7171
states = append(states, st)
7272
}
7373

@@ -343,8 +343,9 @@ func createPatchScript(spec *dalec.Spec, cfg *SourcePkgConfig) []byte {
343343

344344
writeScriptHeader(buf, cfg)
345345

346-
for name, patches := range spec.Patches {
347-
for _, patch := range patches {
346+
sorted := dalec.SortMapKeys(spec.Patches)
347+
for _, name := range sorted {
348+
for _, patch := range spec.Patches[name] {
348349
p := filepath.Join("${DEBIAN_DIR:=debian}/dalec/patches", name, patch.Source)
349350
fmt.Fprintf(buf, "patch -d %q -p%d -s < %q\n", name, *patch.Strip, p)
350351
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package deb
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"path/filepath"
7+
"strings"
8+
"testing"
9+
10+
"github.com/moby/buildkit/client/llb"
11+
"github.com/project-dalec/dalec"
12+
"gotest.tools/v3/assert"
13+
)
14+
15+
func intPtr(i int) *int {
16+
return &i
17+
}
18+
19+
func TestCreatePatchScript_MultiplePatchesSorted(t *testing.T) {
20+
t.Parallel()
21+
22+
spec := &dalec.Spec{
23+
Patches: map[string][]dalec.PatchSpec{
24+
"src-b": {
25+
{Source: "patch-b1", Strip: intPtr(1)},
26+
},
27+
"src-a": {
28+
{Source: "patch-a1", Strip: intPtr(1)},
29+
{Source: "patch-a2", Strip: intPtr(1)},
30+
},
31+
},
32+
}
33+
34+
got := string(createPatchScript(spec, nil))
35+
36+
// Patches should be sorted by the source name being patched (the key in Patches map)
37+
// to ensure deterministic ordering, matching RPM behavior.
38+
idxA := strings.Index(got, `patch -d "src-a"`)
39+
idxB := strings.Index(got, `patch -d "src-b"`)
40+
41+
assert.Assert(t, idxA >= 0, "expected patch command for src-a, got:\n%s", got)
42+
assert.Assert(t, idxB >= 0, "expected patch command for src-b, got:\n%s", got)
43+
assert.Assert(t, idxA < idxB, "expected src-a patches before src-b patches for deterministic ordering, got:\n%s", got)
44+
45+
// Verify all patch commands are present
46+
assert.Assert(t, strings.Contains(got, "patch-a1"), "expected patch-a1 reference in script, got:\n%s", got)
47+
assert.Assert(t, strings.Contains(got, "patch-a2"), "expected patch-a2 reference in script, got:\n%s", got)
48+
assert.Assert(t, strings.Contains(got, "patch-b1"), "expected patch-b1 reference in script, got:\n%s", got)
49+
}
50+
51+
func TestSourcePatchesDir_SeriesContainsPatchSourceNames(t *testing.T) {
52+
t.Parallel()
53+
54+
spec := &dalec.Spec{
55+
Sources: map[string]dalec.Source{
56+
"my-patch1": {
57+
Inline: &dalec.SourceInline{
58+
File: &dalec.SourceInlineFile{
59+
Contents: "patch1 content",
60+
},
61+
},
62+
},
63+
"my-patch2": {
64+
Inline: &dalec.SourceInline{
65+
File: &dalec.SourceInlineFile{
66+
Contents: "patch2 content",
67+
},
68+
},
69+
},
70+
},
71+
Patches: map[string][]dalec.PatchSpec{
72+
"my-src": {
73+
{Source: "my-patch1", Strip: intPtr(1)},
74+
{Source: "my-patch2", Strip: intPtr(1)},
75+
},
76+
},
77+
}
78+
79+
ctx := context.Background()
80+
base := llb.Scratch().File(llb.Mkdir("patches", 0o755))
81+
states := sourcePatchesDir(dalec.SourceOpts{}, base, "patches", "my-src", spec)
82+
83+
// The last state should be the series file
84+
seriesState := states[len(states)-1]
85+
def, err := seriesState.Marshal(ctx)
86+
assert.NilError(t, err)
87+
88+
// Find the series file in the definition and verify its contents
89+
mkfile, err := findMkfile(t, def.ToPB(), filepath.Join("/patches", "my-src", "series"))
90+
assert.NilError(t, err)
91+
assert.Assert(t, mkfile != nil, "series file not found in the state definition")
92+
93+
// The series file should contain the patch source names, not the target name
94+
content := string(mkfile.Data)
95+
lines := strings.Split(strings.TrimSpace(content), "\n")
96+
assert.Assert(t, len(lines) == 2, "expected 2 lines in series file, got %d: %q", len(lines), content)
97+
assert.Assert(t, lines[0] == "my-patch1", "expected first line to be 'my-patch1', got %q", lines[0])
98+
assert.Assert(t, lines[1] == "my-patch2", "expected second line to be 'my-patch2', got %q", lines[1])
99+
100+
// Verify it does NOT contain the target source name repeated
101+
assert.Assert(t, !bytes.Contains(mkfile.Data, []byte("my-src")),
102+
"series file should contain patch source names, not the target source name 'my-src', got: %q", content)
103+
}

0 commit comments

Comments
 (0)