Skip to content

Commit

Permalink
feat: pongo2 template support
Browse files Browse the repository at this point in the history
  • Loading branch information
tcpj committed Jul 20, 2018
1 parent 12bbe74 commit 85c8531
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 76 deletions.
40 changes: 40 additions & 0 deletions engine/pongo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package engine

import (
"os"
"strings"

"github.com/flosch/pongo2"
log "github.com/golang/glog"
)

type PongoTemplar struct {
Source string
}

func (templar *PongoTemplar) GenerateTemplate() (string, error) {
context := pongo2.Context{}

tmpl, err := pongo2.FromString(templar.Source)
if err != nil {
return "", err
}

for _, val := range os.Environ() {
parts := strings.SplitN(val, "=", 2)
key, value := parts[0], parts[1]

context[key] = value
}

if log.V(3) {
log.Info("Using context %v", context)
}

out, err := tmpl.Execute(context)
if err != nil {
return "", err
}

return out, nil
}
5 changes: 5 additions & 0 deletions engine/templar.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package engine

type Templar interface {
GenerateTemplate() (string, error)
}
45 changes: 31 additions & 14 deletions template.go → engine/template.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@
package main
package engine

import (
"bytes"
"errors"
"flag"
"fmt"
"github.com/Masterminds/sprig"
"os"
"strings"
"text/template"

"github.com/Masterminds/sprig"
)

type TextTemplar struct {
source string
name string
delimLeft string
delimRight string
Source string
Name string
}

type OptionalString struct {
ptr *string
}

var (
delimLeft string
delimRight string
)

func init() {
flag.StringVar(
&delimLeft,
"delim-left",
"",
"(text/template only) Override default left delimiter {{.",
)
flag.StringVar(
&delimRight,
"delim-right",
"",
"(text/template only) Override default right delimiter }}.",
)
}

func (s OptionalString) String() string {
if s.ptr == nil {
return ""
Expand All @@ -46,7 +66,7 @@ func Require(arg interface{}) (string, error) {
}
}

return "", fmt.Errorf("Requires: unsupported type '%T'!", v)
return "", fmt.Errorf("Requires: unsupported type '%T'!", arg)
}

