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

Unified Diff: common/data/text/stringtemplate/template.go

Issue 2701033003: milo: Add SwarmBucket templating. (Closed)
Patch Set: Apparently "/swarming" is gitignored! Added... 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « .gitignore ('k') | common/data/text/stringtemplate/template_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: common/data/text/stringtemplate/template.go
diff --git a/common/data/text/stringtemplate/template.go b/common/data/text/stringtemplate/template.go
new file mode 100644
index 0000000000000000000000000000000000000000..1140c2dc4e10578a6c9cd3deeb3789ce18297145
--- /dev/null
+++ b/common/data/text/stringtemplate/template.go
@@ -0,0 +1,105 @@
+// Copyright 2017 The LUCI Authors. All rights reserved.
+// Use of this source code is governed under the Apache License, Version 2.0
+// that can be found in the LICENSE file.
+
+// Package stringtemplate implements Python string.Template-like substitution.
+package stringtemplate
+
+import (
+ "regexp"
+ "strings"
+
+ "github.com/luci/luci-go/common/errors"
+)
+
+const idPattern = "[_a-z][_a-z0-9]*"
+
+// We're looking for:
+//
+// Submatch indices:
+// [0:1] Full match
+// [2:3] $$ (escaped)
+// [4:5] $key (without braces)
+// [6:7] ${key} (with braces)
+// [8:9] $... (Invalid)
+var namedFormatMatcher = regexp.MustCompile(
+ `\$(?:` +
+ `(\$)|` + // Escaped ($$)
+ `(` + idPattern + `)|` + // Without braces: $key
+ `(?:\{(` + idPattern + `)\})|` + // With braces: ${key}
+ `(.*)` + // Invalid
+ `)`)
+
+// Resolve resolves substitutions in v using the supplied substitution map,
+// subst.
+//
+// A substitution can have the form:
+//
+// $key
+// ${key}
+//
+// The substitution can also be escaped using a second "$", such as "$$".
+//
+// If the string includes an erroneous substitution, or if a referenced
+// template variable isn't included in the "substitutions" map, Resolve will
+// return an error.
+func Resolve(v string, subst map[string]string) (string, error) {
+ smi := namedFormatMatcher.FindAllStringSubmatchIndex(v, -1)
+ if len(smi) == 0 {
+ // No substitutions.
+ return v, nil
+ }
+
+ var (
+ parts = make([]string, 0, (len(smi)*2)+1)
+ pos = 0
+ )
+
+ for _, match := range smi {
+ key := ""
+ switch {
+ case match[8] >= 0:
+ // Invalid.
+ return "", errors.Reason("invalid template: %(template)q").
+ D("template", v).
+ Err()
+
+ case match[2] >= 0:
+ // Escaped.
+ parts = append(parts, v[pos:match[2]])
+ pos = match[3]
+ continue
+
+ case match[4] >= 0:
+ // Key (without braces)
+ key = v[match[4]:match[5]]
+ case match[6] >= 0:
+ // Key (with braces)
+ key = v[match[6]:match[7]]
+
+ default:
+ panic("impossible")
+ }
+
+ // Add anything in between the previous match and the current. If our match
+ // includes a non-escape character, add that too.
+ if pos < match[0] {
+ parts = append(parts, v[pos:match[0]])
+ }
+ pos = match[1]
+
+ subst, ok := subst[key]
+ if !ok {
+ return "", errors.Reason("no substitution for %(key)q").
+ D("key", key).
+ Err()
+ }
+ parts = append(parts, subst)
+ }
+
+ // Append any trailing string.
+ parts = append(parts, v[pos:])
+
+ // Join the parts.
+ return strings.Join(parts, ""), nil
+}
« no previous file with comments | « .gitignore ('k') | common/data/text/stringtemplate/template_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698