@@ -7,18 +7,30 @@ import (
7
7
"fmt"
8
8
"regexp"
9
9
"strings"
10
+
11
+ "github.com/docker/cli/internal/lazyregexp"
10
12
)
11
13
12
14
const (
13
15
delimiter = "\\ $"
14
16
subst = "[_a-z][_a-z0-9]*(?::?[-?][^}]*)?"
15
17
)
16
18
17
- var defaultPattern = regexp . MustCompile (fmt .Sprintf (
19
+ var defaultPattern = lazyregexp . New (fmt .Sprintf (
18
20
"%s(?i:(?P<escaped>%s)|(?P<named>%s)|{(?P<braced>%s)}|(?P<invalid>))" ,
19
21
delimiter , delimiter , subst , subst ,
20
22
))
21
23
24
+ // regexper is an internal interface to allow passing a [lazyregexp.Regexp]
25
+ // in places where a custom ("regular") [regexp.Regexp] is accepted. It defines
26
+ // only the methods we currently use.
27
+ type regexper interface {
28
+ FindAllStringSubmatch (s string , n int ) [][]string
29
+ FindStringSubmatch (s string ) []string
30
+ ReplaceAllStringFunc (src string , repl func (string ) string ) string
31
+ SubexpNames () []string
32
+ }
33
+
22
34
// DefaultSubstituteFuncs contains the default SubstituteFunc used by the docker cli
23
35
var DefaultSubstituteFuncs = []SubstituteFunc {
24
36
softDefault ,
@@ -51,10 +63,16 @@ type SubstituteFunc func(string, Mapping) (string, bool, error)
51
63
// SubstituteWith substitutes variables in the string with their values.
52
64
// It accepts additional substitute function.
53
65
func SubstituteWith (template string , mapping Mapping , pattern * regexp.Regexp , subsFuncs ... SubstituteFunc ) (string , error ) {
66
+ return substituteWith (template , mapping , pattern , subsFuncs ... )
67
+ }
68
+
69
+ // SubstituteWith substitutes variables in the string with their values.
70
+ // It accepts additional substitute function.
71
+ func substituteWith (template string , mapping Mapping , pattern regexper , subsFuncs ... SubstituteFunc ) (string , error ) {
54
72
var err error
55
73
result := pattern .ReplaceAllStringFunc (template , func (substring string ) string {
56
74
matches := pattern .FindStringSubmatch (substring )
57
- groups := matchGroups (matches , pattern )
75
+ groups := matchGroups (matches , defaultPattern )
58
76
if escaped := groups ["escaped" ]; escaped != "" {
59
77
return escaped
60
78
}
@@ -93,19 +111,23 @@ func SubstituteWith(template string, mapping Mapping, pattern *regexp.Regexp, su
93
111
94
112
// Substitute variables in the string with their values
95
113
func Substitute (template string , mapping Mapping ) (string , error ) {
96
- return SubstituteWith (template , mapping , defaultPattern , DefaultSubstituteFuncs ... )
114
+ return substituteWith (template , mapping , defaultPattern , DefaultSubstituteFuncs ... )
97
115
}
98
116
99
117
// ExtractVariables returns a map of all the variables defined in the specified
100
118
// composefile (dict representation) and their default value if any.
101
119
func ExtractVariables (configDict map [string ]any , pattern * regexp.Regexp ) map [string ]string {
120
+ return extractVariables (configDict , pattern )
121
+ }
122
+
123
+ func extractVariables (configDict map [string ]any , pattern regexper ) map [string ]string {
102
124
if pattern == nil {
103
125
pattern = defaultPattern
104
126
}
105
127
return recurseExtract (configDict , pattern )
106
128
}
107
129
108
- func recurseExtract (value any , pattern * regexp. Regexp ) map [string ]string {
130
+ func recurseExtract (value any , pattern regexper ) map [string ]string {
109
131
m := map [string ]string {}
110
132
111
133
switch val := value .(type ) {
@@ -141,7 +163,7 @@ type extractedValue struct {
141
163
value string
142
164
}
143
165
144
- func extractVariable (value any , pattern * regexp. Regexp ) ([]extractedValue , bool ) {
166
+ func extractVariable (value any , pattern regexper ) ([]extractedValue , bool ) {
145
167
sValue , ok := value .(string )
146
168
if ! ok {
147
169
return []extractedValue {}, false
@@ -227,7 +249,7 @@ func withRequired(substitution string, mapping Mapping, sep string, valid func(s
227
249
return value , true , nil
228
250
}
229
251
230
- func matchGroups (matches []string , pattern * regexp. Regexp ) map [string ]string {
252
+ func matchGroups (matches []string , pattern regexper ) map [string ]string {
231
253
groups := make (map [string ]string )
232
254
for i , name := range pattern .SubexpNames ()[1 :] {
233
255
groups [name ] = matches [i + 1 ]
0 commit comments