summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Henderson <dhenderson@gmail.com>2021-01-17 15:46:57 -0500
committerDave Henderson <dhenderson@gmail.com>2021-01-17 16:48:48 -0500
commitd6c72218477357bc855f700ca6134d40cd96adf0 (patch)
tree0eb5a3f593fde1aafac6988aafe5ffbe197c2568
parent5835d0d688525716be902297193f78227994f5bf (diff)
Inject stdin/out/err instead of always using os.Stdin/out/err
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
-rw-r--r--config.go6
-rw-r--r--data/datasource.go8
-rw-r--r--data/datasource_stdin.go8
-rw-r--r--go.sum16
-rw-r--r--gomplate_test.go5
-rw-r--r--internal/cmd/config.go4
-rw-r--r--internal/cmd/config_test.go22
-rw-r--r--internal/cmd/main.go10
-rw-r--r--internal/cmd/main_test.go8
-rw-r--r--internal/config/configfile.go18
-rw-r--r--plugins.go5
-rw-r--r--template.go95
-rw-r--r--template_test.go84
13 files changed, 142 insertions, 147 deletions
diff --git a/config.go b/config.go
index 49629248..f9000551 100644
--- a/config.go
+++ b/config.go
@@ -2,9 +2,11 @@ package gomplate
import (
"io"
+ "os"
"strings"
"github.com/hairyhenderson/gomplate/v3/internal/config"
+ "github.com/hairyhenderson/gomplate/v3/internal/iohelpers"
)
// Config - values necessary for rendering templates with gomplate.
@@ -127,7 +129,9 @@ func (o *Config) toNewConfig() (*config.Config, error) {
LDelim: o.LDelim,
RDelim: o.RDelim,
Templates: o.Templates,
- OutWriter: o.Out,
+ Stdin: os.Stdin,
+ Stdout: &iohelpers.NopCloser{Writer: o.Out},
+ Stderr: os.Stderr,
}
err := cfg.ParsePluginFlags(o.Plugins)
if err != nil {
diff --git a/data/datasource.go b/data/datasource.go
index 147ba013..0f2c44fa 100644
--- a/data/datasource.go
+++ b/data/datasource.go
@@ -3,7 +3,6 @@ package data
import (
"context"
"fmt"
- "io"
"mime"
"net/http"
"net/url"
@@ -19,9 +18,6 @@ import (
"github.com/hairyhenderson/gomplate/v3/vault"
)
-// stdin - for overriding in tests
-var stdin io.Reader
-
func regExtension(ext, typ string) {
err := mime.AddExtensionType(ext, typ)
if err != nil {
@@ -114,6 +110,10 @@ func NewData(datasourceArgs, headerArgs []string) (*Data, error) {
// FromConfig - internal use only!
func FromConfig(ctx context.Context, cfg *config.Config) *Data {
+ // XXX: This is temporary, and will be replaced with something a bit cleaner
+ // when datasources are refactored
+ stdin = cfg.Stdin
+
sources := map[string]*Source{}
for alias, d := range cfg.DataSources {
sources[alias] = &Source{
diff --git a/data/datasource_stdin.go b/data/datasource_stdin.go
index f23905d2..8216573b 100644
--- a/data/datasource_stdin.go
+++ b/data/datasource_stdin.go
@@ -1,16 +1,16 @@
package data
import (
+ "io"
"io/ioutil"
- "os"
"github.com/pkg/errors"
)
+// stdin - for overriding in tests
+var stdin io.Reader
+
func readStdin(source *Source, args ...string) ([]byte, error) {
- if stdin == nil {
- stdin = os.Stdin
- }
b, err := ioutil.ReadAll(stdin)
if err != nil {
return nil, errors.Wrapf(err, "Can't read %s", stdin)
diff --git a/go.sum b/go.sum
index 11a9ee54..4c5c7e96 100644
--- a/go.sum
+++ b/go.sum
@@ -105,9 +105,7 @@ github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZo
github.com/aws/aws-sdk-go v1.17.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.36.1/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
-github.com/aws/aws-sdk-go v1.36.19 h1:zbJZKkxeDiYxUYFjymjWxPye+qa1G2gRVyhIzZrB9zA=
-github.com/aws/aws-sdk-go v1.36.19/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
-github.com/aws/aws-sdk-go v1.36.23/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
+github.com/aws/aws-sdk-go v1.36.28 h1:JVRN7BZgwQ31SQCBwG5QM445+ynJU0ruKu+miFIijYY=
github.com/aws/aws-sdk-go v1.36.28/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -266,9 +264,7 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.3 h1:twObb+9XcuH5B9V1TBCvvvZoO6iEdILi2a76PYn5rJI=
-github.com/google/uuid v1.1.3/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.4/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.5 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I=
github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.4.0 h1:kXcsA/rIGzJImVqPdhfnr6q0xsS9gU0515q1EPpJ9fE=
github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
@@ -511,18 +507,16 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
-github.com/ugorji/go v1.2.2 h1:60ZHIOcsJlo3bJm9CbTVu7OSqT2mxaEmyQbK2NwCkn0=
-github.com/ugorji/go v1.2.2/go.mod h1:bitgyERdV7L7Db/Z5gfd5v2NQMNhhiFiZwpgMw2SP7k=
+github.com/ugorji/go v1.2.3 h1:WbFSXLxDFKVN69Sk8t+XHGzVCD7R8UoAATR8NqZgTbk=
github.com/ugorji/go v1.2.3/go.mod h1:5l8GZ8hZvmL4uMdy+mhCO1LjswGRYco9Q3HfuisB21A=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
-github.com/ugorji/go/codec v1.2.2 h1:08Gah8d+dXj4cZNUHhtuD/S4PXD5WpVbj5B8/ClELAQ=
-github.com/ugorji/go/codec v1.2.2/go.mod h1:OM8g7OAy52uYl3Yk+RE/3AS1nXFn1Wh4PPLtupCxbuU=
+github.com/ugorji/go/codec v1.2.3 h1:/mVYEV+Jo3IZKeA5gBngN0AvNnQltEDkR+eQikkWQu0=
github.com/ugorji/go/codec v1.2.3/go.mod h1:5FxzDJIgeiWJZslYHPj+LS1dq1ZBQVelZFnjsFGI/Uc=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
diff --git a/gomplate_test.go b/gomplate_test.go
index 1d569958..797eb87e 100644
--- a/gomplate_test.go
+++ b/gomplate_test.go
@@ -16,7 +16,6 @@ import (
"github.com/hairyhenderson/gomplate/v3/conv"
"github.com/hairyhenderson/gomplate/v3/data"
"github.com/hairyhenderson/gomplate/v3/env"
- "github.com/hairyhenderson/gomplate/v3/internal/iohelpers"
"github.com/stretchr/testify/assert"
)
@@ -156,10 +155,8 @@ func TestCustomDelim(t *testing.T) {
}
func TestRunTemplates(t *testing.T) {
- defer func() { Stdout = os.Stdout }()
buf := &bytes.Buffer{}
- Stdout = &iohelpers.NopCloser{Writer: buf}
- config := &Config{Input: "foo", OutputFiles: []string{"-"}}
+ config := &Config{Input: "foo", OutputFiles: []string{"-"}, Out: buf}
err := RunTemplates(config)
assert.NoError(t, err)
assert.Equal(t, "foo", buf.String())
diff --git a/internal/cmd/config.go b/internal/cmd/config.go
index 3db450af..f45f5ff1 100644
--- a/internal/cmd/config.go
+++ b/internal/cmd/config.go
@@ -48,6 +48,10 @@ func loadConfig(cmd *cobra.Command, args []string) (*config.Config, error) {
return nil, err
}
+ cfg.Stdin = cmd.InOrStdin()
+ cfg.Stdout = cmd.OutOrStdout()
+ cfg.Stderr = cmd.ErrOrStderr()
+
// reset defaults before validation
cfg.ApplyDefaults()
diff --git a/internal/cmd/config_test.go b/internal/cmd/config_test.go
index aa5e09f3..1bc82e09 100644
--- a/internal/cmd/config_test.go
+++ b/internal/cmd/config_test.go
@@ -1,6 +1,7 @@
package cmd
import (
+ "bytes"
"context"
"fmt"
"os"
@@ -63,7 +64,12 @@ func TestLoadConfig(t *testing.T) {
fs = afero.NewMemMapFs()
defer func() { fs = afero.NewOsFs() }()
+ stdin, stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}
cmd := &cobra.Command{}
+ cmd.SetIn(stdin)
+ cmd.SetOut(stdout)
+ cmd.SetErr(stderr)
+
cmd.Args = optionalExecArgs
cmd.Flags().StringSlice("file", []string{"-"}, "...")
cmd.Flags().StringSlice("out", []string{"-"}, "...")
@@ -80,9 +86,11 @@ func TestLoadConfig(t *testing.T) {
OutputFiles: []string{"-"},
LDelim: "{{",
RDelim: "}}",
- PostExecInput: os.Stdin,
- OutWriter: os.Stdout,
+ PostExecInput: stdin,
PluginTimeout: 5 * time.Second,
+ Stdin: stdin,
+ Stdout: stdout,
+ Stderr: stderr,
}
assert.NoError(t, err)
assert.EqualValues(t, expected, out)
@@ -94,9 +102,11 @@ func TestLoadConfig(t *testing.T) {
OutputFiles: []string{"-"},
LDelim: "{{",
RDelim: "}}",
- PostExecInput: os.Stdin,
- OutWriter: os.Stdout,
+ PostExecInput: stdin,
PluginTimeout: 5 * time.Second,
+ Stdin: stdin,
+ Stdout: out.Stdout,
+ Stderr: stderr,
}
assert.NoError(t, err)
assert.EqualValues(t, expected, out)
@@ -110,9 +120,11 @@ func TestLoadConfig(t *testing.T) {
ExecPipe: true,
PostExec: []string{"tr", "[a-z]", "[A-Z]"},
PostExecInput: out.PostExecInput,
- OutWriter: out.PostExecInput,
OutputFiles: []string{"-"},
PluginTimeout: 5 * time.Second,
+ Stdin: stdin,
+ Stdout: out.Stdout,
+ Stderr: stderr,
}
assert.NoError(t, err)
assert.EqualValues(t, expected, out)
diff --git a/internal/cmd/main.go b/internal/cmd/main.go
index 3c7862d5..9217a725 100644
--- a/internal/cmd/main.go
+++ b/internal/cmd/main.go
@@ -18,7 +18,7 @@ import (
)
// postRunExec - if templating succeeds, the command following a '--' will be executed
-func postRunExec(ctx context.Context, cfg *config.Config) error {
+func postRunExec(ctx context.Context, cfg *config.Config, stdout, stderr io.Writer) error {
args := cfg.PostExec
if len(args) > 0 {
log := zerolog.Ctx(ctx)
@@ -29,8 +29,8 @@ func postRunExec(ctx context.Context, cfg *config.Config) error {
// nolint: gosec
c := exec.CommandContext(ctx, name, args...)
c.Stdin = cfg.PostExecInput
- c.Stderr = os.Stderr
- c.Stdout = os.Stdout
+ c.Stderr = stderr
+ c.Stdout = stdout
// make sure all signals are propagated
sigs := make(chan os.Signal, 1)
@@ -98,7 +98,7 @@ func NewGomplateCmd() *cobra.Command {
// Note: once stdin/out/err are externalized we should only do this
// if stdout isn't ending with its own newline!
if len(cfg.OutputFiles) == 0 || (len(cfg.OutputFiles) == 1 && cfg.OutputFiles[0] == "-") && !cfg.ExecPipe {
- fmt.Fprintf(os.Stderr, "\n")
+ fmt.Fprintf(cmd.ErrOrStderr(), "\n")
}
log.Debug().Int("templatesRendered", gomplate.Metrics.TemplatesProcessed).
Int("errors", gomplate.Metrics.Errors).
@@ -108,7 +108,7 @@ func NewGomplateCmd() *cobra.Command {
if err != nil {
return err
}
- return postRunExec(ctx, cfg)
+ return postRunExec(ctx, cfg, cmd.OutOrStdout(), cmd.ErrOrStderr())
},
Args: optionalExecArgs,
}
diff --git a/internal/cmd/main_test.go b/internal/cmd/main_test.go
index 5c688443..678d5979 100644
--- a/internal/cmd/main_test.go
+++ b/internal/cmd/main_test.go
@@ -1,6 +1,7 @@
package cmd
import (
+ "bytes"
"context"
"testing"
@@ -47,4 +48,11 @@ func TestRunMain(t *testing.T) {
err = Main(ctx, []string{"--bogus"}, nil, nil, nil)
assert.Error(t, err)
+
+ stdin := &bytes.Buffer{}
+ stdout := &bytes.Buffer{}
+ stderr := &bytes.Buffer{}
+ err = Main(ctx, []string{"-i", "hello"}, stdin, stdout, stderr)
+ assert.NoError(t, err)
+ assert.Equal(t, "hello", stdout.String())
}
diff --git a/internal/config/configfile.go b/internal/config/configfile.go
index a20c95cb..9969648e 100644
--- a/internal/config/configfile.go
+++ b/internal/config/configfile.go
@@ -14,6 +14,7 @@ import (
"strings"
"time"
+ "github.com/hairyhenderson/gomplate/v3/internal/iohelpers"
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
)
@@ -59,8 +60,11 @@ type Config struct {
ExtraHeaders map[string]http.Header `yaml:"-"`
// internal use only, can't be injected in YAML
- PostExecInput io.ReadWriter `yaml:"-"`
- OutWriter io.Writer `yaml:"-"`
+ PostExecInput io.Reader `yaml:"-"`
+
+ Stdin io.Reader `yaml:"-"`
+ Stdout io.Writer `yaml:"-"`
+ Stderr io.Writer `yaml:"-"`
}
var cfgContextKey = struct{}{}
@@ -452,12 +456,14 @@ func (c *Config) ApplyDefaults() {
}
if c.ExecPipe {
- c.PostExecInput = &bytes.Buffer{}
- c.OutWriter = c.PostExecInput
+ pipe := &bytes.Buffer{}
+ c.PostExecInput = pipe
c.OutputFiles = []string{"-"}
+
+ // --exec-pipe redirects standard out to the out pipe
+ c.Stdout = &iohelpers.NopCloser{Writer: pipe}
} else {
- c.PostExecInput = os.Stdin
- c.OutWriter = os.Stdout
+ c.PostExecInput = c.Stdin
}
if c.PluginTimeout == 0 {
diff --git a/plugins.go b/plugins.go
index b4d56188..4beedd3a 100644
--- a/plugins.go
+++ b/plugins.go
@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"fmt"
+ "io"
"os"
"os/exec"
"os/signal"
@@ -23,6 +24,7 @@ func bindPlugins(ctx context.Context, cfg *config.Config, funcMap template.FuncM
name: k,
path: v,
timeout: cfg.PluginTimeout,
+ stderr: cfg.Stderr,
}
if _, ok := funcMap[plugin.name]; ok {
return fmt.Errorf("function %q is already bound, and can not be overridden", plugin.name)
@@ -37,6 +39,7 @@ type plugin struct {
name, path string
timeout time.Duration
ctx context.Context
+ stderr io.Writer
}
// builds a command that's appropriate for running scripts
@@ -78,7 +81,7 @@ func (p *plugin) run(args ...interface{}) (interface{}, error) {
defer cancel()
c := exec.CommandContext(ctx, name, a...)
c.Stdin = nil
- c.Stderr = os.Stderr
+ c.Stderr = p.stderr
outBuf := &bytes.Buffer{}
c.Stdout = outBuf
diff --git a/template.go b/template.go
index 7d1e1bbf..fe50d069 100644
--- a/template.go
+++ b/template.go
@@ -20,12 +20,8 @@ import (
const gomplateignore = ".gomplateignore"
// for overriding in tests
-var stdin io.ReadCloser = os.Stdin
var fs = afero.NewOsFs()
-// Stdout allows overriding the writer to use when templates are written to stdout ("-").
-var Stdout io.WriteCloser = os.Stdout
-
// tplate - models a gomplate template file...
type tplate struct {
name string
@@ -73,22 +69,24 @@ func (t *tplate) toGoTemplate(g *gomplate) (tmpl *template.Template, err error)
return tmpl, nil
}
-// loadContents - reads the template in _once_ if it hasn't yet been read. Uses the name!
-func (t *tplate) loadContents() (err error) {
- if t.contents == "" {
- t.contents, err = readInput(t.name)
+// loadContents - reads the template
+func (t *tplate) loadContents(in io.Reader) ([]byte, error) {
+ if in == nil {
+ f, err := fs.OpenFile(t.name, os.O_RDONLY, 0)
+ if err != nil {
+ return nil, fmt.Errorf("failed to open %s: %w", t.name, err)
+ }
+ // nolint: errcheck
+ defer f.Close()
+ in = f
}
- return err
-}
-func (t *tplate) addTarget(cfg *config.Config) (err error) {
- if t.name == "<arg>" && t.targetPath == "" {
- t.targetPath = "-"
- }
- if t.target == nil {
- t.target, err = openOutFile(cfg, t.targetPath, t.mode, t.modeOverride)
+ b, err := ioutil.ReadAll(in)
+ if err != nil {
+ return nil, fmt.Errorf("failed to load contents of %s: %w", t.name, err)
}
- return err
+
+ return b, nil
}
// gatherTemplates - gather and prepare input template(s) and output file(s) for rendering
@@ -99,11 +97,6 @@ func gatherTemplates(cfg *config.Config, outFileNamer func(string) (string, erro
return nil, err
}
- // --exec-pipe redirects standard out to the out pipe
- if cfg.OutWriter != nil {
- Stdout = &iohelpers.NopCloser{Writer: cfg.OutWriter}
- }
-
switch {
// the arg-provided input string gets a special name
case cfg.Input != "":
@@ -133,14 +126,31 @@ func gatherTemplates(cfg *config.Config, outFileNamer func(string) (string, erro
return processTemplates(cfg, templates)
}
+// processTemplates - reads data into the given templates as necessary and opens
+// outputs for writing as necessary
func processTemplates(cfg *config.Config, templates []*tplate) ([]*tplate, error) {
for _, t := range templates {
- if err := t.loadContents(); err != nil {
- return nil, err
+ if t.contents == "" {
+ var in io.Reader
+ if t.name == "-" {
+ in = cfg.Stdin
+ }
+
+ b, err := t.loadContents(in)
+ if err != nil {
+ return nil, err
+ }
+
+ t.contents = string(b)
}
- if err := t.addTarget(cfg); err != nil {
- return nil, err
+ if t.target == nil {
+ out, err := openOutFile(cfg, t.targetPath, t.mode, t.modeOverride)
+ if err != nil {
+ return nil, err
+ }
+
+ t.target = out
}
}
@@ -225,11 +235,19 @@ func fileToTemplates(inFile, outFile string, mode os.FileMode, modeOverride bool
return tmpl, nil
}
+func stdout(cfg *config.Config) io.WriteCloser {
+ wc, ok := cfg.Stdout.(io.WriteCloser)
+ if ok {
+ return wc
+ }
+ return &iohelpers.NopCloser{Writer: cfg.Stdout}
+}
+
func openOutFile(cfg *config.Config, filename string, mode os.FileMode, modeOverride bool) (out io.WriteCloser, err error) {
if cfg.SuppressEmpty {
out = iohelpers.NewEmptySkipper(func() (io.WriteCloser, error) {
if filename == "-" {
- return Stdout, nil
+ return stdout(cfg), nil
}
return createOutFile(filename, mode, modeOverride)
})
@@ -237,7 +255,7 @@ func openOutFile(cfg *config.Config, filename string, mode os.FileMode, modeOver
}
if filename == "-" {
- return Stdout, nil
+ return stdout(cfg), nil
}
return createOutFile(filename, mode, modeOverride)
}
@@ -277,24 +295,3 @@ func createOutFile(filename string, mode os.FileMode, modeOverride bool) (out io
return out, err
}
-
-func readInput(filename string) (string, error) {
- var err error
- var inFile io.ReadCloser
- if filename == "-" {
- inFile = stdin
- } else {
- inFile, err = fs.OpenFile(filename, os.O_RDONLY, 0)
- if err != nil {
- return "", fmt.Errorf("failed to open %s: %w", filename, err)
- }
- // nolint: errcheck
- defer inFile.Close()
- }
- bytes, err := ioutil.ReadAll(inFile)
- if err != nil {
- err = fmt.Errorf("read failed for %s: %w", filename, err)
- return "", err
- }
- return string(bytes), nil
-}
diff --git a/template_test.go b/template_test.go
index dc0c7ae0..0c4f0e64 100644
--- a/template_test.go
+++ b/template_test.go
@@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"io"
- "io/ioutil"
"os"
"testing"
@@ -16,32 +15,6 @@ import (
"github.com/stretchr/testify/require"
)
-func TestReadInput(t *testing.T) {
- origfs := fs
- defer func() { fs = origfs }()
- fs = afero.NewMemMapFs()
- _ = fs.Mkdir("/tmp", 0777)
- f, _ := fs.Create("/tmp/foo")
- _, _ = f.Write([]byte("foo"))
-
- f, _ = fs.Create("/tmp/unreadable")
- _, _ = f.Write([]byte("foo"))
-
- actual, err := readInput("/tmp/foo")
- assert.NoError(t, err)
- assert.Equal(t, "foo", actual)
-
- defer func() { stdin = os.Stdin }()
- stdin = ioutil.NopCloser(bytes.NewBufferString("bar"))
-
- actual, err = readInput("-")
- assert.NoError(t, err)
- assert.Equal(t, "bar", actual)
-
- _, err = readInput("bogus")
- assert.Error(t, err)
-}
-
func TestOpenOutFile(t *testing.T) {
origfs := fs
defer func() { fs = origfs }()
@@ -59,12 +32,11 @@ func TestOpenOutFile(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, config.NormalizeFileMode(0644), i.Mode())
- defer func() { Stdout = os.Stdout }()
- Stdout = &iohelpers.NopCloser{Writer: &bytes.Buffer{}}
+ cfg.Stdout = &iohelpers.NopCloser{Writer: &bytes.Buffer{}}
f, err = openOutFile(cfg, "-", 0644, false)
assert.NoError(t, err)
- assert.Equal(t, Stdout, f)
+ assert.Equal(t, cfg.Stdout, f)
}
func TestLoadContents(t *testing.T) {
@@ -75,21 +47,9 @@ func TestLoadContents(t *testing.T) {
afero.WriteFile(fs, "foo", []byte("contents"), 0644)
tmpl := &tplate{name: "foo"}
- err := tmpl.loadContents()
- assert.NoError(t, err)
- assert.Equal(t, "contents", tmpl.contents)
-}
-
-func TestAddTarget(t *testing.T) {
- origfs := fs
- defer func() { fs = origfs }()
- fs = afero.NewMemMapFs()
-
- cfg := &config.Config{}
- tmpl := &tplate{name: "foo", targetPath: "/out/outfile"}
- err := tmpl.addTarget(cfg)
+ b, err := tmpl.loadContents(nil)
assert.NoError(t, err)
- assert.NotNil(t, tmpl.target)
+ assert.Equal(t, "contents", string(b))
}
func TestGatherTemplates(t *testing.T) {
@@ -102,21 +62,25 @@ func TestGatherTemplates(t *testing.T) {
afero.WriteFile(fs, "in/2", []byte("bar"), 0644)
afero.WriteFile(fs, "in/3", []byte("baz"), 0644)
- cfg := &config.Config{}
+ cfg := &config.Config{
+ Stdin: &bytes.Buffer{},
+ Stdout: &bytes.Buffer{},
+ }
cfg.ApplyDefaults()
templates, err := gatherTemplates(cfg, nil)
assert.NoError(t, err)
assert.Len(t, templates, 1)
cfg = &config.Config{
- Input: "foo",
+ Input: "foo",
+ Stdout: &iohelpers.NopCloser{Writer: &bytes.Buffer{}},
}
cfg.ApplyDefaults()
templates, err = gatherTemplates(cfg, nil)
assert.NoError(t, err)
assert.Len(t, templates, 1)
assert.Equal(t, "foo", templates[0].contents)
- assert.Equal(t, Stdout, templates[0].target)
+ assert.Equal(t, cfg.Stdout, templates[0].target)
templates, err = gatherTemplates(&config.Config{
Input: "foo",
@@ -140,14 +104,16 @@ func TestGatherTemplates(t *testing.T) {
assert.Equal(t, config.NormalizeFileMode(0644), info.Mode())
fs.Remove("out")
- templates, err = gatherTemplates(&config.Config{
+ cfg = &config.Config{
InputFiles: []string{"foo"},
OutputFiles: []string{"out"},
- }, nil)
+ Stdout: &iohelpers.NopCloser{Writer: &bytes.Buffer{}},
+ }
+ templates, err = gatherTemplates(cfg, nil)
assert.NoError(t, err)
assert.Len(t, templates, 1)
assert.Equal(t, "bar", templates[0].contents)
- assert.NotEqual(t, Stdout, templates[0].target)
+ assert.NotEqual(t, cfg.Stdout, templates[0].target)
assert.Equal(t, os.FileMode(0600), templates[0].mode)
_, err = templates[0].target.Write([]byte("hello world"))
@@ -158,15 +124,17 @@ func TestGatherTemplates(t *testing.T) {
assert.Equal(t, config.NormalizeFileMode(0600), info.Mode())
fs.Remove("out")
- templates, err = gatherTemplates(&config.Config{
+ cfg = &config.Config{
InputFiles: []string{"foo"},
OutputFiles: []string{"out"},
OutMode: "755",
- }, nil)
+ Stdout: &iohelpers.NopCloser{Writer: &bytes.Buffer{}},
+ }
+ templates, err = gatherTemplates(cfg, nil)
assert.NoError(t, err)
assert.Len(t, templates, 1)
assert.Equal(t, "bar", templates[0].contents)
- assert.NotEqual(t, Stdout, templates[0].target)
+ assert.NotEqual(t, cfg.Stdout, templates[0].target)
assert.Equal(t, config.NormalizeFileMode(0755), templates[0].mode)
_, err = templates[0].target.Write([]byte("hello world"))
@@ -199,7 +167,9 @@ func TestProcessTemplates(t *testing.T) {
afero.WriteFile(fs, "existing", []byte(""), config.NormalizeFileMode(0644))
- cfg := &config.Config{}
+ cfg := &config.Config{
+ Stdout: &iohelpers.NopCloser{Writer: &bytes.Buffer{}},
+ }
testdata := []struct {
templates []*tplate
contents []string
@@ -211,7 +181,7 @@ func TestProcessTemplates(t *testing.T) {
templates: []*tplate{{name: "<arg>", contents: "foo", targetPath: "-", mode: 0644}},
contents: []string{"foo"},
modes: []os.FileMode{0644},
- targets: []io.WriteCloser{Stdout},
+ targets: []io.WriteCloser{stdout(cfg)},
},
{
templates: []*tplate{{name: "<arg>", contents: "foo", targetPath: "out", mode: 0644}},
@@ -265,8 +235,8 @@ func TestProcessTemplates(t *testing.T) {
if len(in.targets) > 0 {
assert.Equal(t, in.targets[i], a.target)
}
- if current.targetPath != "-" {
- err = current.loadContents()
+ if current.targetPath != "-" && current.name != "<arg>" {
+ _, err = current.loadContents(nil)
assert.NoError(t, err)
n, err := current.target.Write([]byte("hello world"))