fn/framework support for reading from stdin in standalone

- speficy '-' to read from stdin when running standalone
This commit is contained in:
Phillip Wittrock
2020-11-21 09:15:31 -08:00
parent 7e01aec5a4
commit 82b2d83ede
4 changed files with 107 additions and 8 deletions

View File

@@ -95,11 +95,21 @@ type ResourceList struct {
// NoPrintError if set will prevent the error from being printed
NoPrintError bool
Command *cobra.Command
}
// Read reads the ResourceList
func (r *ResourceList) Read() error {
var in io.Reader = os.Stdin
var out io.Writer = os.Stdout
if r.Command != nil {
in = r.Command.InOrStdin()
out = r.Command.OutOrStdout()
}
// parse the inputs from the args
var readStdinStandalone bool
if len(r.Args) > 0 && !r.DisableStandalone {
// write the files as input
var buf bytes.Buffer
@@ -109,6 +119,12 @@ func (r *ResourceList) Read() error {
if i == 0 {
continue
}
if r.Args[i] == "-" {
// Read stdin separately
readStdinStandalone = true
continue
}
b, err := ioutil.ReadFile(r.Args[i])
if err != nil {
return errors.WrapPrefixf(err, "unable to read input file %s", r.Args[i])
@@ -120,10 +136,10 @@ func (r *ResourceList) Read() error {
}
if r.Reader == nil {
r.Reader = os.Stdin
r.Reader = in
}
if r.Writer == nil {
r.Writer = os.Stdout
r.Writer = out
}
r.rw = &kio.ByteReadWriter{
Reader: r.Reader,
@@ -157,6 +173,16 @@ func (r *ResourceList) Read() error {
return errors.Wrap(err)
}
if readStdinStandalone {
br := kio.ByteReader{Reader: in}
items, err := br.Read()
if err != nil {
return errors.Wrap(err)
}
// stdin always comes first so files are patches
r.Items = append(items, r.Items...)
}
// parse the functionConfig
return func() error {
if r.rw.FunctionConfig == nil {
@@ -223,8 +249,9 @@ func (r *ResourceList) Write() error {
// a Dockerfile to build the function into a container image
//
// go run main.go gen DIR/
func Command(resourceList *ResourceList, function Function) cobra.Command {
func Command(resourceList *ResourceList, function Function) *cobra.Command {
cmd := cobra.Command{}
resourceList.Command = &cmd
AddGenerateDockerfile(&cmd)
var printStack bool
cmd.RunE = func(cmd *cobra.Command, args []string) error {
@@ -242,7 +269,7 @@ func Command(resourceList *ResourceList, function Function) cobra.Command {
cmd.Args = cobra.MinimumNArgs(0)
cmd.SilenceErrors = true
cmd.SilenceUsage = true
return cmd
return &cmd
}
// TemplateCommand provides a cobra command to invoke a template
@@ -310,7 +337,7 @@ func (tc TemplateCommand) doTemplate(t *template.Template, rl *ResourceList) err
}
// GetCommand returns a new cobra command
func (tc TemplateCommand) GetCommand() cobra.Command {
func (tc TemplateCommand) GetCommand() *cobra.Command {
rl := ResourceList{
FunctionConfig: tc.API,
NoPrintError: true,

View File

@@ -4,13 +4,16 @@
package framework_test
import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"sigs.k8s.io/kustomize/kyaml/fn/framework"
"sigs.k8s.io/kustomize/kyaml/fn/framework/frameworktestutil"
"sigs.k8s.io/kustomize/kyaml/testutil"
@@ -66,7 +69,7 @@ func TestCommand_standalone(t *testing.T) {
var config api
resourceList := &framework.ResourceList{FunctionConfig: &config}
cmdFn := func() cobra.Command {
cmdFn := func() *cobra.Command {
return framework.Command(resourceList, func() error {
resourceList.Items = append(resourceList.Items, yaml.MustParse(`
apiVersion: apps/v1
@@ -90,3 +93,72 @@ metadata:
frameworktestutil.ResultsChecker{Command: cmdFn}.Assert(t)
}
func TestCommand_standalonestdin(t *testing.T) {
// TODO: make this test pass on windows -- currently failure seems spurious
testutil.SkipWindows(t)
type api = struct {
A string `json:"a" yaml:"a"`
}
var config api
resourceList := &framework.ResourceList{FunctionConfig: &config}
cmd := framework.Command(resourceList, func() error {
resourceList.Items = append(resourceList.Items, yaml.MustParse(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: bar2
namespace: default
annotations:
foo: bar2
`))
for i := range resourceList.Items {
err := resourceList.Items[i].PipeE(yaml.SetAnnotation("a", config.A))
if err != nil {
return err
}
}
return nil
})
cmd.SetIn(bytes.NewBufferString(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: bar1
namespace: default
annotations:
foo: bar1
spec:
replicas: 1
`))
var out bytes.Buffer
cmd.SetOut(&out)
cmd.SetArgs([]string{filepath.Join("testdata", "command", "config.yaml"), "-"})
require.NoError(t, cmd.Execute())
require.Equal(t, strings.TrimSpace(`
apiVersion: apps/v1
kind: Deployment
metadata:
name: bar1
namespace: default
annotations:
foo: bar1
a: 'b'
spec:
replicas: 1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: bar2
namespace: default
annotations:
foo: bar2
a: 'b'
`), strings.TrimSpace(out.String()))
}

View File

@@ -46,7 +46,7 @@ type ResultsChecker struct {
ExpectedErrorFilename string
// Command provides the function to run.
Command func() cobra.Command
Command func() *cobra.Command
}
// Assert asserts the results for functions

View File

@@ -21,7 +21,7 @@ func TestPatchTemplate(t *testing.T) {
// TODO: make this test pass on windows -- current failure seems spurious
testutil.SkipWindows(t)
cmdFn := func() cobra.Command {
cmdFn := func() *cobra.Command {
type api struct {
Selector framework.Selector `json:"selector" yaml:"selector"`
A string `json:"a" yaml:"a"`