diff --git a/.gitignore b/.gitignore index 378eac2..ee102b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ build +site diff --git a/Makefile b/Makefile index c2689e2..328b4f5 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ NAME=sigil ARCH=$(shell uname -m) ORG=gliderlabs -VERSION=0.1.0 +VERSION=0.2.0 build: mkdir -p build/Linux && GOOS=linux go build -ldflags "-X main.Version $(VERSION)" -o build/Linux/$(NAME) ./cmd @@ -22,10 +22,10 @@ release: circleci: rm ~/.gitconfig - test -d /home/ubuntu/.go_workspace/src/github.com/$(ORG)/$(NAME) || { cd .. \ + rm -rf /home/ubuntu/.go_workspace/src/github.com/$(ORG)/$(NAME) && cd .. \ && mkdir -p /home/ubuntu/.go_workspace/src/github.com/$(ORG) \ && mv $(NAME) /home/ubuntu/.go_workspace/src/github.com/$(ORG)/$(NAME) \ - && ln -s /home/ubuntu/.go_workspace/src/github.com/$(ORG)/$(NAME) $(NAME); } + && ln -s /home/ubuntu/.go_workspace/src/github.com/$(ORG)/$(NAME) $(NAME) clean: rm -rf build release diff --git a/README.md b/README.md index 4c37471..d6f4f43 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,93 @@ -# sigil +# Sigil Standalone string interpolator and template processor + +``` +$ echo '${name} is{{ range seq ${count:-3} }} cool{{ end }}!' | sigil name=Sigil +Sigil is cool cool cool! +``` + +Sigil is a command line tool for template processing and POSIX-compliant +variable expansion. It was created for configuration templating, but can be used +for any text processing. + +## Getting Sigil + +``` +$ curl https://dl.gliderlabs.com/sigil/latest/$(uname -sm|tr \ _).tgz \ + | tar -zxC /usr/local/bin +``` + +Other releases can be downloaded from [Github Releases](https://github.com/gliderlabs/sigil/releases). + +## Using Sigil + +Template text can be provided via STDIN or from a file if provided with the `-f` +flag. Any other arguments are key-values in the form `=`. They are +used as variables. + + * `echo 'Hello, $name' | sigil name=Jeff` + * `sigil -f config.tmpl var1=foo "var2=Hello world"` + +### Variables + +#### POSIX style + +There are two forms of variable syntax in Sigil. The first is POSIX style, which +among other features allows default values or enforces required values: + + * `$variable` - normal POSIX style + * `${variable:-"default"}` - expansion with default value + * `${variable:?}` - fails when not set + +Environment variables are also available as POSIX style variables. This makes +Sigil great for quick and simple string interpolation. + +#### Template style + +The other syntax to use variables is consistent with the rest of the templating +syntax. It uses `{{` and `}}` to define template expressions. Variable expansion +in this form is simply used as: + + * `{{ $variable }}` + +You can do much more with this syntax, such as modifier pipelines. All of which +is explained below. + +### Functions + +There are a number of builtin functions that can be used as modifiers, +conditional tests, expansion data sources, and more. There are two references +for functions available: + + * [Sigil builtins](http://godoc.org/github.com/gliderlabs/sigil/builtin) + * [Go template builtins](http://golang.org/pkg/text/template/#hdr-Functions) + +Here are a few examples: + + * `{{ $variable | capitalize }}` + * `{{ include "file.tmpl" "var1=foo" "var2=bar" }}` + * `{{ file "example.txt" | replace "old" "new" }}` + * `{{ json "file.json" | pointer "/Widgets/0/Name" }}` + +### Conditionals + + * `{{ if expr }} true {{ end }}` + * `{{ if expr }} true {{ else }} false {{ end }}` + * `{{ if expr }} true {{ else if expr }} also true {{ end }}` + +### Loops / Iteration + + * `{{ range expr }} element: {{.}} {{ end }}` + * `{{ range expr }} elements {{ else }} no elements {{ end }}` + +### Full Syntax + +Lots more is possible with this template syntax. Sigil is based on Go's +[text/template package](http://golang.org/pkg/text/template/). You can read full +documentation there. + + +## License + +BSD diff --git a/cmd/sigil.go b/cmd/sigil.go index 2ef1678..78b5329 100644 --- a/cmd/sigil.go +++ b/cmd/sigil.go @@ -16,6 +16,7 @@ var Version string var ( filename = flag.String("f", "", "use template file instead of STDIN") + posix = flag.Bool("p", true, "preprocess with POSIX variable expansion") version = flag.Bool("v", false, "prints version") ) @@ -41,8 +42,14 @@ func main() { fmt.Println(Version) os.Exit(0) } + if *posix { + sigil.PosixPreprocess = true + } vars := make(map[string]string) for _, arg := range os.Args { + if strings.HasPrefix(arg, "-") { + continue + } parts := strings.SplitN(arg, "=", 2) if len(parts) == 2 { vars[parts[0]] = parts[1] diff --git a/sigil.go b/sigil.go index 9d75d5d..300d0ba 100644 --- a/sigil.go +++ b/sigil.go @@ -11,7 +11,8 @@ import ( ) var ( - TemplateDir string + TemplateDir string + PosixPreprocess bool ) var fnMap = template.FuncMap{} @@ -24,6 +25,7 @@ func Register(fm template.FuncMap) { func Execute(input string, vars map[string]string) (string, error) { var tmplVars string + var err error for k, v := range vars { err := os.Setenv(k, v) if err != nil { @@ -32,6 +34,12 @@ func Execute(input string, vars map[string]string) (string, error) { escaped := strings.Replace(v, "\"", "\\\"", -1) tmplVars = tmplVars + fmt.Sprintf("{{ $%s := \"%s\" }}", k, escaped) } + if PosixPreprocess { + input, err = posix.ExpandEnv(input) + if err != nil { + return "", err + } + } tmpl, err := template.New("template").Funcs(fnMap).Parse(tmplVars + input) if err != nil { return "", err @@ -41,9 +49,5 @@ func Execute(input string, vars map[string]string) (string, error) { if err != nil { return "", err } - postprocessed, err := posix.ExpandEnv(buf.String()) - if err != nil { - return "", err - } - return postprocessed, nil + return buf.String(), nil }