2020-09-16 14:50:09 +02:00
|
|
|
package interpolation
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
2020-10-13 14:14:47 +02:00
|
|
|
|
|
|
|
"github.com/SAP/jenkins-library/pkg/log"
|
2020-09-16 14:50:09 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
maxLookupDepth = 10
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
lookupRegex *regexp.Regexp = regexp.MustCompile(`\$\((?P<property>[a-zA-Z0-9\.]*)\)`)
|
|
|
|
captureGroups = setupCaptureGroups(lookupRegex.SubexpNames())
|
|
|
|
)
|
|
|
|
|
|
|
|
// ResolveMap interpolates every string value of a map and tries to lookup references to other properties of that map
|
2020-10-13 14:14:47 +02:00
|
|
|
func ResolveMap(config map[string]interface{}) bool {
|
2020-09-16 14:50:09 +02:00
|
|
|
for key, value := range config {
|
|
|
|
if str, ok := value.(string); ok {
|
2020-10-13 14:14:47 +02:00
|
|
|
resolvedStr, ok := ResolveString(str, config)
|
|
|
|
if !ok {
|
|
|
|
return false
|
2020-09-16 14:50:09 +02:00
|
|
|
}
|
|
|
|
config[key] = resolvedStr
|
|
|
|
}
|
|
|
|
}
|
2020-10-13 14:14:47 +02:00
|
|
|
return true
|
2020-09-16 14:50:09 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 14:14:47 +02:00
|
|
|
func resolveString(str string, lookupMap map[string]interface{}, n int) (string, bool) {
|
2020-09-16 14:50:09 +02:00
|
|
|
matches := lookupRegex.FindAllStringSubmatch(str, -1)
|
|
|
|
if len(matches) == 0 {
|
2020-10-13 14:14:47 +02:00
|
|
|
return str, true
|
2020-09-16 14:50:09 +02:00
|
|
|
}
|
|
|
|
if n == maxLookupDepth {
|
2020-10-13 14:14:47 +02:00
|
|
|
log.Entry().Errorf("Property could not be resolved with a depth of %d. '%s' is still left to resolve", n, str)
|
|
|
|
return "", false
|
2020-09-16 14:50:09 +02:00
|
|
|
}
|
|
|
|
for _, match := range matches {
|
|
|
|
property := match[captureGroups["property"]]
|
|
|
|
if propVal, ok := lookupMap[property]; ok {
|
|
|
|
str = strings.ReplaceAll(str, fmt.Sprintf("$(%s)", property), propVal.(string))
|
|
|
|
} else {
|
2020-10-13 14:14:47 +02:00
|
|
|
// value not found
|
|
|
|
return "", false
|
2020-09-16 14:50:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return resolveString(str, lookupMap, n+1)
|
|
|
|
}
|
|
|
|
|
2020-09-24 07:41:06 +02:00
|
|
|
// ResolveString takes a string and replaces all references inside of it with values from the given lookupMap.
|
2020-09-16 14:50:09 +02:00
|
|
|
// This is being done recursively until the maxLookupDepth is reached.
|
2020-10-13 14:14:47 +02:00
|
|
|
func ResolveString(str string, lookupMap map[string]interface{}) (string, bool) {
|
2020-09-16 14:50:09 +02:00
|
|
|
return resolveString(str, lookupMap, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func setupCaptureGroups(captureGroupsList []string) map[string]int {
|
|
|
|
groups := make(map[string]int, len(captureGroupsList))
|
|
|
|
for i, captureGroupName := range captureGroupsList {
|
|
|
|
if i == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
groups[captureGroupName] = i
|
|
|
|
}
|
|
|
|
return groups
|
|
|
|
}
|