Skip to content

Commit

Permalink
Unify params and params-file arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
bander2 committed Jul 12, 2016
1 parent c1cc704 commit d30adfd
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 151 deletions.
89 changes: 44 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
<!doctype html>
<html>
<head>
<title>{{ .title }}</title>
</head>
<body>
<h1>{{ .title }}</h1>
{{ range $band := .bands }}
<h2>{{$band.name}}</h2>
<ul>
{{ range $member := $band.members }}
<li>{{ $member }}</li>
{{ end }}
</ul>
{{ end }}
</body>
</html>
Listen {{ .port }}

ServerName {{ .server_name }}
DocumentRoot "{{ .document_root }}"

{{ range $host := .hosts }}
<VirtualHost {{ $host.ip }}>
DocumentRoot "{{ $host.document_root }}"
ServerName {{ $host.server_name }}
</VirtualHost>
{{ 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
```
64 changes: 9 additions & 55 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(&paramsPath, "params-file", "f", "", "")
flag.StringVarP(&paramsJSON, "params", "p", "", "")
flag.BoolVarP(&html, "html", "m", false, "")
flag.VarP(&templateParams, "params", "p", "")
flag.BoolVarP(&version, "version", "v", false, "")

flag.Usage = twitUsage
Expand All @@ -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()
}
88 changes: 42 additions & 46 deletions params.go
Original file line number Diff line number Diff line change
Expand Up @@ -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), &params)

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, &params)
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
}
9 changes: 4 additions & 5 deletions usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"}'
`
)

Expand Down

0 comments on commit d30adfd

Please # to comment.