-
Notifications
You must be signed in to change notification settings - Fork 1
/
config.go
148 lines (127 loc) · 3.38 KB
/
config.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package main
import (
"reflect"
"regexp"
"strings"
"github.com/spf13/viper"
)
// Config is parsed from the config file.
type config struct {
// docker command config
Image string
Cmd []string
Path string
Exec []string
// docker exec config
User string `option:"user"`
Workdir string `option:"workdir"`
Env []string `option:"env"`
Detach bool `option:"detach"`
// docker run config, also uses exec config
Name string `option:"name"`
Link []string `option:"link"`
Volume []string `option:"volume"`
Rm bool `option:"rm"`
Device []string `option:"device"`
Expose []string `option:"expose"`
Publish []string `option:"publish"`
}
// options returns the options to pass to docker
func (c *config) options() []string {
list := []string{}
v := reflect.ValueOf(c)
// v is a pointer, get the element
v = v.Elem()
// Loop through all the fields.
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
// Get the option tag and split it by comma, in case we add something else.
opts := strings.Split(v.Type().Field(i).Tag.Get("option"), ",")
if len(opts) == 0 || opts[0] == "" {
// If there are no options or the option is empty, it is not an option.
continue
}
opt := "--" + opts[0]
switch f.Kind() {
case reflect.String:
if len(f.String()) > 0 {
// If it is a string and the field is not empty, add the option.
list = append(list, opt, f.String())
}
case reflect.Slice:
li, ok := f.Interface().([]string)
if !ok {
panic("value not a []string")
}
// For slices add all the elements of the slice as options.
for _, el := range li {
if len(el) > 0 {
list = append(list, opt, el)
}
}
case reflect.Bool:
if f.Bool() {
// For a boolean value add the option if it is true.
list = append(list, opt)
}
}
}
return list
}
// replaceStrings searches for strings in some configuration keys and replaces them with what the function returns for them.
func (c *config) replaceStrings(r *regexp.Regexp, trans func(string, string) string) {
// The function to fix the string used by the reflection processing.
fix := func(item string, key string) string {
fixed := item
// Find all regex matches.
for _, s := range r.FindAllString(item, -1) {
// Replace the matches with the translation function.
fixed = strings.Replace(fixed, s, trans(s, key), 1)
}
return fixed
}
v := reflect.ValueOf(c)
// v is a pointer, get the element
v = v.Elem()
// Loop through all the fields.
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
n := v.Type().Field(i).Name
switch f.Kind() {
case reflect.String:
if len(f.String()) > 0 {
// Fix the string with our fix function.
f.SetString(fix(f.String(), n))
}
case reflect.Slice:
li, ok := f.Interface().([]string)
if !ok {
panic("value not a []string")
}
for j, el := range li {
if len(el) > 0 {
// Fix each element of the slice with our fix function.
f.Index(j).SetString(fix(el, n))
}
}
}
}
}
// getConf returns the configuration for the program
func getConf(cfg *viper.Viper, run bool) (*config, error) {
var c *config
if err := cfg.Unmarshal(&c); err != nil {
return nil, err
}
if run {
// Set default values for when running an image
c.Rm = true
rcfg := cfg.Sub("run")
if rcfg != nil {
if err := rcfg.Unmarshal(&c); err != nil {
return c, err
}
}
}
return c, nil
}