From d30adfd0c56d91bbcef54541b394c66efbfb65be Mon Sep 17 00:00:00 2001 From: Brendan Anderson Date: Mon, 11 Jul 2016 23:09:20 -0400 Subject: [PATCH] Unify params and params-file arguments --- README.md | 89 +++++++++++++++++++++++++++---------------------------- main.go | 64 ++++++--------------------------------- params.go | 88 ++++++++++++++++++++++++++---------------------------- usage.go | 9 +++--- 4 files changed, 99 insertions(+), 151 deletions(-) diff --git a/README.md b/README.md index 387efb6..8b6b600 100644 --- a/README.md +++ b/README.md @@ -6,61 +6,60 @@ command line usage. ## Usage -First create a YAML encoded file to house your parameters: +### Templates -```yaml -# bands.yml -title: Great Bands -bands: - - name: The White Stripes - members: - - Jack White - - Meg White - - name: The Strokes - mambers: - - Julian Casablancas - - Nick Valensi - - Albert Hammond, Jr. - - Nikolai Fraiture - - Fabrizio Moretti - - name: Yeah Yeah Yeahs - members: - - Karen O - - Nick Zinner - - Brian Chase -``` +Templates are written in the standard +[Go template](https://golang.org/pkg/text/template) format. + +### Filters + +Filter support comes from the [leekchan/gtf](https://github.com/leekchan/gtf) +package. + +### Parameters + +TWIT accepts parameters for the template as either a YAML file or as a JSON +string. -The create a Go formatted template called *bands.tpl*: +### Example + +For our example, let's image that we needed to write an Apache vhosts +configuration file. + +First we create a template. We'll call it *vhosts.conf.tpl*: ```go - - - - {{ .title }} - - -

{{ .title }}

- {{ range $band := .bands }} -

{{$band.name}}

