Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1964)

Side by Side Diff: common/data/text/stringtemplate/template.go

Issue 2701033003: milo: Add SwarmBucket templating. (Closed)
Patch Set: full Python template package Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 // Package stringtemplate implements Python string.Template-like substitution.
nodir 2017/02/18 07:00:54 this is a nice package, thanks
6 package stringtemplate
7
8 import (
9 "regexp"
10 "strings"
11
12 "github.com/luci/luci-go/common/errors"
13 )
14
15 const idPattern = "[_a-z][_a-z0-9]*"
16
17 // We're looking for:
18 //
19 // Submatch indices:
20 // [0:1] Full match
21 // [2:3] $$ (escaped)
22 // [4:5] $key (without braces)
23 // [6:7] ${key} (with braces)
24 // [8:9] $... (Invalid)
25 var namedFormatMatcher = regexp.MustCompile(
26 `\$(?:` +
27 `(\$)|` + // Escaped ($$)
28 `(` + idPattern + `)|` + // Without braces: $key
29 `(?:\{(` + idPattern + `)\})|` + // With braces: ${key}
30 `(.*)` + // Invalid
31 `)`)
32
33 // Resolve resolves substitutions in v using the supplied substitution map,
34 // subst.
35 //
36 // A substitution can have the form:
37 //
38 // $key
39 // ${key}
40 //
41 // The substitution can also be escaped using a second "$", such as "$$".
42 //
43 // If the string includes an erroneous substitution, or if a referenced
44 // template variable isn't included in the "substitutions" map, Resolve will
45 // return an error.
46 func Resolve(v string, subst map[string]string) (string, error) {
47 smi := namedFormatMatcher.FindAllStringSubmatchIndex(v, -1)
48 if len(smi) == 0 {
49 // No substitutions.
50 return v, nil
51 }
52
53 var (
54 parts = make([]string, 0, (len(smi)*2)+1)
55 pos = 0
56 )
57
58 for _, match := range smi {
59 key := ""
60 switch {
61 case match[8] >= 0:
62 // Invalid.
63 return "", errors.Reason("invalid template: %(template)q ").
64 D("template", v).
65 Err()
66
67 case match[2] >= 0:
68 // Escaped.
69 parts = append(parts, v[pos:match[2]])
70 pos = match[3]
71 continue
72
73 case match[4] >= 0:
74 // Key (without braces)
75 key = v[match[4]:match[5]]
76 case match[6] >= 0:
77 // Key (with braces)
78 key = v[match[6]:match[7]]
79 }
nodir 2017/02/18 07:00:54 nit: can you add `panic("impossible") in the defau
dnj 2017/02/18 07:42:48 Done.
80
81 // Add anything in between the previous match and the current. I f our match
82 // includes a non-escape character, add that too.
83 if pos < match[0] {
84 parts = append(parts, v[pos:match[0]])
85 }
86 pos = match[1]
87
88 subst, ok := subst[key]
89 if !ok {
90 return "", errors.Reason("no substitution for %(key)q").
91 D("key", key).
92 Err()
93 }
94 parts = append(parts, subst)
95 }
96
97 // Append any trailing string.
98 parts = append(parts, v[pos:])
99
100 // Join the parts.
101 return strings.Join(parts, ""), nil
102 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698