@@ -21,8 +21,9 @@ const usage = `Usage:
21
21
Options:
22
22
-j, --json-data DATA_INPUT Input data source in JSON format.
23
23
-y, --yaml-data DATA_INPUT Input data source in YAML format.
24
+ -t, --subtree JSON and YAML only, use a subtree of the data source instead of the full contents
24
25
-e, --env-data Input data source comes from environment variables.
25
- -i, --input INPUT Input template file in go template format.
26
+ -i, --input INPUT Input template file or directory containig template(s) in go template format.
26
27
-o, --output OUTPUT Write the output to the file at OUTPUT.
27
28
-s, --strict Strict mode (causes an error if a key is missing)
28
29
-d, --delimiters Set the delimiters used in the templates in the format <left>:<right> (default: '{{:}}')
@@ -35,10 +36,95 @@ Examples:
35
36
$ datasubst --input examples/basic-input.txt --json-data examples/basic-data.json
36
37
$ echo "v3: {{ .key2.first.key3 }}" | datasubst --yaml-data examples/basic-data.yaml
37
38
$ echo "{{ .TEST1 }} {{ .TEST2 }}" | TEST1="hello" TEST2="world" datasubst --env-data
38
- $ echo "(( .TEST ))" | TEST="hi" datasubst --env-data -d '((:))'`
39
+ $ echo "(( .TEST ))" | TEST="hi" datasubst --env-data -d '((:))'
40
+ $ echo "v3: {{ .first.key3 }}" | datasubst --yaml-data examples/basic-data.yaml --subtree .key2`
39
41
40
42
var Version string
41
43
44
+ var (
45
+ inputFile , outputFile , jsonDataFile , yamlDataFile , delimiters , subtree string
46
+ envFlag , strictFlag , helpFlag , versionFlag bool
47
+ )
48
+
49
+ func main () {
50
+ log .SetFlags (0 )
51
+ parseArgs ()
52
+
53
+ // Read input
54
+ in := os .Stdin
55
+ if inputFile != "" && inputFile != "-" {
56
+ f , err := os .Open (inputFile )
57
+ if err != nil {
58
+ log .Fatalf ("Error opening input file: %v\n " , err )
59
+ }
60
+ defer f .Close ()
61
+ in = f
62
+ }
63
+ tplStr , err := ioutil .ReadAll (in )
64
+ if err != nil {
65
+ log .Fatalf ("Error reading input file: %v\n " , err )
66
+ }
67
+
68
+ // Read and Parse data file
69
+ var data interface {}
70
+ if jsonDataFile != "" {
71
+ data , err = parseJSON (jsonDataFile )
72
+ if subtree != "" {
73
+ data = getSubTree (data , subtree )
74
+ }
75
+ } else if yamlDataFile != "" {
76
+ data , err = parseYAML (yamlDataFile )
77
+ if subtree != "" {
78
+ data = getSubTree (data , subtree )
79
+ }
80
+ } else {
81
+ data , err = parseEnv ()
82
+ }
83
+ if err != nil {
84
+ log .Fatalf ("Error opening data file: %v\n " , err )
85
+ }
86
+
87
+ // Prepare Template
88
+ tpl := template .New ("template" )
89
+ if strictFlag {
90
+ tpl .Option ("missingkey=error" )
91
+ }
92
+ if delimiters != "" {
93
+ if strings .Count (delimiters , ":" ) != 1 || delimiters [len (delimiters )- 1 :] == ":" || delimiters [0 :1 ] == ":" {
94
+ log .Fatal ("Error: invalid delimiter format. Must be '<left>:<right>' and ':'" )
95
+ }
96
+ d := strings .Split (delimiters , ":" )
97
+ tpl .Delims (d [0 ], d [1 ])
98
+ }
99
+ tpl , err = tpl .Parse (string (tplStr ))
100
+ if err != nil {
101
+ log .Fatalf ("Error parsing template: %v\n " , err )
102
+ }
103
+
104
+ // Render
105
+ out := os .Stdout
106
+ if outputFile != "" && outputFile != "-" {
107
+ out , err = os .Create (outputFile )
108
+ if err != nil {
109
+ log .Fatalf ("Error creating output file: %v\n " , err )
110
+ }
111
+ defer out .Close ()
112
+ }
113
+ err = tpl .Execute (out , data )
114
+ if err != nil {
115
+ log .Fatalf ("Error rendering template: %v\n " , err )
116
+ }
117
+ }
118
+
119
+ func getSubTree (data interface {}, substree string ) interface {} {
120
+ st := strings .Split (subtree , "." )[1 :]
121
+ for _ , k := range st {
122
+ v := data .(map [string ]interface {})
123
+ data = v [k ]
124
+ }
125
+ return data
126
+ }
127
+
42
128
func parseYAML (yamlDataFile string ) (interface {}, error ) {
43
129
var data interface {}
44
130
dataFile , err := os .Open (filepath .Clean (yamlDataFile ))
@@ -86,22 +172,18 @@ func countTrue(b ...bool) int {
86
172
return n
87
173
}
88
174
89
- func main () {
90
- log .SetFlags (0 )
175
+ func parseArgs () {
91
176
flag .Usage = func () { fmt .Fprintf (os .Stderr , "%s\n " , usage ) }
92
177
if len (os .Args ) == 1 {
93
178
log .Fatalf ("%s\n " , usage )
94
179
}
95
180
96
- var (
97
- inputFile , outputFile , jsonDataFile , yamlDataFile , delimiters string
98
- envFlag , strictFlag , helpFlag , versionFlag bool
99
- )
100
-
101
- flag .StringVar (& inputFile , "input" , "" , "input template file in go template format" )
102
- flag .StringVar (& inputFile , "i" , "" , "input template file in go template format" )
181
+ flag .StringVar (& inputFile , "input" , "" , "input template file or directory containig template(s) in go template format" )
182
+ flag .StringVar (& inputFile , "i" , "" , "input template file or directory containig template(s) in go template format" )
103
183
flag .StringVar (& jsonDataFile , "json-data" , "" , "input data source in JSON format" )
104
184
flag .StringVar (& jsonDataFile , "j" , "" , "input data source in JSON format" )
185
+ flag .StringVar (& subtree , "subtree" , "" , "subtree to be used (e.g. .my_key.my_subkey)" )
186
+ flag .StringVar (& subtree , "t" , "" , "subtree to be used (e.g. .my_key.my_subkey)" )
105
187
flag .BoolVar (& envFlag , "env-data" , false , "input data source comes from environment variables" )
106
188
flag .BoolVar (& envFlag , "e" , false , "input data source comes from environment variables" )
107
189
flag .StringVar (& outputFile , "output" , "" , "write the output to the file at OUTPUT" )
@@ -119,76 +201,22 @@ func main() {
119
201
if versionFlag {
120
202
if Version != "" {
121
203
fmt .Println (Version )
122
- return
204
+ os . Exit ( 0 )
123
205
}
124
206
if buildInfo , ok := debug .ReadBuildInfo (); ok {
125
207
fmt .Println (buildInfo .Main .Version )
126
- return
208
+ os . Exit ( 0 )
127
209
}
128
210
fmt .Println ("(unknown)" )
129
- return
211
+ os . Exit ( 0 )
130
212
}
131
213
132
214
if helpFlag {
133
215
fmt .Println (usage )
134
- return
216
+ os . Exit ( 0 )
135
217
}
136
218
137
219
if countTrue (jsonDataFile != "" , yamlDataFile != "" , envFlag ) != 1 {
138
220
log .Fatal ("Error: please specify --json-data, --yaml-data or --env-data" )
139
221
}
140
- // Read input
141
- in := os .Stdin
142
- if inputFile != "" && inputFile != "-" {
143
- f , err := os .Open (inputFile )
144
- if err != nil {
145
- log .Fatalf ("Error opening input file: %v\n " , err )
146
- }
147
- defer f .Close ()
148
- in = f
149
- }
150
- tplStr , err := ioutil .ReadAll (in )
151
- if err != nil {
152
- log .Fatalf ("Error reading input file: %v\n " , err )
153
- }
154
- // Read and Parse data file
155
- var data interface {}
156
- if jsonDataFile != "" {
157
- data , err = parseJSON (jsonDataFile )
158
- } else if yamlDataFile != "" {
159
- data , err = parseYAML (yamlDataFile )
160
- } else {
161
- data , err = parseEnv ()
162
- }
163
- if err != nil {
164
- log .Fatalf ("Error opening data file: %v\n " , err )
165
- }
166
- tpl := template .New ("template" )
167
- if strictFlag {
168
- tpl .Option ("missingkey=error" )
169
- }
170
- if delimiters != "" {
171
- if strings .Count (delimiters , ":" ) != 1 || delimiters [len (delimiters )- 1 :] == ":" || delimiters [0 :1 ] == ":" {
172
- log .Fatal ("Error: invalid delimiter format. Must be '<left>:<right>' and ':'" )
173
- }
174
- d := strings .Split (delimiters , ":" )
175
- tpl .Delims (d [0 ], d [1 ])
176
- }
177
- tpl , err = tpl .Parse (string (tplStr ))
178
- if err != nil {
179
- log .Fatalf ("Error parsing template: %v\n " , err )
180
- }
181
- // Render
182
- out := os .Stdout
183
- if outputFile != "" && outputFile != "-" {
184
- out , err = os .Create (outputFile )
185
- if err != nil {
186
- log .Fatalf ("Error creating output file: %v\n " , err )
187
- }
188
- defer out .Close ()
189
- }
190
- err = tpl .Execute (out , data )
191
- if err != nil {
192
- log .Fatalf ("Error rendering template: %v\n " , err )
193
- }
194
222
}
0 commit comments