/
main.go
140 lines (127 loc) · 3.29 KB
/
main.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
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"text/template"
"github.com/codegangsta/cli"
"github.com/peterbourgon/mergemap"
)
func resolveArgs(args []string) (dataFile, tmplFile, outFile string) {
r := []*string{
&dataFile,
&tmplFile,
&outFile,
}
for i, a := range args {
*r[i] = a
}
return
}
func render(tmpl *template.Template, d map[string]interface{}, w io.Writer) {
err := tmpl.Execute(w, d)
if err != nil {
fmt.Printf("Unable to execute template with error '%s'\n", err.Error())
return
}
}
func main() {
var global string
app := cli.NewApp()
app.Name = "rendr"
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "global, g",
Value: "",
Usage: "global json values to be applied to all items in data.json",
Destination: &global,
EnvVar: "RENDR_GLOBAL",
},
}
app.Usage = `
Rendr a template with a list of datasets contained in a json file and output to files
rendr data.json template.tmpl "result.{{ .PossibleDataKey }}.out"
`
app.EnableBashCompletion = true
app.Action = func(c *cli.Context) {
dataFile, tmplFile, outFile := resolveArgs(c.Args())
js, err := ioutil.ReadFile(dataFile)
if err != nil {
fmt.Printf("Unable to read data file '%s' with error '%s'\n", dataFile, err.Error())
return
}
tmpl, err := template.ParseFiles(tmplFile)
if err != nil {
fmt.Printf("Unable to read template file '%s' with error '%s'\n", tmplFile, err.Error())
return
}
dg := make(map[string]interface{})
if len(global) > 0 {
err = json.Unmarshal([]byte(global), &dg)
if err != nil {
fmt.Printf("Unable to unmarshal json with error '%s'\n", err.Error())
return
}
jstmpl, err := template.New("jstmpl").Parse(string(js))
if err != nil {
fmt.Printf("Unable to parse '%s' into a template with error '%s'\n", dataFile, err.Error())
return
}
jsb := bytes.Buffer{}
err = jstmpl.Execute(&jsb, dg)
if err != nil {
fmt.Printf("Unable to execute template with error '%s'\n", err.Error())
}
js = jsb.Bytes()
}
var dl []map[string]interface{}
err = json.Unmarshal(js, &dl)
if err != nil {
fmt.Printf("Unable to unmarshal json with error '%s'\n", err.Error())
return
}
outFileTmpl, err := template.New("outFileTmpl").Parse(outFile)
if err != nil {
fmt.Printf("Unable to parse outfile name as template with error '%s'\n", err.Error())
return
}
fwritten := map[string]bool{}
for _, d := range dl {
if outFile != "" {
d = mergemap.Merge(dg, d)
ofb := bytes.Buffer{}
err := outFileTmpl.Execute(&ofb, d)
if err != nil {
fmt.Printf("Unable to resolve outfile name with error '%s'\n", err.Error())
return
}
fn := ofb.String()
flag := os.O_WRONLY | os.O_CREATE | os.O_APPEND
if !fwritten[fn] {
flag = flag | os.O_TRUNC
}
dir := path.Dir(fn)
err = os.MkdirAll(dir, 0644)
if err != nil {
fmt.Printf("Unable to create path to file '%s' with error '%s'\n", fn, err.Error())
return
}
fp, err := os.OpenFile(fn, flag, 0666)
if err != nil {
fmt.Printf("Unable to write to file '%s' with error '%s'\n", fn, err.Error())
return
}
fwritten[fn] = true
render(tmpl, d, fp)
fp.Close()
} else {
render(tmpl, d, os.Stdout)
}
}
}
app.Run(os.Args)
}