mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-12 01:14:22 +00:00
kyaml/rnfn: support explicit fn list and reading from an io.Reader
- Support specifying an io.Reader as Input. Use this instead of Path for reading Resources. - Default io.Writer to os.Stdout if no Path is specified - Default io.Reader to os.Stdin if no Path is specified - Support specifying an explicit list of Functions. If specified, use these in place of reading from the Input or Directory source by default.
This commit is contained in:
@@ -5,6 +5,7 @@ package runfn
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
@@ -28,12 +29,21 @@ type RunFns struct {
|
||||
// FunctionPaths Paths allows functions to be specified outside the configuration
|
||||
// directory.
|
||||
// Functions provided on FunctionPaths are globally scoped.
|
||||
// If FunctionPaths length is > 0, then NoFunctionsFromInput defaults to true
|
||||
FunctionPaths []string
|
||||
|
||||
// Functions is an explicit list of functions to run against the input.
|
||||
// Functions provided on Functions are globally scoped.
|
||||
// If Functions length is > 0, then NoFunctionsFromInput defaults to true
|
||||
Functions []*yaml.RNode
|
||||
|
||||
// GlobalScope if true, functions read from input will be scoped globally rather
|
||||
// than only to Resources under their subdirs.
|
||||
GlobalScope bool
|
||||
|
||||
// Input can be set to read the Resources from Input rather than from a directory
|
||||
Input io.Reader
|
||||
|
||||
// Output can be set to write the result to Output rather than back to the directory
|
||||
Output io.Writer
|
||||
|
||||
@@ -56,51 +66,83 @@ func (r RunFns) Execute() error {
|
||||
|
||||
// default the containerFilterProvider if it hasn't been override. Split out for testing.
|
||||
(&r).init()
|
||||
|
||||
fltrs, err := r.getFilters()
|
||||
nodes, fltrs, output, err := r.getNodesAndFilters()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return r.runFunctions(fltrs)
|
||||
return r.runFunctions(nodes, output, fltrs)
|
||||
}
|
||||
|
||||
func (r RunFns) getFilters() ([]kio.Filter, error) {
|
||||
func (r RunFns) getNodesAndFilters() (
|
||||
*kio.PackageBuffer, []kio.Filter, *kio.LocalPackageReadWriter, error) {
|
||||
// Read Resources from Directory or Input
|
||||
buff := &kio.PackageBuffer{}
|
||||
p := kio.Pipeline{Outputs: []kio.Writer{buff}}
|
||||
// save the output dir because we will need it to write back
|
||||
// the same one for reading must be used for writing if deleting Resources
|
||||
var outputPkg *kio.LocalPackageReadWriter
|
||||
if r.Path != "" {
|
||||
outputPkg = &kio.LocalPackageReadWriter{PackagePath: r.Path}
|
||||
}
|
||||
|
||||
if r.Input == nil {
|
||||
p.Inputs = []kio.Reader{outputPkg}
|
||||
} else {
|
||||
p.Inputs = []kio.Reader{&kio.ByteReader{Reader: r.Input}}
|
||||
}
|
||||
if err := p.Execute(); err != nil {
|
||||
return nil, nil, outputPkg, err
|
||||
}
|
||||
|
||||
fltrs, err := r.getFilters(buff.Nodes)
|
||||
if err != nil {
|
||||
return nil, nil, outputPkg, err
|
||||
}
|
||||
return buff, fltrs, outputPkg, nil
|
||||
}
|
||||
|
||||
func (r RunFns) getFilters(nodes []*yaml.RNode) ([]kio.Filter, error) {
|
||||
var fltrs []kio.Filter
|
||||
|
||||
// implicit filters from the input Resources
|
||||
f, err := r.getFunctionsFromInput()
|
||||
f, err := r.getFunctionsFromInput(nodes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fltrs = append(fltrs, f...)
|
||||
|
||||
// explicit filters from a list of directories
|
||||
f, err = r.getFunctionsFromDirList()
|
||||
f, err = r.getFunctionsFromFunctionPaths()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fltrs = append(fltrs, f...)
|
||||
|
||||
// explicit filters from a list of directories
|
||||
f = r.getFunctionsFromFunctions()
|
||||
fltrs = append(fltrs, f...)
|
||||
|
||||
return fltrs, nil
|
||||
}
|
||||
|
||||
// runFunctions runs the fltrs against the input
|
||||
func (r RunFns) runFunctions(fltrs []kio.Filter) error {
|
||||
pkgIO := &kio.LocalPackageReadWriter{PackagePath: r.Path}
|
||||
inputs := []kio.Reader{pkgIO}
|
||||
// runFunctions runs the fltrs against the input and writes to either r.Output or output
|
||||
func (r RunFns) runFunctions(
|
||||
input kio.Reader, output kio.Writer, fltrs []kio.Filter) error {
|
||||
// use the previously read Resources as input
|
||||
var outputs []kio.Writer
|
||||
if r.Output == nil {
|
||||
// write back to the package
|
||||
outputs = append(outputs, pkgIO)
|
||||
outputs = append(outputs, output)
|
||||
} else {
|
||||
// write to the output instead of the directory
|
||||
// write to the output instead of the directory if r.Output is specified or
|
||||
// the output is nil (reading from Input)
|
||||
outputs = append(outputs, kio.ByteWriter{Writer: r.Output})
|
||||
}
|
||||
return kio.Pipeline{Inputs: inputs, Filters: fltrs, Outputs: outputs}.Execute()
|
||||
return kio.Pipeline{Inputs: []kio.Reader{input}, Filters: fltrs, Outputs: outputs}.Execute()
|
||||
}
|
||||
|
||||
// getFunctionsFromInput scans the input for functions and runs them
|
||||
func (r RunFns) getFunctionsFromInput() ([]kio.Filter, error) {
|
||||
func (r RunFns) getFunctionsFromInput(nodes []*yaml.RNode) ([]kio.Filter, error) {
|
||||
if *r.NoFunctionsFromInput {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -108,7 +150,7 @@ func (r RunFns) getFunctionsFromInput() ([]kio.Filter, error) {
|
||||
var fltrs []kio.Filter
|
||||
buff := &kio.PackageBuffer{}
|
||||
err := kio.Pipeline{
|
||||
Inputs: []kio.Reader{kio.LocalPackageReader{PackagePath: r.Path}},
|
||||
Inputs: []kio.Reader{&kio.PackageBuffer{Nodes: nodes}},
|
||||
Filters: []kio.Filter{&filters.IsReconcilerFilter{}},
|
||||
Outputs: []kio.Writer{buff},
|
||||
}.Execute()
|
||||
@@ -124,9 +166,9 @@ func (r RunFns) getFunctionsFromInput() ([]kio.Filter, error) {
|
||||
return fltrs, nil
|
||||
}
|
||||
|
||||
// getFunctionsFromDirList returns the set of functions read from r.FunctionPaths
|
||||
// getFunctionsFromFunctionPaths returns the set of functions read from r.FunctionPaths
|
||||
// as a slice of Filters
|
||||
func (r RunFns) getFunctionsFromDirList() ([]kio.Filter, error) {
|
||||
func (r RunFns) getFunctionsFromFunctionPaths() ([]kio.Filter, error) {
|
||||
var fltrs []kio.Filter
|
||||
buff := &kio.PackageBuffer{}
|
||||
for i := range r.FunctionPaths {
|
||||
@@ -144,7 +186,7 @@ func (r RunFns) getFunctionsFromDirList() ([]kio.Filter, error) {
|
||||
c := r.containerFilterProvider(img, path, api)
|
||||
cf, ok := c.(*filters.ContainerFilter)
|
||||
if ok {
|
||||
// functions provided on FunctionPaths are globally scoped
|
||||
// functions provided by FunctionPaths are globally scoped
|
||||
cf.GlobalScope = true
|
||||
}
|
||||
fltrs = append(fltrs, c)
|
||||
@@ -152,6 +194,24 @@ func (r RunFns) getFunctionsFromDirList() ([]kio.Filter, error) {
|
||||
return fltrs, nil
|
||||
}
|
||||
|
||||
// getFunctionsFromFunctions returns the set of explicitly provided functions as
|
||||
// Filters
|
||||
func (r RunFns) getFunctionsFromFunctions() []kio.Filter {
|
||||
var fltrs []kio.Filter
|
||||
for i := range r.Functions {
|
||||
api := r.Functions[i]
|
||||
img, path := filters.GetContainerName(api)
|
||||
c := r.containerFilterProvider(img, path, api)
|
||||
cf, ok := c.(*filters.ContainerFilter)
|
||||
if ok {
|
||||
// functions provided by Functions are globally scoped
|
||||
cf.GlobalScope = true
|
||||
}
|
||||
fltrs = append(fltrs, c)
|
||||
}
|
||||
return fltrs
|
||||
}
|
||||
|
||||
// sortFns sorts functions so that functions with the longest paths come first
|
||||
func sortFns(buff *kio.PackageBuffer) {
|
||||
// sort the nodes so that we traverse them depth first
|
||||
@@ -201,10 +261,21 @@ func sortFns(buff *kio.PackageBuffer) {
|
||||
// init initializes the RunFns with a containerFilterProvider.
|
||||
func (r *RunFns) init() {
|
||||
if r.NoFunctionsFromInput == nil {
|
||||
nfn := len(r.FunctionPaths) > 0
|
||||
// default no functions from input if any function sources are explicitly provided
|
||||
nfn := len(r.FunctionPaths) > 0 || len(r.Functions) > 0
|
||||
r.NoFunctionsFromInput = &nfn
|
||||
}
|
||||
|
||||
// if no path is specified, default reading from stdin and writing to stdout
|
||||
if r.Path == "" {
|
||||
if r.Output == nil {
|
||||
r.Output = os.Stdout
|
||||
}
|
||||
if r.Input == nil {
|
||||
r.Input = os.Stdin
|
||||
}
|
||||
}
|
||||
|
||||
// if containerFilterProvider hasn't been set, use the default
|
||||
if r.containerFilterProvider == nil {
|
||||
r.containerFilterProvider = func(image, path string, api *yaml.RNode) kio.Filter {
|
||||
|
||||
Reference in New Issue
Block a user