From 43ab7a8e71cf7b46d2c35ab1a227170c3af48319 Mon Sep 17 00:00:00 2001 From: Phani Teja Marupaka Date: Tue, 8 Sep 2020 16:28:01 -0700 Subject: [PATCH] Count with Subpackages --- cmd/config/internal/commands/count.go | 74 +++++++++++++++------ cmd/config/internal/commands/count_test.go | 76 +++++++++++++++++++++- 2 files changed, 129 insertions(+), 21 deletions(-) diff --git a/cmd/config/internal/commands/count.go b/cmd/config/internal/commands/count.go index 8539d2de44..085195adfe 100644 --- a/cmd/config/internal/commands/count.go +++ b/cmd/config/internal/commands/count.go @@ -5,9 +5,11 @@ package commands import ( "fmt" + "io" "sort" "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/kio" "sigs.k8s.io/kustomize/kyaml/sets" @@ -17,18 +19,18 @@ import ( func GetCountRunner(name string) *CountRunner { r := &CountRunner{} c := &cobra.Command{ - Use: "count DIR...", + Use: "count [DIR]", + Args: cobra.MaximumNArgs(1), Short: commands.CountShort, Long: commands.CountLong, Example: commands.CountExamples, RunE: r.runE, } fixDocs(name, c) - c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true, - "also print resources from subpackages.") c.Flags().BoolVar(&r.Kind, "kind", true, "count resources by kind.") - + c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true, + "prints count of resources recursively in all the nested subpackages") r.Command = c return r } @@ -42,20 +44,57 @@ type CountRunner struct { IncludeSubpackages bool Kind bool Command *cobra.Command + RecurseSubPackages bool } func (r *CountRunner) runE(c *cobra.Command, args []string) error { - var inputs []kio.Reader - for _, a := range args { - inputs = append(inputs, kio.LocalPackageReader{ - PackagePath: a, - IncludeSubpackages: r.IncludeSubpackages, - }) + if len(args) == 0 { + input := &kio.ByteReader{Reader: c.InOrStdin()} + + return handleError(c, kio.Pipeline{ + Inputs: []kio.Reader{input}, + Outputs: r.out(c.OutOrStdout()), + }.Execute()) + } + + e := executeCmdOnPkgs{ + writer: c.OutOrStdout(), + needOpenAPI: false, + recurseSubPackages: r.RecurseSubPackages, + cmdRunner: r, + rootPkgPath: args[0], + } + + return e.execute() +} + +func (r *CountRunner) executeCmd(w io.Writer, pkgPath string) error { + openAPIFileName, err := ext.OpenAPIFileName() + if err != nil { + return err } - if len(inputs) == 0 { - inputs = append(inputs, &kio.ByteReader{Reader: c.InOrStdin()}) + + input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: openAPIFileName} + + fmt.Fprintf(w, "%q:\n", pkgPath) + err = kio.Pipeline{ + Inputs: []kio.Reader{input}, + Outputs: r.out(w), + }.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) + } } + return nil +} +func (r *CountRunner) out(w io.Writer) []kio.Writer { var out []kio.Writer if r.Kind { out = append(out, kio.WriterFunc(func(nodes []*yaml.RNode) error { @@ -69,20 +108,15 @@ func (r *CountRunner) runE(c *cobra.Command, args []string) error { order := k.List() sort.Strings(order) for _, k := range order { - fmt.Fprintf(c.OutOrStdout(), "%s: %d\n", k, count[k]) + fmt.Fprintf(w, "%s: %d\n", k, count[k]) } - return nil })) - } else { out = append(out, kio.WriterFunc(func(nodes []*yaml.RNode) error { - fmt.Fprintf(c.OutOrStdout(), "%d\n", len(nodes)) + fmt.Fprintf(w, "%d\n", len(nodes)) return nil })) } - return handleError(c, kio.Pipeline{ - Inputs: inputs, - Outputs: out, - }.Execute()) + return out } diff --git a/cmd/config/internal/commands/count_test.go b/cmd/config/internal/commands/count_test.go index 3c2941a8e8..622aa525e5 100644 --- a/cmd/config/internal/commands/count_test.go +++ b/cmd/config/internal/commands/count_test.go @@ -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" ) func TestCountCommand_files(t *testing.T) { @@ -67,7 +70,78 @@ spec: return } - if !assert.Equal(t, "Deployment: 2\nService: 1\n", b.String()) { + if !assert.Contains(t, b.String(), "Deployment: 2\nService: 1\n") { return } } + +func TestCountSubPackages(t *testing.T) { + var tests = []struct { + name string + dataset string + packagePath string + args []string + expected string + }{ + { + name: "count-recurse-subpackages", + dataset: "dataset-without-setters", + expected: ` +"${baseDir}/mysql": +Deployment: 1 +"${baseDir}/mysql/storage": +Deployment: 1 +`, + }, + { + name: "count-top-level-pkg-no-recurse-subpackages", + dataset: "dataset-without-setters", + args: []string{"-R=false"}, + packagePath: "mysql", + expected: `"${baseDir}/mysql": +Deployment: 1`, + }, + { + name: "count-nested-pkg-no-recurse-subpackages", + dataset: "dataset-without-setters", + packagePath: "mysql/storage", + args: []string{"-R=false"}, + expected: `"${baseDir}/mysql/storage": +Deployment: 1`, + }, + } + 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.GetCountRunner("") + 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() + } + }) + } +}