Refactor subpackages logic

This commit is contained in:
Phani Teja Marupaka
2020-09-04 17:58:41 -07:00
parent e7970d82a8
commit c4d937322f
6 changed files with 404 additions and 169 deletions

View File

@@ -6,6 +6,7 @@ package commands
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"path/filepath"
"strings"
@@ -16,8 +17,6 @@ import (
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/pathutil"
"sigs.k8s.io/kustomize/kyaml/setters"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
)
@@ -82,7 +81,7 @@ type CreateSetterRunner struct {
}
func (r *CreateSetterRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, r.set(c, args))
return handleError(c, r.createSetter(c, args))
}
func (r *CreateSetterRunner) preRunE(c *cobra.Command, args []string) error {
@@ -178,59 +177,18 @@ func (r *CreateSetterRunner) processSchema() error {
return nil
}
func (r *CreateSetterRunner) set(c *cobra.Command, args []string) error {
func (r *CreateSetterRunner) createSetter(c *cobra.Command, args []string) error {
if setterVersion == "v2" {
openAPIFileName, err := ext.OpenAPIFileName()
e := executeCmdOnPkgs{
needOpenAPI: true,
writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.CreateSetter.RecurseSubPackages,
cmdRunner: r,
}
err := e.execute()
if err != nil {
return err
}
r.CreateSetter.OpenAPIFileName = openAPIFileName
resourcePackagesPaths, err := pathutil.DirsWithFile(args[0], openAPIFileName, r.CreateSetter.RecurseSubPackages)
if err != nil {
return err
}
if len(resourcePackagesPaths) == 0 {
return errors.Errorf("unable to find %q in package %q", r.CreateSetter.OpenAPIFileName, args[0])
}
for _, resourcesPath := range resourcePackagesPaths {
r.CreateSetter = settersutil.SetterCreator{
Name: r.CreateSetter.Name,
SetBy: r.CreateSetter.SetBy,
Description: r.CreateSetter.Description,
Type: r.CreateSetter.Type,
Schema: r.CreateSetter.Schema,
FieldName: r.CreateSetter.FieldName,
FieldValue: r.CreateSetter.FieldValue,
Required: r.CreateSetter.Required,
RecurseSubPackages: r.CreateSetter.RecurseSubPackages,
OpenAPIFileName: openAPIFileName,
OpenAPIPath: filepath.Join(resourcesPath, openAPIFileName),
ResourcesPath: resourcesPath,
}
// Add schema present in openAPI file for current package
if err := openapi.AddSchemaFromFile(r.CreateSetter.OpenAPIPath); err != nil {
return err
}
err := r.CreateSetter.Create()
if err != nil {
// return err if there is only package
if len(resourcePackagesPaths) == 1 {
return err
} else {
// print error message and continue if there are multiple packages to set
fmt.Fprintf(c.OutOrStdout(), "%s in package %q\n\n", err.Error(), r.CreateSetter.ResourcesPath)
}
} else {
fmt.Fprintf(c.OutOrStdout(), "created setter %q in package %q\n\n", r.CreateSetter.Name, r.CreateSetter.ResourcesPath)
}
// Delete schema present in openAPI file for current package
if err := openapi.DeleteSchemaInFile(r.CreateSetter.OpenAPIPath); err != nil {
return err
}
return handleError(c, err)
}
return nil
}
@@ -246,6 +204,41 @@ func (r *CreateSetterRunner) set(c *cobra.Command, args []string) error {
return nil
}
func (r *CreateSetterRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
r.CreateSetter = settersutil.SetterCreator{
Name: r.CreateSetter.Name,
SetBy: r.CreateSetter.SetBy,
Description: r.CreateSetter.Description,
Type: r.CreateSetter.Type,
Schema: r.CreateSetter.Schema,
FieldName: r.CreateSetter.FieldName,
FieldValue: r.CreateSetter.FieldValue,
Required: r.CreateSetter.Required,
RecurseSubPackages: r.CreateSetter.RecurseSubPackages,
OpenAPIFileName: openAPIFileName,
OpenAPIPath: filepath.Join(pkgPath, openAPIFileName),
ResourcesPath: pkgPath,
}
err = r.CreateSetter.Create()
if err != nil {
// return err if RecurseSubPackages is false
if !r.CreateSetter.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s in package %q\n\n", err.Error(), pkgPath)
}
} else {
fmt.Fprintf(w, "created setter %q in package %q\n\n", r.CreateSetter.Name, pkgPath)
}
return nil
}
// schemaFromFile reads the contents from schemaPath and returns schema
func schemaFromFile(schemaPath string) (*spec.Schema, error) {
sc := &spec.Schema{}

View File

@@ -5,13 +5,11 @@ package commands
import (
"fmt"
"io"
"path/filepath"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/pathutil"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
)
@@ -51,54 +49,48 @@ type CreateSubstitutionRunner struct {
}
func (r *CreateSubstitutionRunner) runE(c *cobra.Command, args []string) error {
e := executeCmdOnPkgs{
needOpenAPI: true,
writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.CreateSubstitution.RecurseSubPackages,
cmdRunner: r,
}
err := e.execute()
if err != nil {
return handleError(c, err)
}
return nil
}
func (r *CreateSubstitutionRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
r.CreateSubstitution = settersutil.SubstitutionCreator{
Name: r.CreateSubstitution.Name,
FieldName: r.CreateSubstitution.FieldName,
FieldValue: r.CreateSubstitution.FieldValue,
RecurseSubPackages: r.CreateSubstitution.RecurseSubPackages,
Pattern: r.CreateSubstitution.Pattern,
OpenAPIFileName: openAPIFileName,
OpenAPIPath: filepath.Join(pkgPath, openAPIFileName),
ResourcesPath: pkgPath,
}
r.CreateSubstitution.OpenAPIFileName = openAPIFileName
resourcePackagesPaths, err := pathutil.DirsWithFile(args[0], openAPIFileName, r.CreateSubstitution.RecurseSubPackages)
err = r.CreateSubstitution.Create()
if err != nil {
return err
}
if len(resourcePackagesPaths) == 0 {
return errors.Errorf("unable to find %q in package %q", r.CreateSubstitution.OpenAPIFileName, args[0])
}
for _, resourcesPath := range resourcePackagesPaths {
r.CreateSubstitution = settersutil.SubstitutionCreator{
Name: r.CreateSubstitution.Name,
FieldName: r.CreateSubstitution.FieldName,
FieldValue: r.CreateSubstitution.FieldValue,
RecurseSubPackages: r.CreateSubstitution.RecurseSubPackages,
Pattern: r.CreateSubstitution.Pattern,
OpenAPIFileName: openAPIFileName,
OpenAPIPath: filepath.Join(resourcesPath, openAPIFileName),
ResourcesPath: resourcesPath,
}
// Add schema present in openAPI file for current package
if err := openapi.AddSchemaFromFile(r.CreateSubstitution.OpenAPIPath); err != nil {
// return err if RecurseSubPackages is false
if !r.CreateSubstitution.RecurseSubPackages {
return err
}
err := r.CreateSubstitution.Create()
if err != nil {
// return err if there is only package
if len(resourcePackagesPaths) == 1 {
return err
} else {
// print error message and continue if there are multiple packages to set
fmt.Fprintf(c.OutOrStdout(), "%s in package %q\n\n", err.Error(), r.CreateSubstitution.ResourcesPath)
}
} else {
fmt.Fprintf(c.OutOrStdout(), "created substitution %q in package %q\n\n", r.CreateSubstitution.Name, r.CreateSubstitution.ResourcesPath)
}
// Delete schema present in openAPI file for current package
if err := openapi.DeleteSchemaInFile(r.CreateSubstitution.OpenAPIPath); err != nil {
return err
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s in package %q\n\n", err.Error(), pkgPath)
}
} else {
fmt.Fprintf(w, "created substitution %q in package %q\n\n", r.CreateSubstitution.Name, pkgPath)
}
return nil
}

View File

@@ -14,9 +14,7 @@ import (
"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/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/pathutil"
"sigs.k8s.io/kustomize/kyaml/setters"
"sigs.k8s.io/kustomize/kyaml/setters2"
)
@@ -69,48 +67,51 @@ func (r *ListSettersRunner) preRunE(c *cobra.Command, args []string) error {
func (r *ListSettersRunner) runE(c *cobra.Command, args []string) error {
if setterVersion == "v2" {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
e := executeCmdOnPkgs{
needOpenAPI: true,
writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.RecurseSubPackages,
cmdRunner: r,
}
resourcePaths, err := pathutil.DirsWithFile(args[0], openAPIFileName, r.RecurseSubPackages)
err := e.execute()
if err != nil {
return err
}
if len(resourcePaths) == 0 {
return errors.Errorf("unable to find %s in package %s", openAPIFileName, args[0])
}
// list setters for all the subpackages with openAPI file paths
for _, resourcePath := range resourcePaths {
r.List = setters2.List{
Name: r.List.Name,
OpenAPIFileName: openAPIFileName,
}
openAPIPath := filepath.Join(resourcePath, openAPIFileName)
fmt.Fprintf(c.OutOrStdout(), "\n%s/\n", resourcePath)
if err := r.ListSetters(c, openAPIPath, resourcePath); err != nil {
return err
}
if r.IncludeSubst {
if err := r.ListSubstitutions(c, openAPIPath); err != nil {
return err
}
}
return handleError(c, err)
}
return nil
}
return handleError(c, lookup(r.Lookup, c, args))
}
func (r *ListSettersRunner) ListSetters(c *cobra.Command, openAPIPath, resourcePath string) error {
func (r *ListSettersRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
r.List = setters2.List{
Name: r.List.Name,
OpenAPIFileName: openAPIFileName,
}
openAPIPath := filepath.Join(pkgPath, openAPIFileName)
fmt.Fprintf(w, "\n%s/\n", pkgPath)
if err := r.ListSetters(w, openAPIPath, pkgPath); err != nil {
return err
}
if r.IncludeSubst {
if err := r.ListSubstitutions(w, openAPIPath); err != nil {
return err
}
}
return nil
}
func (r *ListSettersRunner) ListSetters(w io.Writer, openAPIPath, resourcePath string) error {
// use setters v2
if err := r.List.ListSetters(openAPIPath, resourcePath); err != nil {
return err
}
table := newTable(c.OutOrStdout(), r.Markdown)
table := newTable(w, r.Markdown)
table.SetHeader([]string{"NAME", "VALUE", "SET BY", "DESCRIPTION", "COUNT", "REQUIRED"})
for i := range r.List.Setters {
s := r.List.Setters[i]
@@ -141,12 +142,12 @@ func (r *ListSettersRunner) ListSetters(c *cobra.Command, openAPIPath, resourceP
return nil
}
func (r *ListSettersRunner) ListSubstitutions(c *cobra.Command, openAPIPath string) error {
func (r *ListSettersRunner) ListSubstitutions(w io.Writer, openAPIPath string) error {
// use setters v2
if err := r.List.ListSubst(openAPIPath); err != nil {
return err
}
table := newTable(c.OutOrStdout(), r.Markdown)
table := newTable(w, r.Markdown)
b := tablewriter.Border{Top: true}
table.SetBorders(b)

View File

@@ -5,6 +5,7 @@ package commands
import (
"fmt"
"io"
"os"
"path/filepath"
@@ -14,7 +15,6 @@ import (
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/pathutil"
"sigs.k8s.io/kustomize/kyaml/setters"
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
)
@@ -135,46 +135,16 @@ func (r *SetRunner) preRunE(c *cobra.Command, args []string) error {
func (r *SetRunner) runE(c *cobra.Command, args []string) error {
if setterVersion == "v2" {
openAPIFileName, err := ext.OpenAPIFileName()
e := executeCmdOnPkgs{
needOpenAPI: true,
writer: c.OutOrStdout(),
rootPkgPath: args[0],
recurseSubPackages: r.Set.RecurseSubPackages,
cmdRunner: r,
}
err := e.execute()
if err != nil {
return err
}
r.Set.OpenAPIFileName = openAPIFileName
resourcePackagesPaths, err := pathutil.DirsWithFile(args[0], openAPIFileName, r.Set.RecurseSubPackages)
if err != nil {
return err
}
if len(resourcePackagesPaths) == 0 {
return errors.Errorf("unable to find %q in package %q", r.Set.OpenAPIFileName, args[0])
}
for _, resourcesPath := range resourcePackagesPaths {
r.Set = settersutil.FieldSetter{
Name: r.Set.Name,
Value: r.Set.Value,
ListValues: r.Set.ListValues,
Description: r.Set.Description,
SetBy: r.Set.SetBy,
Count: 0,
OpenAPIPath: filepath.Join(resourcesPath, openAPIFileName),
OpenAPIFileName: openAPIFileName,
ResourcesPath: resourcesPath,
RecurseSubPackages: r.Set.RecurseSubPackages,
}
count, err := r.Set.Set()
if err != nil {
// return err if there is only package
if len(resourcePackagesPaths) == 1 {
return err
} else {
// print error message and continue if there are multiple packages to set
fmt.Fprintf(c.OutOrStdout(), "%s in package %q\n", err.Error(), r.Set.ResourcesPath)
}
} else {
fmt.Fprintf(c.OutOrStdout(), "set %d fields in package %q\n", count, r.Set.ResourcesPath)
}
return handleError(c, err)
}
return nil
}
@@ -184,6 +154,38 @@ func (r *SetRunner) runE(c *cobra.Command, args []string) error {
return handleError(c, lookup(r.Lookup, c, args))
}
func (r *SetRunner) executeCmd(w io.Writer, pkgPath string) error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
r.Set = settersutil.FieldSetter{
Name: r.Set.Name,
Value: r.Set.Value,
ListValues: r.Set.ListValues,
Description: r.Set.Description,
SetBy: r.Set.SetBy,
Count: 0,
OpenAPIPath: filepath.Join(pkgPath, openAPIFileName),
OpenAPIFileName: openAPIFileName,
ResourcesPath: pkgPath,
RecurseSubPackages: r.Set.RecurseSubPackages,
}
count, err := r.Set.Set()
if err != nil {
// return err if RecurseSubPackages is false
if !r.Set.RecurseSubPackages {
return err
} else {
// print error message and continue if RecurseSubPackages is true
fmt.Fprintf(w, "%s in package %q\n", err.Error(), r.Set.ResourcesPath)
}
} else {
fmt.Fprintf(w, "set %d fields in package %q\n", count, r.Set.ResourcesPath)
}
return nil
}
func lookup(l setters.LookupSetters, c *cobra.Command, args []string) error {
// lookup the setters
err := kio.Pipeline{

View File

@@ -5,13 +5,81 @@ package commands
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/go-errors/errors"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/ext"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/pathutil"
)
// cmdRunner interface holds executeCmd definition which executes respective command's
// implementation on single package
type cmdRunner interface {
executeCmd(w io.Writer, pkgPath string) error
}
// executeCmdOnPkgs struct holds the parameters necessary to
// execute the filter command on packages in rootPkgPath
type executeCmdOnPkgs struct {
rootPkgPath string
recurseSubPackages bool
needOpenAPI bool
cmdRunner cmdRunner
writer io.Writer
}
// executeCmdOnPkgs takes the function definition for a command to be executed on single package, applies that definition
// recursively on all the subpackages present in rootPkgPath if recurseSubPackages is true, else applies the command on rootPkgPath only
func (e executeCmdOnPkgs) execute() error {
openAPIFileName, err := ext.OpenAPIFileName()
if err != nil {
return err
}
pkgsPaths, err := pathutil.DirsWithFile(e.rootPkgPath, openAPIFileName, e.recurseSubPackages)
if err != nil {
return err
}
if len(pkgsPaths) == 0 {
// at this point, there are no openAPI files in the rootPkgPath
if e.needOpenAPI {
// few executions need openAPI file to be present(ex: setters commands), if true throw an error
return errors.Errorf("unable to find %q in package %q", openAPIFileName, e.rootPkgPath)
}
// add root path for commands which doesn't need openAPI(ex: annotate, fmt)
pkgsPaths = []string{e.rootPkgPath}
}
for _, pkgPath := range pkgsPaths {
// Add schema present in openAPI file for current package
if e.needOpenAPI {
if err := openapi.AddSchemaFromFile(filepath.Join(pkgPath, openAPIFileName)); err != nil {
return err
}
}
err := e.cmdRunner.executeCmd(e.writer, pkgPath)
if err != nil {
return err
}
// Delete schema present in openAPI file for current package
if e.needOpenAPI {
if err := openapi.DeleteSchemaInFile(filepath.Join(pkgPath, openAPIFileName)); err != nil {
return err
}
}
}
return nil
}
// parseFieldPath parse a flag value into a field path
func parseFieldPath(path string) ([]string, error) {
// fixup '\.' so we don't split on it

View File

@@ -0,0 +1,179 @@
package commands
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/kyaml/errors"
)
func TestExecuteCmdOnPkgs(t *testing.T) {
var tests = []struct {
name string
recurse bool
pkgPath string
needOpenAPI bool
errMsg string
expectedOut string
}{
{
name: "need_Krmfile_error",
recurse: true,
needOpenAPI: true,
pkgPath: "subpkg1/subdir1",
errMsg: `unable to find "Krmfile" in package`,
},
{
name: "Krmfile_not_needed_no_err",
recurse: true,
needOpenAPI: false,
pkgPath: "subpkg1/subdir1",
expectedOut: `${baseDir}/subpkg1/subdir1`,
},
{
name: "executeCmd_returns_error",
recurse: true,
needOpenAPI: false,
pkgPath: "subpkg4",
errMsg: `this command returns an error if package has error.txt file`,
},
{
name: "executeCmd_prints_pkgpaths",
recurse: true,
needOpenAPI: false,
pkgPath: "subpkg2",
expectedOut: `
${baseDir}/subpkg2
${baseDir}/subpkg2/subpkg3`,
},
}
dir, err := ioutil.TempDir("", "")
if !assert.NoError(t, err) {
t.FailNow()
}
defer os.RemoveAll(dir)
err = createTestDirStructure(dir)
if !assert.NoError(t, err) {
t.FailNow()
}
for i := range tests {
test := tests[i]
t.Run(test.name, func(t *testing.T) {
actual := &bytes.Buffer{}
r := &TestRunner{}
e := executeCmdOnPkgs{
needOpenAPI: test.needOpenAPI,
writer: actual,
rootPkgPath: filepath.Join(dir, test.pkgPath),
recurseSubPackages: test.recurse,
cmdRunner: r,
}
err := e.execute()
if test.errMsg == "" {
if !assert.NoError(t, err) {
t.FailNow()
}
} else {
if !assert.Error(t, err) {
t.FailNow()
}
if !assert.Contains(t, err.Error(), test.errMsg) {
t.FailNow()
}
}
// normalize path format for windows
actualNormalized := strings.Replace(
strings.Replace(actual.String(), "\\", "/", -1),
"//", "/", -1)
expected := strings.Replace(test.expectedOut, "${baseDir}", dir, -1)
expectedNormalized := strings.Replace(
strings.Replace(expected, "\\", "/", -1),
"//", "/", -1)
if !assert.Equal(t, strings.TrimSpace(expectedNormalized), strings.TrimSpace(actualNormalized)) {
t.FailNow()
}
})
}
}
func createTestDirStructure(dir string) error {
/*
Adds the folders to the input dir with following structure
dir
├── subpkg1
│   ├── Krmfile
│   └── subdir1
├── subpkg4
│   ├── Krmfile
│   └── error.txt
└── subpkg2
├── subpkg3
│ ├── Krmfile
│ └── subdir2
└── Krmfile
*/
err := os.MkdirAll(filepath.Join(dir, "subpkg1/subdir1"), 0777|os.ModeDir)
if err != nil {
return err
}
err = os.MkdirAll(filepath.Join(dir, "subpkg2/subpkg3/subdir2"), 0777|os.ModeDir)
if err != nil {
return err
}
err = os.MkdirAll(filepath.Join(dir, "subpkg4"), 0777|os.ModeDir)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg1", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg2", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg2/subpkg3", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg4", "error.txt"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "subpkg4", "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, "Krmfile"), []byte(""), 0777)
if err != nil {
return err
}
return nil
}
type TestRunner struct{}
func (r *TestRunner) executeCmd(w io.Writer, pkgPath string) error {
children, err := ioutil.ReadDir(pkgPath)
if err != nil {
return err
}
for _, child := range children {
if child.Name() == "error.txt" {
return errors.Errorf("this command returns an error if package has error.txt file")
}
}
fmt.Fprintf(w, "%s\n", pkgPath)
return nil
}