Merge pull request #7267 from thaJeztah/fix_aliases

cmd/docker: fix stringSliceReplaceAt with overlapping matches
This commit is contained in:
Paweł Gronowski
2026-09-03 15:00:28 +02:00
committed by GitHub
2 changed files with 94 additions and 47 deletions
+19 -25
View File
@@ -1,32 +1,26 @@
package main
func stringSliceIndex(s, subs []string) int {
j := 0
if len(subs) > 0 {
for i, x := range s {
if j < len(subs) && subs[j] == x {
j++
} else {
j = 0
}
if len(subs) == j {
return i + 1 - j
}
}
}
return -1
}
import "slices"
// stringSliceReplaceAt replaces the sub-slice find, with the sub-slice replace, in the string
// slice s, returning a new slice and a boolean indicating if the replacement happened.
// requireIdx is the index at which old needs to be found at (or -1 to disregard that).
// stringSliceReplaceAt replaces the sub-slice find with the sub-slice replace in s,
// returning a new slice and a boolean indicating whether the replacement happened.
// requireIndex is the index at which find must be found, or -1 to disregard it.
func stringSliceReplaceAt(s, find, replace []string, requireIndex int) ([]string, bool) {
idx := stringSliceIndex(s, find)
if (requireIndex != -1 && requireIndex != idx) || idx == -1 {
if len(find) == 0 {
return s, false
}
out := append([]string{}, s[:idx]...)
out = append(out, replace...)
out = append(out, s[idx+len(find):]...)
return out, true
if requireIndex >= 0 {
if requireIndex+len(find) > len(s) || !slices.Equal(s[requireIndex:requireIndex+len(find)], find) {
return s, false
}
return slices.Concat(s[:requireIndex], replace, s[requireIndex+len(find):]), true
}
for i := range len(s) - len(find) + 1 {
if slices.Equal(s[i:i+len(find)], find) {
return slices.Concat(s[:i], replace, s[i+len(find):]), true
}
}
return s, false
}
+75 -22
View File
@@ -7,27 +7,80 @@ import (
)
func TestStringSliceReplaceAt(t *testing.T) {
out, ok := stringSliceReplaceAt([]string{"abc", "foo", "bar", "bax"}, []string{"foo", "bar"}, []string{"baz"}, -1)
assert.Assert(t, ok)
assert.DeepEqual(t, []string{"abc", "baz", "bax"}, out)
tests := []struct {
name string
s []string
find []string
replace []string
requireIndex int
expected []string
ok bool
}{
{
name: "replace",
s: []string{"abc", "foo", "bar", "bax"},
find: []string{"foo", "bar"},
replace: []string{"baz"},
requireIndex: -1,
expected: []string{"abc", "baz", "bax"},
ok: true,
},
{
name: "find longer than input",
s: []string{"foo"},
find: []string{"foo", "bar"},
replace: []string{"baz"},
requireIndex: -1,
expected: []string{"foo"},
},
{
name: "wrong required index",
s: []string{"abc", "foo", "bar", "bax"},
find: []string{"foo", "bar"},
replace: []string{"baz"},
requireIndex: 0,
expected: []string{"abc", "foo", "bar", "bax"},
},
{
name: "required index",
s: []string{"foo", "bar", "bax"},
find: []string{"foo", "bar"},
replace: []string{"baz"},
requireIndex: 0,
expected: []string{"baz", "bax"},
ok: true,
},
{
name: "remove",
s: []string{"abc", "foo", "bar", "baz"},
find: []string{"foo", "bar"},
requireIndex: -1,
expected: []string{"abc", "baz"},
ok: true,
},
{
name: "empty find",
s: []string{"foo"},
replace: []string{"baz"},
requireIndex: -1,
expected: []string{"foo"},
},
{
name: "overlapping match",
s: []string{"a", "a", "b"},
find: []string{"a", "b"},
replace: []string{"c"},
requireIndex: -1,
expected: []string{"a", "c"},
ok: true,
},
}
out, ok = stringSliceReplaceAt([]string{"foo"}, []string{"foo", "bar"}, []string{"baz"}, -1)
assert.Assert(t, !ok)
assert.DeepEqual(t, []string{"foo"}, out)
out, ok = stringSliceReplaceAt([]string{"abc", "foo", "bar", "bax"}, []string{"foo", "bar"}, []string{"baz"}, 0)
assert.Assert(t, !ok)
assert.DeepEqual(t, []string{"abc", "foo", "bar", "bax"}, out)
out, ok = stringSliceReplaceAt([]string{"foo", "bar", "bax"}, []string{"foo", "bar"}, []string{"baz"}, 0)
assert.Assert(t, ok)
assert.DeepEqual(t, []string{"baz", "bax"}, out)
out, ok = stringSliceReplaceAt([]string{"abc", "foo", "bar", "baz"}, []string{"foo", "bar"}, nil, -1)
assert.Assert(t, ok)
assert.DeepEqual(t, []string{"abc", "baz"}, out)
out, ok = stringSliceReplaceAt([]string{"foo"}, nil, []string{"baz"}, -1)
assert.Assert(t, !ok)
assert.DeepEqual(t, []string{"foo"}, out)
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
out, ok := stringSliceReplaceAt(tc.s, tc.find, tc.replace, tc.requireIndex)
assert.Equal(t, tc.ok, ok)
assert.DeepEqual(t, tc.expected, out)
})
}
}