mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-12 01:14:22 +00:00
Cat with subpackages
This commit is contained in:
@@ -5,9 +5,11 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"sigs.k8s.io/kustomize/cmd/config/ext"
|
||||||
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
|
||||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
@@ -19,15 +21,14 @@ import (
|
|||||||
func GetCatRunner(name string) *CatRunner {
|
func GetCatRunner(name string) *CatRunner {
|
||||||
r := &CatRunner{}
|
r := &CatRunner{}
|
||||||
c := &cobra.Command{
|
c := &cobra.Command{
|
||||||
Use: "cat DIR...",
|
Use: "cat DIR",
|
||||||
Short: commands.CatShort,
|
Short: commands.CatShort,
|
||||||
Long: commands.CatLong,
|
Long: commands.CatLong,
|
||||||
Example: commands.CatExamples,
|
Example: commands.CatExamples,
|
||||||
RunE: r.runE,
|
RunE: r.runE,
|
||||||
|
Args: cobra.MaximumNArgs(1),
|
||||||
}
|
}
|
||||||
fixDocs(name, c)
|
fixDocs(name, c)
|
||||||
c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
|
|
||||||
"also print resources from subpackages.")
|
|
||||||
c.Flags().BoolVar(&r.Format, "format", true,
|
c.Flags().BoolVar(&r.Format, "format", true,
|
||||||
"format resource config yaml before printing.")
|
"format resource config yaml before printing.")
|
||||||
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", false,
|
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.")
|
"if true, exclude non-local-config in the output.")
|
||||||
c.Flags().StringVar(&r.OutputDest, "dest", "",
|
c.Flags().StringVar(&r.OutputDest, "dest", "",
|
||||||
"if specified, write output to a file rather than stdout")
|
"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
|
r.Command = c
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
@@ -59,7 +62,6 @@ func CatCommand(name string) *cobra.Command {
|
|||||||
|
|
||||||
// CatRunner contains the run function
|
// CatRunner contains the run function
|
||||||
type CatRunner struct {
|
type CatRunner struct {
|
||||||
IncludeSubpackages bool
|
|
||||||
Format bool
|
Format bool
|
||||||
KeepAnnotations bool
|
KeepAnnotations bool
|
||||||
WrapKind string
|
WrapKind string
|
||||||
@@ -71,56 +73,101 @@ type CatRunner struct {
|
|||||||
IncludeLocal bool
|
IncludeLocal bool
|
||||||
ExcludeNonLocal bool
|
ExcludeNonLocal bool
|
||||||
Command *cobra.Command
|
Command *cobra.Command
|
||||||
|
RecurseSubPackages bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *CatRunner) runE(c *cobra.Command, args []string) error {
|
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
|
var functionConfig *yaml.RNode
|
||||||
if r.FunctionConfig != "" {
|
if r.FunctionConfig != "" {
|
||||||
configs, err := kio.LocalPackageReader{PackagePath: r.FunctionConfig,
|
configs, err := kio.LocalPackageReader{PackagePath: r.FunctionConfig,
|
||||||
OmitReaderAnnotations: !r.KeepAnnotations}.Read()
|
OmitReaderAnnotations: !r.KeepAnnotations}.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return outputs, err
|
||||||
}
|
}
|
||||||
if len(configs) != 1 {
|
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]
|
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
|
// remove this annotation explicitly, the ByteWriter won't clear it by
|
||||||
// default because it doesn't set it
|
// default because it doesn't set it
|
||||||
clear := []string{"config.kubernetes.io/path"}
|
clear := []string{"config.kubernetes.io/path"}
|
||||||
@@ -128,9 +175,8 @@ func (r *CatRunner) runE(c *cobra.Command, args []string) error {
|
|||||||
clear = nil
|
clear = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var outputs []kio.Writer
|
|
||||||
outputs = append(outputs, kio.ByteWriter{
|
outputs = append(outputs, kio.ByteWriter{
|
||||||
Writer: out,
|
Writer: w,
|
||||||
KeepReaderAnnotations: r.KeepAnnotations,
|
KeepReaderAnnotations: r.KeepAnnotations,
|
||||||
WrappingKind: r.WrapKind,
|
WrappingKind: r.WrapKind,
|
||||||
WrappingAPIVersion: r.WrapApiVersion,
|
WrappingAPIVersion: r.WrapApiVersion,
|
||||||
@@ -139,5 +185,5 @@ func (r *CatRunner) runE(c *cobra.Command, args []string) error {
|
|||||||
ClearAnnotations: clear,
|
ClearAnnotations: clear,
|
||||||
})
|
})
|
||||||
|
|
||||||
return handleError(c, kio.Pipeline{Inputs: inputs, Filters: fltr, Outputs: outputs}.Execute())
|
return outputs, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,13 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"sigs.k8s.io/kustomize/cmd/config/internal/commands"
|
"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
|
// TODO(pwittrock): write tests for reading / writing ResourceLists
|
||||||
@@ -112,6 +115,7 @@ metadata:
|
|||||||
app: nginx
|
app: nginx
|
||||||
spec:
|
spec:
|
||||||
replicas: 3
|
replicas: 3
|
||||||
|
---
|
||||||
`, b.String()) {
|
`, b.String()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -223,6 +227,7 @@ metadata:
|
|||||||
app: nginx
|
app: nginx
|
||||||
spec:
|
spec:
|
||||||
replicas: 3
|
replicas: 3
|
||||||
|
---
|
||||||
`, b.String()) {
|
`, b.String()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -305,6 +310,7 @@ metadata:
|
|||||||
image: gcr.io/example/reconciler:v1
|
image: gcr.io/example/reconciler:v1
|
||||||
spec:
|
spec:
|
||||||
replicas: 3
|
replicas: 3
|
||||||
|
---
|
||||||
`, b.String()) {
|
`, b.String()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -420,6 +426,7 @@ metadata:
|
|||||||
app: nginx
|
app: nginx
|
||||||
spec:
|
spec:
|
||||||
replicas: 3
|
replicas: 3
|
||||||
|
---
|
||||||
`, string(actual)) {
|
`, string(actual)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -536,7 +543,138 @@ metadata:
|
|||||||
app: nginx
|
app: nginx
|
||||||
spec:
|
spec:
|
||||||
replicas: 3
|
replicas: 3
|
||||||
|
---
|
||||||
`, string(actual)) {
|
`, string(actual)) {
|
||||||
return
|
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