func EnvAll() (map[string]string, error) {
Expand All @@ -65,16 +85,13 @@ var funcMap = template.FuncMap{
"envall": EnvAll,
}

func (templar *TextTemplar) generateTemplate() (string, error) {
var t *template.Template
var err error

t, err = template.New(templar.name).
Delims(templar.delimLeft, templar.delimRight).
func (templar *TextTemplar) GenerateTemplate() (string, error) {
t, err := template.New(templar.Name).
Delims(delimLeft, delimRight).
Option("missingkey=error").
Funcs(funcMap).
Funcs(sprig.TxtFuncMap()).
Parse(templar.source)
Parse(templar.Source)

if err != nil {
return "", err
Expand Down
3 changes: 3 additions & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ import:
version: v1
- package: github.com/Masterminds/sprig
version: 2.8.0
- package: github.com/flosch/pongo2
version: v3
- package: github.com/golang/glog
125 changes: 64 additions & 61 deletions goenvtemplator.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,56 @@ import (
"errors"
"flag"
"fmt"
"github.com/joho/godotenv"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"

log "github.com/golang/glog"
"github.com/joho/godotenv"

"github.com/seznam/goenvtemplator/engine"
)

type Templar interface {
generateTemplate() (string, error)
}
var (
buildVersion string = "Build version was not specified."
)

type templatesPaths []templatePath

type templatePaths struct {
// to parse slice of strings from flags we need to use custom type
type envFiles []string

type templatePath struct {
source string
destination string
}

func (t templatePaths) String() string {
func (t templatePath) String() string {
return fmt.Sprintf("{source: '%s', destination: '%s'}",
t.source, t.destination)
}

type templatesPaths []templatePaths

func (ts *templatesPaths) Set(value string) error {
var t templatePaths
parts := strings.Split(value, ":")
if len(parts) == 2 {
t.source = strings.TrimSpace(parts[0])
t.destination = strings.TrimSpace(parts[1])
} else {
parts := strings.SplitN(value, ":", 2)
if len(parts) < 2 {
return errors.New("Option has invalid format!")
}
*ts = append(*ts, t)

*ts = append(*ts, templatePath{
source: strings.TrimSpace(parts[0]),
destination: strings.TrimSpace(parts[1]),
})

return nil
}

func (ts *templatesPaths) String() string {
return fmt.Sprintf("%v", *ts)
}

// to parse slice of strings from flags we need to use custom type
type envFiles []string

func (ef *envFiles) Set(value string) error {
*ef = append(*ef, value)
return nil
Expand All @@ -61,8 +65,7 @@ func (ef *envFiles) String() string {

func writeFile(destinationPath string, data string) error {
if !filepath.IsAbs(destinationPath) {
log.Fatalf("Destination path '%s' is not absolute!", destinationPath)
return errors.New("absolute path error")
return fmt.Errorf("absolute path error: %s", destinationPath)
}

if err := ioutil.WriteFile(destinationPath, []byte(data), 0664); err != nil {
Expand All @@ -72,10 +75,9 @@ func writeFile(destinationPath string, data string) error {
return nil
}

func readSource(templatePath string) (string, error) {
func readFile(templatePath string) (string, error) {
if !filepath.IsAbs(templatePath) {
log.Fatalf("Template path '%s' is not absolute!", templatePath)
return "", errors.New("absolute path error")
return "", fmt.Errorf("absolute path error: %s", templatePath)
}

var slice []byte
Expand All @@ -88,37 +90,46 @@ func readSource(templatePath string) (string, error) {

}

func generateTemplates(
ts templatesPaths, debug bool, delimLeft string, delimRight string, engine string) error {
func generateTemplates(ts templatesPaths, engineName string) error {
for _, t := range ts {
if v > 0 {
log.Printf("generating %s -> %s", t.source, t.destination)
if log.V(1) {
log.Info("generating %s -> %s", t.source, t.destination)
}

var templar Templar
var templar engine.Templar

source, err := readSource(t.source)
source, err := readFile(t.source)
if err != nil {
return err
}

templateName := filepath.Base(t.source)

switch engine {
default:
templar = &TextTemplar{
source: source,
name: templateName,
delimLeft: delimLeft,
delimRight: delimRight,
switch engineName {
case "pongo":
templar = &engine.PongoTemplar{
Source: source,
}
case "text/template":
templar = &engine.TextTemplar{
Source: source,
Name: templateName,
}
}

if log.V(3) {
log.Info("Templating %s", templateName)
}

render, err := templar.generateTemplate()
render, err := templar.GenerateTemplate()
if err != nil {
return err
}

if log.V(3) {
log.Info("Generated template %s", render)
}

if err = writeFile(t.destination, render); err != nil {
return err
}
Expand All @@ -127,49 +138,41 @@ func generateTemplates(
return nil
}

var (
v int
buildVersion string = "Build version was not specified."
)

func main() {
var tmpls templatesPaths
flag.Var(&tmpls, "template", "Template (/template:/dest). Can be passed multiple times.")
var debugTemplates bool
flag.BoolVar(&debugTemplates, "debug-templates", false, "Print processed templates to stdout.")
var doExec bool
flag.BoolVar(&doExec, "exec", false, "Activates exec by command. First non-flag arguments is the command, the rest are it's arguments.")
var printVersion bool
flag.BoolVar(&printVersion, "version", false, "Prints version.")
var envFileList envFiles
var engine string

flag.Var(&tmpls, "template", "Template (/template:/dest). Can be passed multiple times.")
flag.BoolVar(&doExec, "exec", false, "Activates exec by command. First non-flag arguments is the command, the rest are it's arguments.")
flag.BoolVar(&printVersion, "version", false, "Prints version.")
flag.Var(&envFileList, "env-file", "Additional file with environment variables. Can be passed multiple times.")
var delimLeft string
flag.StringVar(&delimLeft, "delim-left", "", "Override default left delimiter {{.")
var delimRight string
flag.StringVar(&delimRight, "delim-right", "", "Override default right delimiter }}.")
flag.IntVar(&v, "v", 0, "Verbosity level.")
flag.StringVar(
&engine, "engine", "text/template",
"Override default text/template [supports: text/template, pongo]",
)

flag.Parse()

// if no env-file was passed, godotenv.Load loads .env file by default, we want to disable this
if len(envFileList) > 0 {
err := godotenv.Load(envFileList...)
if err != nil {
if err := godotenv.Load(envFileList...); err != nil {
log.Fatal(err)
}
}

if printVersion {
log.Printf("Version: %s", buildVersion)
log.Info("Version: %s", buildVersion)
os.Exit(0)
}

if v > 0 {
log.Print("Generating templates")
if log.V(1) {
log.Info("Generating templates")
}

if err := generateTemplates(tmpls, debugTemplates, delimLeft, delimRight, "default"); err != nil {
panic(err)
if err := generateTemplates(tmpls, engine); err != nil {
log.Fatal(err)
}

if doExec {
Expand Down
Loading

0 comments on commit 85c8531

Please sign in to comment.