1
0
mirror of https://github.com/danog/liquid.git synced 2024-11-26 19:24:45 +01:00

Merge pull request #54 from kke/bind-env

Add --env for binding environment in the CLI tool
This commit is contained in:
Oliver Steele 2022-02-12 23:00:46 +08:00 committed by GitHub
commit 49f7daf257
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 143 additions and 55 deletions

View File

@ -9,10 +9,10 @@
package main
import (
"bytes"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
@ -21,59 +21,79 @@ import (
// for testing
var (
stderr = os.Stderr
stdout io.Writer = os.Stdout
stdin io.Reader = os.Stdin
exit = os.Exit
stderr io.Writer = os.Stderr
stdout io.Writer = os.Stdout
stdin io.Reader = os.Stdin
exit func(int) = os.Exit
env func() []string = os.Environ
bindings map[string]interface{} = map[string]interface{}{}
)
func main() {
if err := run(os.Args[1:]); err != nil {
fmt.Fprintln(stderr, err) // nolint: gas
os.Exit(1)
}
}
var err error
func run(args []string) error {
switch {
case len(args) == 0:
buf := new(bytes.Buffer)
if _, err := io.Copy(buf, stdin); err != nil {
return err
cmdLine := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
cmdLine.Usage = func() {
fmt.Fprintf(stderr, "usage: %s [OPTIONS] [FILE]\n", cmdLine.Name())
fmt.Fprint(stderr, "\nOPTIONS\n")
cmdLine.PrintDefaults()
}
var bindEnvs bool
cmdLine.BoolVar(&bindEnvs, "env", false, "bind environment variables")
err = cmdLine.Parse(os.Args[1:])
if err != nil {
if err == flag.ErrHelp {
exit(0)
return
}
return render(buf.Bytes(), "")
case args[0] == "-h" || args[0] == "--help":
usage()
case strings.HasPrefix(args[0], "-"):
// undefined flag
usage()
fmt.Fprintln(stderr, err)
exit(1)
case len(args) == 1:
s, err := ioutil.ReadFile(args[0])
if err != nil {
return err
return
}
if bindEnvs {
for _, e := range env() {
pair := strings.SplitN(e, "=", 2)
bindings[pair[0]] = pair[1]
}
return render(s, args[0])
}
args := cmdLine.Args()
switch len(args) {
case 0:
// use stdin
case 1:
stdin, err = os.Open(args[0])
default:
usage()
err = errors.New("too many arguments")
}
if err == nil {
err = render()
}
if err != nil {
fmt.Fprintln(stderr, err)
exit(1)
}
return nil
}
func render(b []byte, filename string) (err error) {
tpl, err := liquid.NewEngine().ParseTemplate(b)
func render() error {
buf, err := io.ReadAll(stdin)
if err != nil {
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 {
return err
}
_, err = stdout.Write(out)
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 (
"bytes"
"os"
"testing"
"github.com/stretchr/testify/require"
)
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
src := `{{ "Hello World" | downcase | split: " " | first | append: "!"}}`
buf := new(bytes.Buffer)
buf := &bytes.Buffer{}
stdin = bytes.NewBufferString(src)
stdout = buf
require.NoError(t, run([]string{}))
main()
require.Equal(t, "hello!", buf.String())
// filename
buf = new(bytes.Buffer)
stdin = bytes.NewBufferString("")
// environment binding
var envCalled bool
env = func() []string {
envCalled = true
return []string{"TARGET=World"}
}
src = `Hello, {{ TARGET }}!`
// without -e
stdin = bytes.NewBufferString(src)
buf = &bytes.Buffer{}
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.liquid"}
main()
require.Contains(t, buf.String(), "file system")
// missing file
require.Error(t, run([]string{"testdata/missing_file"}))
// following tests test the exit code
var exitCalled bool
exitCode := 0
exit = func(n int) { exitCalled = true; exitCode = n }
os.Args = []string{"liquid", "testdata/source.liquid"}
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
buf = new(bytes.Buffer)
stdout = buf
require.NoError(t, run([]string{"--help"}))
buf = &bytes.Buffer{}
stderr = buf
os.Args = []string{"liquid", "--help"}
main()
require.Contains(t, buf.String(), "usage:")
require.True(t, exitCalled)
require.Equal(t, 0, exitCode)
// --undefined-flag
exitCode := 0
exit = func(n int) { exitCode = n }
require.NoError(t, run([]string{"--undefined-flag"}))
buf = &bytes.Buffer{}
stderr = buf
os.Args = []string{"liquid", "--undefined-flag"}
main()
require.Equal(t, 1, exitCode)
require.Contains(t, buf.String(), "defined")
// multiple args
exitCode = 0
exit = func(n int) { exitCode = n }
require.NoError(t, run([]string{"file1", "file2"}))
os.Args = []string{"liquid", "testdata/source.liquid", "file2"}
buf = &bytes.Buffer{}
stderr = buf
main()
require.Contains(t, buf.String(), "too many")
require.Equal(t, 1, exitCode)
}

3
cmd/liquid/testdata/env.liquid vendored Normal file
View File

@ -0,0 +1,3 @@
PWD={{ PWD }}
HOME={{ HOME }}
USER={{ USER }}