/
generator.go
134 lines (105 loc) · 3.68 KB
/
generator.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
/*
Package generator implements a solution to parse a data-driven template and generate an output from it.
A data-driven template is executed by applying it the data structure provided by the payload from the application context.
*/
package generator
import (
"bytes"
"fmt"
"os"
"path/filepath"
"text/template"
"github.com/gulien/orbit/app/context"
OrbitError "github.com/gulien/orbit/app/error"
"github.com/gulien/orbit/app/logger"
"github.com/Masterminds/sprig"
)
type (
// OrbitGenerator provides a set of functions which helps to execute a data-driven template.
OrbitGenerator struct {
// context is an instance of OrbitContext.
context *context.OrbitContext
// funcMap contains sprig functions and custom os function.
funcMap template.FuncMap
}
// orbitData is a simple handler of the payload given by the user.
orbitData struct {
// Orbit will be filled by the payload from the context.
// The goal here is to allow the use of the syntax {{ .Orbit }}
// in a data-driven template.
Orbit map[string]interface{}
}
)
// NewOrbitGenerator creates an instance of OrbitGenerator.
func NewOrbitGenerator(context *context.OrbitContext) *OrbitGenerator {
funcMap := sprig.TxtFuncMap()
funcMap["os"] = getOS
funcMap["verbose"] = isVerbose
funcMap["debug"] = isDebug
funcMap["run"] = run
g := &OrbitGenerator{
context: context,
funcMap: funcMap,
}
logger.Debugf("generator has been instantiated with context %s", g.context)
return g
}
/*
Execute executes a data-driven template by applying it the data structure provided by the application context.
Returns the resulting bytes.
*/
func (g *OrbitGenerator) Execute() (bytes.Buffer, error) {
var (
files []string
data bytes.Buffer
)
files = append(files, g.context.TemplateFilePath)
files = append(files, g.context.Templates...)
tmpl, err := template.New(filepath.Base(g.context.TemplateFilePath)).Delims(g.context.TemplateDelimiters[0], g.context.TemplateDelimiters[1]).Funcs(g.funcMap).ParseFiles(files...)
if err != nil {
return data, OrbitError.NewOrbitErrorf("unable to parse the template file %s. Details:\n%s", g.context.TemplateFilePath, err)
}
tmpl.Option("missingkey=error")
orbitData := &orbitData{
Orbit: g.context.Payload,
}
if err := tmpl.Execute(&data, orbitData); err != nil {
return data, OrbitError.NewOrbitErrorf("unable to execute the template file %s. Details:\n%s", g.context.TemplateFilePath, err)
}
logger.Debugf("template file %s has been parsed and the following data have been retrieved:\n%s", g.context.TemplateFilePath, data.String())
return data, nil
}
/*
Flush writes bytes into a file or to Stdout if no output path given.
This function should be called after Execute function.
*/
func (g *OrbitGenerator) Flush(outputPath string, data bytes.Buffer) error {
if outputPath != "" {
return flushToFile(outputPath, data)
}
// ok, no output file given, let's flush the result to Stdout.
flushToStdout(data)
return nil
}
/*
flushToFile writes bytes into a file.
If the file does not exist, this function will create it.
*/
func flushToFile(outputPath string, data bytes.Buffer) error {
file, err := os.Create(outputPath)
if err != nil {
return OrbitError.NewOrbitErrorf("unable to create the output file %s. Details:\n%s", outputPath, err)
}
defer file.Close()
_, err = file.Write(data.Bytes())
if err != nil {
return OrbitError.NewOrbitErrorf("unable to flushToFile into the output file %s. Details:\n%s", outputPath, err)
}
logger.Infof("output file %s has been created", outputPath)
return nil
}
// flushToStdout writes bytes to Stdout.
func flushToStdout(data bytes.Buffer) {
logger.Infof("no output file given, printing the result to Stdout")
fmt.Println(string(data.Bytes()))
}