- - {{ end }} - - +Listen {{ .port }} + +ServerName {{ .server_name }} +DocumentRoot "{{ .document_root }}" +{{ range $host := .hosts }} + + DocumentRoot "{{ $host.document_root }}" + ServerName {{ $host.server_name }} + +{{ end }} ``` -Then run TWIT: +Then we will create a YAML encoded file to hold the parameters. We'll call it +*vhosts.yml*: -``` -$ twit bands.tpl bands.html --params-file=bands.yml --html +```yaml +port: 80 +server_name: server.company.com +document_root: /srv/main +hosts: + - ip: 172.20.30.1 + document_root: /srv/website1 + server_name: site1.company.com + - ip: 172.20.30.2 + document_root: /srv/website2 + server_name: site2.company.com ``` -Or you could pass in JSON instead: +Generate the Apache configuration with TWIT: ``` -$ twit bands.tpl bands.html --params='{"title", "Best Bands Ever"}' +$ twit vhosts.conf.tpl /etc/apache2/sites-available/vhosts.conf -p vhosts.yml ``` diff --git a/main.go b/main.go index bf602c9..0d1d550 100644 --- a/main.go +++ b/main.go @@ -2,31 +2,22 @@ package main import ( "fmt" - htmlTemplate "html/template" - "io/ioutil" "log" "os" - textTemplate "text/template" flag "github.com/ogier/pflag" ) // VERSION of the application. -const VERSION = "v0.1.0" +const VERSION = "v1.0.0" -var ( - source, destination string - params map[string]interface{} - html bool -) +var app *Twit func init() { - var paramsPath, paramsJSON string var version bool + var templateParams TemplateParams - flag.StringVarP(¶msPath, "params-file", "f", "", "") - flag.StringVarP(¶msJSON, "params", "p", "", "") - flag.BoolVarP(&html, "html", "m", false, "") + flag.VarP(&templateParams, "params", "p", "") flag.BoolVarP(&version, "version", "v", false, "") flag.Usage = twitUsage @@ -42,51 +33,14 @@ func init() { log.Fatal("Not enough arguments.") } - source = flag.Arg(0) - destination = flag.Arg(1) - setJSONParams(paramsJSON) - setFileParams(paramsPath) -} - -func main() { - destinationFile, err := os.Create(destination) + twit, err := NewTwit(flag.Arg(0), flag.Arg(1), templateParams) if err != nil { - log.Fatalf( - "Could not create destination file %s. The error was %s", - destination, - err.Error(), - ) + panic(err) } - defer destinationFile.Close() - templateBytes, err := ioutil.ReadFile(source) - if err != nil { - log.Fatalf( - "Could not read the template %s. The error was %s", - source, - err.Error(), - ) - } - - render(string(templateBytes), destinationFile, params) + app = twit } -func render(template string, destFile *os.File, params map[string]interface{}) { - if html { - funcMap := htmlTemplate.FuncMap{ - "ToBool": ToBool, - } - - htmlTemplate. - Must(htmlTemplate.New("html").Funcs(funcMap).Parse(template)). - Execute(destFile, params) - } else { - funcMap := textTemplate.FuncMap{ - "ToBool": ToBool, - } - - textTemplate. - Must(textTemplate.New("text").Funcs(funcMap).Parse(template)). - Execute(destFile, params) - } +func main() { + app.Render() } diff --git a/params.go b/params.go index 754be39..f52943d 100644 --- a/params.go +++ b/params.go @@ -3,68 +3,64 @@ package main import ( "encoding/json" "io/ioutil" - "log" + "strings" "gopkg.in/yaml.v2" ) -func setJSONParams(jsonString string) { - if jsonString == "" { - return - } +// TemplateParams is the representation of template parameters. +type TemplateParams struct { + flags []string + params map[string]interface{} +} - err := resolveParams(jsonString, json.Unmarshal) - if err != nil { - log.Fatalf( - "Could not read parameters. The error was: %s", - err.Error(), - ) - } +// String is the string representation of the TemplateParams. +func (tp *TemplateParams) String() string { + return strings.Join(tp.flags, ", ") } -func setFileParams(paramsPath string) { - if paramsPath == "" { - return - } - paramsBytes, err := ioutil.ReadFile(paramsPath) - if err != nil { - log.Fatalf( - "Could not read file %s. The error was: %s", - paramsPath, - err.Error(), - ) - } +// Set sets a new value from a flag. +func (tp *TemplateParams) Set(value string) error { + // Let's keep track of the flags. + tp.flags = append(tp.flags, value) - err = resolveParams(string(paramsBytes), yaml.Unmarshal) - if err != nil { - log.Fatalf( - "Could not read parameters from %s. The error was: %s", - paramsPath, - err.Error(), - ) - } + err := tp.AddParamsFromFlag(value) + + return err } -type unmarshaller func([]byte, interface{}) error +// AddParamsFromFlag adds params from a flag. Flag is either a path to a YAML +// encoded file or a JSON encoded string. +func (tp *TemplateParams) AddParamsFromFlag(flag string) error { + params := make(map[string]interface{}) + + jsonErr := json.Unmarshal([]byte(flag), ¶ms) -func resolveParams( - paramsString string, - callback func([]byte, interface{}) error, -) (err error) { - var localParams map[string]interface{} + if jsonErr != nil { + // We could not unmarshal as json so let's try as a YAML file. + paramBytes, readErr := ioutil.ReadFile(flag) + if readErr != nil { + return readErr + } - if params == nil { - params = make(map[string]interface{}) + yamlErr := yaml.Unmarshal(paramBytes, ¶ms) + if yamlErr != nil { + return yamlErr + } } - err = callback([]byte(paramsString), &localParams) - if err != nil { - return + if tp.params == nil { + tp.params = make(map[string]interface{}) } - for k, v := range localParams { - params[k] = v + for k, v := range params { + tp.params[k] = v } - return + return nil +} + +// ToMap returns the map of template parameters. +func (tp *TemplateParams) ToMap() map[string]interface{} { + return tp.params } diff --git a/usage.go b/usage.go index ffb61b5..9123eda 100644 --- a/usage.go +++ b/usage.go @@ -32,17 +32,16 @@ Arguments: overwritten. Options: - -f, --params-file=FILE The path to a YAML formatted file containing the + -p, --params=PARAMS Params can either be the path to a YAML formatted file + with template parameters or a JSON encoded string of template parameters. - -p, --params=PARAMS A JSON formatted string containing the template - parameters. - --html Template in HTML mode. This does some output escaping. -h, --help Display this help information. -v, --version Display version information. Examples: twit settings.php.tpl ../default/setting.php --params='{"dbname": "drupal"}' - twit default.conf.tpl /etc/apache2/sites-available/default.conf -f=apache.yml + twit default.conf.tpl /etc/apache2/sites-available/default.conf -p apache.yml + twit template.tpl page.html -p param1.yml -p param2.yml -p '{"key": "value"}' ` )