/
applications.go
124 lines (104 loc) · 3.38 KB
/
applications.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"regexp"
"strings"
"text/template"
)
const (
leftDelimTemplate = "[["
rightDelimTemplate = "]]"
)
var (
templateReplacer *strings.Replacer = strings.NewReplacer(`[`, `\[`, `]`, `\]`)
regexpTemplate *regexp.Regexp = regexp.MustCompile(templateReplacer.Replace(leftDelimTemplate + ".+" + rightDelimTemplate))
)
// Applications is the structure of the file containing all the templates variables
type Applications struct {
Default map[string]interface{} `yaml:"default" json:"default"`
Apps map[string]map[string]interface{} `yaml:"apps" json:"apps"`
alters map[string]VariableAlteration
}
// VariableAlteration is a function to alter variable
type VariableAlteration func(interface{}) (interface{}, error)
// NewApplications create a new application
func NewApplications(file string) (*Applications, error) {
var ret Applications
data, err := ioutil.ReadFile(file)
if err != nil {
return nil, fmt.Errorf("failed to read applications file : %s", err)
}
err = json.Unmarshal(data, &ret)
if err != nil {
return nil, fmt.Errorf("failed to unmarshall applications file : %s", err)
}
return &ret, nil
}
// Names returns all the applications names availables
func (app *Applications) Names() []string {
var ret []string
for name := range app.Apps {
ret = append(ret, name)
}
return ret
}
// AddAlteration adds the possibility to alter an application variable when getting the variables
func (app *Applications) AddAlteration(key string, ptr VariableAlteration) {
if app.alters == nil {
app.alters = make(map[string]VariableAlteration)
}
app.alters[key] = ptr
}
// Variables returns the default variables overwritten by the app variables
func (app *Applications) Variables(name string) (map[string]interface{}, error) {
variables, exists := app.Apps[name]
if !exists {
return nil, fmt.Errorf("application %s does not exists", name)
}
variables["id"] = name
var ret map[string]interface{} = make(map[string]interface{})
for key, defaultValue := range app.Default {
if defaultStrValue, ok := defaultValue.(string); ok && regexpTemplate.MatchString(defaultStrValue) {
tmpl, err := template.New(name+key).Delims(leftDelimTemplate, rightDelimTemplate).Parse(defaultStrValue)
if err != nil {
return nil, err
}
buf := new(bytes.Buffer)
if err := tmpl.Execute(buf, variables); err != nil {
return nil, err
}
defaultValue = buf.String()
}
ret[key] = defaultValue
}
var err error
for key, value := range variables {
// Check if the variables contains '...' for prepend the default variables
strValue, isString := value.(string)
if isString && strings.HasPrefix(strValue, "...") {
defaultValue, exists := app.Default[key]
if !exists {
return nil, fmt.Errorf("cannot preprend value to key %s : default value does not exists", key)
}
defaultStrValue, isString := defaultValue.(string)
if !isString {
return nil, fmt.Errorf("cannot preprend value to key %s : default value is not type of string", key)
}
value = strings.Replace(strValue, "...", defaultStrValue, 1)
}
ret[key] = value
}
for key, value := range ret {
// Check if we need to alter the value
if ptr, exists := app.alters[key]; exists {
ret[key], err = ptr(value)
if err != nil {
return nil, fmt.Errorf("failed to apply alter on key %s : %s", key, err)
}
}
}
return ret, nil
}