Skip to content

Commit

Permalink
Implement expansion of curly braces
Browse files Browse the repository at this point in the history
These patterns are used in DependencyPattern, such as in conflict
declarations, as well as in doc/pkg-vulnerabilities.
  • Loading branch information
rillig committed Dec 14, 2024
1 parent c0234af commit cdce508
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 0 deletions.
36 changes: 36 additions & 0 deletions v23/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,42 @@ func hasBalancedBraces(text string) bool {
return n == 0
}

// expandCurlyBraces expands "a{b,c}d" to ["abd", "acd"].
// The braces in s must be balanced, see hasBalancedBraces.
func expandCurlyBraces(s string) []string {

find := func(i int, b byte) int {
n := 0
for ; i < len(s); i++ {
switch {
case (s[i] == '}' || s[i] == b) && n == 0:
return i
case s[i] == '{':
n++
case s[i] == '}':
n--
}
}
return i
}

lbrace := strings.IndexByte(s, '{')
rbrace := find(lbrace+1, '}')
if lbrace == -1 || rbrace == len(s) {
return []string{s}
}

var expanded []string
pieceStart := lbrace + 1
for pieceStart < rbrace+1 {
pieceEnd := find(pieceStart, ',')
word := s[0:lbrace] + s[pieceStart:pieceEnd] + s[rbrace+1:]
expanded = append(expanded, expandCurlyBraces(word)...)
pieceStart = pieceEnd + 1
}
return expanded
}

var pathMatchers = make(map[string]*pathMatcher)

type pathMatcher struct {
Expand Down
24 changes: 24 additions & 0 deletions v23/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,30 @@ func (s *Suite) Test_shquote(c *check.C) {
test("~", "'~'")
}

func Test_expandCurlyBraces(t *testing.T) {
tests := []struct {
s string
want []string
}{
{"}", []string{"}"}},
{"{}{}{}{}{}{}{}", []string{""}},
{"{}}", []string{"}"}},
{"{}{}{}{}{}{}{}}", []string{"}"}},
{"{thir,f{our,if}}teen", []string{"thirteen", "fourteen", "fifteen"}},
{"pkgname<=1.0", []string{"pkgname<=1.0"}},
{"{pkgname,pkgname-client}<=1.0", []string{"pkgname<=1.0", "pkgname-client<=1.0"}},
{"a{b,c,{d,e}}f", []string{"abf", "acf", "adf", "aef"}},
}
for _, tt := range tests {
t.Run(tt.s, func(t *testing.T) {
got := expandCurlyBraces(tt.s)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("got %q, want %q", got, tt.want)
}
})
}
}

func (s *Suite) Test_LazyStringBuilder_WriteByte__exact_match(c *check.C) {
t := s.Init(c)

Expand Down

0 comments on commit cdce508

Please sign in to comment.