1
0
mirror of https://github.com/danog/liquid.git synced 2024-11-30 08:28:58 +01:00

Add --env for binding environment in the CLI tool

This commit is contained in:
Kimmo Lehto 2021-10-14 16:37:56 +03:00 committed by Oliver Steele
parent c68221dd7e
commit ae6b280abe
2 changed files with 140 additions and 55 deletions

View File

@ -9,10 +9,10 @@
package main package main
import ( import (
"bytes" "errors"
"flag"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"strings" "strings"
@ -21,59 +21,79 @@ import (
// for testing // for testing
var ( var (
stderr = os.Stderr stderr io.Writer = os.Stderr
stdout io.Writer = os.Stdout stdout io.Writer = os.Stdout
stdin io.Reader = os.Stdin stdin io.Reader = os.Stdin
exit = os.Exit exit func(int) = os.Exit
env func() []string = os.Environ
bindings map[string]interface{} = map[string]interface{}{}
) )
func main() { func main() {
if err := run(os.Args[1:]); err != nil { var err error
fmt.Fprintln(stderr, err) // nolint: gas
os.Exit(1)
}
}
func run(args []string) error { cmdLine := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
switch { cmdLine.Usage = func() {
case len(args) == 0: fmt.Fprintf(stderr, "usage: %s [OPTIONS] [FILE]\n", cmdLine.Name())
buf := new(bytes.Buffer) fmt.Fprint(stderr, "\nOPTIONS\n")
if _, err := io.Copy(buf, stdin); err != nil { cmdLine.PrintDefaults()
return err
} }
return render(buf.Bytes(), "")
case args[0] == "-h" || args[0] == "--help": var bindEnvs bool
usage() cmdLine.BoolVar(&bindEnvs, "env", false, "bind environment variables")
case strings.HasPrefix(args[0], "-"):
// undefined flag err = cmdLine.Parse(os.Args[1:])
usage()
exit(1)
case len(args) == 1:
s, err := ioutil.ReadFile(args[0])
if err != nil { if err != nil {
return err if err == flag.ErrHelp {
exit(0)
return
} }
return render(s, args[0]) fmt.Fprintln(stderr, err)
exit(1)
return
}
if bindEnvs {
for _, e := range env() {
pair := strings.SplitN(e, "=", 2)
bindings[pair[0]] = pair[1]
}
}
args := cmdLine.Args()
switch len(args) {
case 0:
// use stdin
case 1:
stdin, err = os.Open(args[0])
default: default:
usage() err = errors.New("too many arguments")
}
if err == nil {
err = render()
}
if err != nil {
fmt.Fprintln(stderr, err)
exit(1) exit(1)
} }
return nil
} }
func render(b []byte, filename string) (err error) { func render() error {
tpl, err := liquid.NewEngine().ParseTemplate(b) buf, err := io.ReadAll(stdin)
if err != nil { if err != nil {
return err return err
} }
out, err := tpl.Render(map[string]interface{}{})
tpl, err := liquid.NewEngine().ParseTemplate(buf)
if err != nil {
return err
}
out, err := tpl.Render(bindings)
if err != nil { if err != nil {
return err return err
} }
_, err = stdout.Write(out) _, err = stdout.Write(out)
return err return err
} }
func usage() {
fmt.Fprintf(stdout, "usage: %s [FILE]\n", os.Args[0]) // nolint: gas
}

View File

@ -2,47 +2,112 @@ package main
import ( import (
"bytes" "bytes"
"os"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestMain(t *testing.T) { func TestMain(t *testing.T) {
exit = func(n int) { t.Fatalf("exit called") } oldArgs := os.Args
defer func() {
os.Args = oldArgs
stderr = os.Stderr
stdout = os.Stdout
stdin = os.Stdin
exit = os.Exit
env = os.Environ
bindings = map[string]interface{}{}
}()
exit = func(n int) {
t.Fatalf("exit called")
}
os.Args = []string{"liquid"}
// stdin // stdin
src := `{{ "Hello World" | downcase | split: " " | first | append: "!"}}` src := `{{ "Hello World" | downcase | split: " " | first | append: "!"}}`
buf := new(bytes.Buffer) buf := &bytes.Buffer{}
stdin = bytes.NewBufferString(src) stdin = bytes.NewBufferString(src)
stdout = buf stdout = buf
require.NoError(t, run([]string{})) main()
require.Equal(t, "hello!", buf.String()) require.Equal(t, "hello!", buf.String())
// filename // environment binding
buf = new(bytes.Buffer) var envCalled bool
stdin = bytes.NewBufferString("") env = func() []string {
envCalled = true
return []string{"TARGET=World"}
}
src = `Hello, {{ TARGET }}!`
// without -e
stdin = bytes.NewBufferString(src)
buf = &bytes.Buffer{}
stdout = buf stdout = buf
require.NoError(t, run([]string{"testdata/source.txt"})) os.Args = []string{"liquid"}
main()
require.False(t, envCalled)
require.Equal(t, "Hello, !", buf.String())
// with -e
stdin = bytes.NewBufferString(src)
buf = &bytes.Buffer{}
stdout = buf
os.Args = []string{"liquid", "--env"}
main()
require.True(t, envCalled)
require.Equal(t, "Hello, World!", buf.String())
// filename
stdin = os.Stdin
buf = &bytes.Buffer{}
stdout = buf
os.Args = []string{"liquid", "testdata/source.txt"}
main()
require.Contains(t, buf.String(), "file system") require.Contains(t, buf.String(), "file system")
// missing file // following tests test the exit code
require.Error(t, run([]string{"testdata/missing_file"})) var exitCalled bool
exitCode := 0
exit = func(n int) { exitCalled = true; exitCode = n }
os.Args = []string{"liquid", "testdata/source.txt"}
main()
require.Equal(t, 0, exitCode)
exitCode = 0
// missing file
buf = &bytes.Buffer{}
stderr = buf
os.Args = []string{"liquid", "testdata/missing_file"}
main()
require.Equal(t, 1, exitCode)
require.Contains(t, buf.String(), "no such")
exitCalled = false
// --help // --help
buf = new(bytes.Buffer) buf = &bytes.Buffer{}
stdout = buf stderr = buf
require.NoError(t, run([]string{"--help"})) os.Args = []string{"liquid", "--help"}
main()
require.Contains(t, buf.String(), "usage:") require.Contains(t, buf.String(), "usage:")
require.True(t, exitCalled)
require.Equal(t, 0, exitCode)
// --undefined-flag // --undefined-flag
exitCode := 0 buf = &bytes.Buffer{}
exit = func(n int) { exitCode = n } stderr = buf
require.NoError(t, run([]string{"--undefined-flag"})) os.Args = []string{"liquid", "--undefined-flag"}
main()
require.Equal(t, 1, exitCode) require.Equal(t, 1, exitCode)
require.Contains(t, buf.String(), "defined")
// multiple args // multiple args
exitCode = 0 os.Args = []string{"liquid", "testdata/source.txt", "file2"}
exit = func(n int) { exitCode = n } buf = &bytes.Buffer{}
require.NoError(t, run([]string{"file1", "file2"})) stderr = buf
main()
require.Contains(t, buf.String(), "too many")
require.Equal(t, 1, exitCode) require.Equal(t, 1, exitCode)
} }