mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-10 08:20:59 +00:00
Merge pull request #2959 from phanimarupaka/CatWithSubpkgs
Cat with subpackages
This commit is contained in:
@@ -5,9 +5,11 @@ package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sigs.k8s.io/kustomize/cmd/config/ext"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
@@ -19,15 +21,14 @@ import (
|
||||
func GetCatRunner(name string) *CatRunner {
|
||||
r := &CatRunner{}
|
||||
c := &cobra.Command{
|
||||
Use: "cat DIR...",
|
||||
Use: "cat DIR",
|
||||
Short: commands.CatShort,
|
||||
Long: commands.CatLong,
|
||||
Example: commands.CatExamples,
|
||||
RunE: r.runE,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
}
|
||||
fixDocs(name, c)
|
||||
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
|
||||
"also print resources from subpackages.")
|
||||
c.Flags().BoolVar(&r.Format, "format", true,
|
||||
"format resource config yaml before printing.")
|
||||
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", false,
|
||||
@@ -49,6 +50,8 @@ func GetCatRunner(name string) *CatRunner {
|
||||
"if true, exclude non-local-config in the output.")
|
||||
c.Flags().StringVar(&r.OutputDest, "dest", "",
|
||||
"if specified, write output to a file rather than stdout")
|
||||
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true,
|
||||
"print resources recursively in all the nested subpackages")
|
||||
r.Command = c
|
||||
return r
|
||||
}
|
||||
@@ -59,7 +62,6 @@ func CatCommand(name string) *cobra.Command {
|
||||
|
||||
// CatRunner contains the run function
|
||||
type CatRunner struct {
|
||||
IncludeSubpackages bool
|
||||
Format bool
|
||||
KeepAnnotations bool
|
||||
WrapKind string
|
||||
@@ -71,56 +73,101 @@ type CatRunner struct {
|
||||
IncludeLocal bool
|
||||
ExcludeNonLocal bool
|
||||
Command *cobra.Command
|
||||
RecurseSubPackages bool
|
||||
}
|
||||
|
||||
func (r *CatRunner) runE(c *cobra.Command, args []string) error {
|
||||
// if there is a function-config specified, emit it
|
||||
var writer = c.OutOrStdout()
|
||||
if r.OutputDest != "" {
|
||||
o, err := os.Create(r.OutputDest)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
defer o.Close()
|
||||
writer = o
|
||||
}
|
||||
if len(args) == 0 {
|
||||
input := &kio.ByteReader{Reader: c.InOrStdin()}
|
||||
// if there is a function-config specified, emit it
|
||||
outputs, err := r.out(writer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return handleError(c, kio.Pipeline{Inputs: []kio.Reader{input}, Filters: r.catFilters(), Outputs: outputs}.Execute())
|
||||
}
|
||||
|
||||
e := executeCmdOnPkgs{
|
||||
writer: writer,
|
||||
needOpenAPI: false,
|
||||
recurseSubPackages: r.RecurseSubPackages,
|
||||
cmdRunner: r,
|
||||
rootPkgPath: args[0],
|
||||
}
|
||||
|
||||
return e.execute()
|
||||
}
|
||||
|
||||
func (r *CatRunner) executeCmd(w io.Writer, pkgPath string) error {
|
||||
openAPIFileName, err := ext.OpenAPIFileName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: openAPIFileName}
|
||||
outputs, err := r.out(w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = kio.Pipeline{
|
||||
Inputs: []kio.Reader{input},
|
||||
Filters: r.catFilters(),
|
||||
Outputs: outputs,
|
||||
}.Execute()
|
||||
|
||||
if err != nil {
|
||||
// return err if there is only package
|
||||
if !r.RecurseSubPackages {
|
||||
return err
|
||||
} else {
|
||||
// print error message and continue if there are multiple packages to annotate
|
||||
fmt.Fprintf(w, "%s in package %q\n", err.Error(), pkgPath)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(w, "---\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *CatRunner) catFilters() []kio.Filter {
|
||||
var fltrs []kio.Filter
|
||||
// don't include reconcilers
|
||||
fltrs = append(fltrs, &filters.IsLocalConfig{
|
||||
IncludeLocalConfig: r.IncludeLocal,
|
||||
ExcludeNonLocalConfig: r.ExcludeNonLocal,
|
||||
})
|
||||
if r.Format {
|
||||
fltrs = append(fltrs, filters.FormatFilter{})
|
||||
}
|
||||
if r.StripComments {
|
||||
fltrs = append(fltrs, filters.StripCommentsFilter{})
|
||||
}
|
||||
return fltrs
|
||||
}
|
||||
|
||||
func (r *CatRunner) out(w io.Writer) ([]kio.Writer, error) {
|
||||
var outputs []kio.Writer
|
||||
var functionConfig *yaml.RNode
|
||||
if r.FunctionConfig != "" {
|
||||
configs, err := kio.LocalPackageReader{PackagePath: r.FunctionConfig,
|
||||
OmitReaderAnnotations: !r.KeepAnnotations}.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
return outputs, err
|
||||
}
|
||||
if len(configs) != 1 {
|
||||
return fmt.Errorf("expected exactly 1 functionConfig, found %d", len(configs))
|
||||
return outputs, fmt.Errorf("expected exactly 1 functionConfig, found %d", len(configs))
|
||||
}
|
||||
functionConfig = configs[0]
|
||||
}
|
||||
|
||||
var inputs []kio.Reader
|
||||
for _, a := range args {
|
||||
inputs = append(inputs, kio.LocalPackageReader{
|
||||
PackagePath: a,
|
||||
IncludeSubpackages: r.IncludeSubpackages,
|
||||
})
|
||||
}
|
||||
if len(inputs) == 0 {
|
||||
inputs = append(inputs, &kio.ByteReader{Reader: c.InOrStdin()})
|
||||
}
|
||||
var fltr []kio.Filter
|
||||
// don't include reconcilers
|
||||
fltr = append(fltr, &filters.IsLocalConfig{
|
||||
IncludeLocalConfig: r.IncludeLocal,
|
||||
ExcludeNonLocalConfig: r.ExcludeNonLocal,
|
||||
})
|
||||
if r.Format {
|
||||
fltr = append(fltr, filters.FormatFilter{})
|
||||
}
|
||||
if r.StripComments {
|
||||
fltr = append(fltr, filters.StripCommentsFilter{})
|
||||
}
|
||||
|
||||
var out = c.OutOrStdout()
|
||||
if r.OutputDest != "" {
|
||||
o, err := os.Create(r.OutputDest)
|
||||
if err != nil {
|
||||
return handleError(c, errors.Wrap(err))
|
||||
}
|
||||
defer o.Close()
|
||||
out = o
|
||||
}
|
||||
|
||||
// remove this annotation explicitly, the ByteWriter won't clear it by
|
||||
// default because it doesn't set it
|
||||
clear := []string{"config.kubernetes.io/path"}
|
||||
@@ -128,9 +175,8 @@ func (r *CatRunner) runE(c *cobra.Command, args []string) error {
|
||||
clear = nil
|
||||
}
|
||||
|
||||
var outputs []kio.Writer
|
||||
outputs = append(outputs, kio.ByteWriter{
|
||||
Writer: out,
|
||||
Writer: w,
|
||||
KeepReaderAnnotations: r.KeepAnnotations,
|
||||
WrappingKind: r.WrapKind,
|
||||
WrappingAPIVersion: r.WrapApiVersion,
|
||||
@@ -139,5 +185,5 @@ func (r *CatRunner) runE(c *cobra.Command, args []string) error {
|
||||
ClearAnnotations: clear,
|
||||
})
|
||||
|
||||
return handleError(c, kio.Pipeline{Inputs: inputs, Filters: fltr, Outputs: outputs}.Execute())
|
||||
return outputs, nil
|
||||
}
|
||||
|
||||
@@ -8,10 +8,13 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
|
||||
"sigs.k8s.io/kustomize/kyaml/copyutil"
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||
)
|
||||
|
||||
// TODO(pwittrock): write tests for reading / writing ResourceLists
|
||||
@@ -112,6 +115,7 @@ metadata:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 3
|
||||
---
|
||||
`, b.String()) {
|
||||
return
|
||||
}
|
||||
@@ -223,6 +227,7 @@ metadata:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 3
|
||||
---
|
||||
`, b.String()) {
|
||||
return
|
||||
}
|
||||
@@ -305,6 +310,7 @@ metadata:
|
||||
image: gcr.io/example/reconciler:v1
|
||||
spec:
|
||||
replicas: 3
|
||||
---
|
||||
`, b.String()) {
|
||||
return
|
||||
}
|
||||
@@ -420,6 +426,7 @@ metadata:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 3
|
||||
---
|
||||
`, string(actual)) {
|
||||
return
|
||||
}
|
||||
@@ -536,7 +543,138 @@ metadata:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 3
|
||||
---
|
||||
`, string(actual)) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestCatSubPackages(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
dataset string
|
||||
packagePath string
|
||||
args []string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "cat-recurse-subpackages",
|
||||
dataset: "dataset-without-setters",
|
||||
expected: `
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mysql-deployment
|
||||
namespace: myspace
|
||||
spec:
|
||||
replicas: 3
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: mysql
|
||||
image: mysql:1.7.9
|
||||
---
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: storage-deployment
|
||||
namespace: myspace
|
||||
spec:
|
||||
replicas: 4
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: storage
|
||||
image: storage:1.7.7
|
||||
---
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "cat-top-level-pkg-no-recurse-subpackages",
|
||||
dataset: "dataset-without-setters",
|
||||
args: []string{"-R=false"},
|
||||
packagePath: "mysql",
|
||||
expected: `
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mysql-deployment
|
||||
namespace: myspace
|
||||
spec:
|
||||
replicas: 3
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: mysql
|
||||
image: mysql:1.7.9
|
||||
---
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "cat-nested-pkg-no-recurse-subpackages",
|
||||
dataset: "dataset-without-setters",
|
||||
packagePath: "mysql/storage",
|
||||
args: []string{"-R=false"},
|
||||
expected: `
|
||||
# Copyright 2019 The Kubernetes Authors.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: storage-deployment
|
||||
namespace: myspace
|
||||
spec:
|
||||
replicas: 4
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: storage
|
||||
image: storage:1.7.7
|
||||
---`,
|
||||
},
|
||||
}
|
||||
for i := range tests {
|
||||
test := tests[i]
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
// reset the openAPI afterward
|
||||
openapi.ResetOpenAPI()
|
||||
defer openapi.ResetOpenAPI()
|
||||
sourceDir := filepath.Join("test", "testdata", test.dataset)
|
||||
baseDir, err := ioutil.TempDir("", "")
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
copyutil.CopyDir(sourceDir, baseDir)
|
||||
defer os.RemoveAll(baseDir)
|
||||
runner := commands.GetCatRunner("")
|
||||
actual := &bytes.Buffer{}
|
||||
runner.Command.SetOut(actual)
|
||||
runner.Command.SetArgs(append([]string{filepath.Join(baseDir, test.packagePath)}, test.args...))
|
||||
err = runner.Command.Execute()
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// normalize path format for windows
|
||||
actualNormalized := strings.Replace(
|
||||
strings.Replace(actual.String(), "\\", "/", -1),
|
||||
"//", "/", -1)
|
||||
|
||||
expected := strings.Replace(test.expected, "${baseDir}", baseDir, -1)
|
||||
expectedNormalized := strings.Replace(expected, "\\", "/", -1)
|
||||
if !assert.Equal(t, strings.TrimSpace(expectedNormalized), strings.TrimSpace(actualNormalized)) {
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user