From 94c3b1212e791766358b840b0aa471846d928750 Mon Sep 17 00:00:00 2001 From: Jingfang Liu Date: Fri, 28 Sep 2018 15:30:58 -0700 Subject: [PATCH] add command to save the default transformer configurations to local files --- pkg/commands/commands.go | 1 + pkg/commands/config.go | 114 ++++++++++++++++++ pkg/commands/config_test.go | 87 +++++++++++++ pkg/fs/fakefs.go | 5 + pkg/fs/fs.go | 1 + pkg/fs/realfs.go | 5 + .../defaultconfig/defaultconfig.go | 12 ++ 7 files changed, 225 insertions(+) create mode 100644 pkg/commands/config.go create mode 100644 pkg/commands/config_test.go diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index 29c19338c..b59b251ea 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.go @@ -45,6 +45,7 @@ See https://sigs.k8s.io/kustomize // TODO: Make consistent API for newCmd* functions. newCmdBuild(stdOut, fsys), newCmdEdit(fsys), + newCmdConfig(fsys), newCmdVersion(stdOut), ) c.PersistentFlags().AddGoFlagSet(flag.CommandLine) diff --git a/pkg/commands/config.go b/pkg/commands/config.go new file mode 100644 index 000000000..0132a65d0 --- /dev/null +++ b/pkg/commands/config.go @@ -0,0 +1,114 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package commands + +import ( + "fmt" + "path/filepath" + + "github.com/spf13/cobra" + + "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/transformerconfig/defaultconfig" +) + +// newCmdConfig returns an instance of 'config' subcommand. +func newCmdConfig(fsys fs.FileSystem) *cobra.Command { + c := &cobra.Command{ + Use: "config", + Short: "Config Kustomize transformers", + Long: "", + Example: ` + # Save the default transformer configrations to a local directory + kustomize config save -d ~/.kustomize/config +`, + Args: cobra.MinimumNArgs(1), + } + c.AddCommand( + newCmdSave(fsys), + ) + return c +} + +type saveOptions struct { + saveDirectory string +} + +func newCmdSave(fsys fs.FileSystem) *cobra.Command { + var o saveOptions + + c := &cobra.Command{ + Use: "save", + Short: "Save default kustomize transformer configurations to a local directory", + Long: "", + Example: ` + # Save the default transformer configrations to a local directory + save -d ~/.kustomize/config + +`, + RunE: func(cmd *cobra.Command, args []string) error { + err := o.Validate() + if err != nil { + return err + } + err = o.Complete(fsys) + if err != nil { + return err + } + return o.RunSave(fsys) + }, + } + c.Flags().StringVarP( + &o.saveDirectory, + "directory", "d", "", + "Directory to save the default transformer configurations") + + return c + +} + +// Validate validates the saveOptions is not empty +func (o *saveOptions) Validate() error { + if o.saveDirectory == "" { + return fmt.Errorf("must specify one local directory to save the default transformer configurations") + } + return nil +} + +// Complete creates the save directory when the directory doesn't exist +func (o *saveOptions) Complete(fsys fs.FileSystem) error { + if !fsys.Exists(o.saveDirectory) { + return fsys.MkdirAll(o.saveDirectory) + } + if fsys.IsDir(o.saveDirectory) { + return nil + } + return fmt.Errorf("%s is not a directory. Please use a different directory name.", o.saveDirectory) +} + +// RunSave saves the default transformer configurations local directory +func (o *saveOptions) RunSave(fsys fs.FileSystem) error { + m := defaultconfig.GetDefaultPathConfigStrings() + for tname, tcfg := range m { + filename := filepath.Join(o.saveDirectory, tname+".yaml") + err := fsys.WriteFile(filename, []byte(tcfg)) + if err != nil { + return err + } + } + return nil +} diff --git a/pkg/commands/config_test.go b/pkg/commands/config_test.go new file mode 100644 index 000000000..1d6caad19 --- /dev/null +++ b/pkg/commands/config_test.go @@ -0,0 +1,87 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package commands + +import ( + "fmt" + "reflect" + "strings" + "testing" + + "sigs.k8s.io/kustomize/pkg/fs" +) + +func TestValidate(t *testing.T) { + o := saveOptions{ + saveDirectory: "", + } + err := o.Validate() + if !strings.Contains(err.Error(), "must specify one local directory") { + t.Fatalf("Incorrect error %v", err) + } + + o.saveDirectory = "/some/dir" + err = o.Validate() + if err != nil { + t.Fatalf("Unexpected error %v", err) + } +} + +func TestComplete(t *testing.T) { + fsys := fs.MakeFakeFS() + fsys.Mkdir("/some/dir") + fsys.WriteFile("/some/file", []byte(`some file`)) + + type testcase struct { + dir string + expect error + } + testcases := []testcase{ + { + dir: "/some/dir", + expect: nil, + }, + { + dir: "/some/dir/not/existing", + expect: nil, + }, + { + dir: "/some/file", + expect: fmt.Errorf("%s is not a directory. Please use a different directory name.", "/some/file"), + }, + } + + for _, tcase := range testcases { + o := saveOptions{saveDirectory: tcase.dir} + actual := o.Complete(fsys) + if !reflect.DeepEqual(actual, tcase.expect) { + t.Fatalf("Expected %v\n but bot %v\n", tcase.expect, actual) + } + } +} + +func TestRunSave(t *testing.T) { + fsys := fs.MakeFakeFS() + o := saveOptions{saveDirectory: "/some/dir"} + err := o.RunSave(fsys) + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + if !fsys.Exists("/some/dir/nameprefix.yaml") { + t.Fatal("default configurations are not successfully save.") + } +} diff --git a/pkg/fs/fakefs.go b/pkg/fs/fakefs.go index 045d94c17..6b67c27fc 100644 --- a/pkg/fs/fakefs.go +++ b/pkg/fs/fakefs.go @@ -48,6 +48,11 @@ func (fs *FakeFS) Mkdir(name string) error { return nil } +// MkdirAll delegates to Mkdir +func (fs *FakeFS) MkdirAll(name string) error { + return fs.Mkdir(name) +} + // Open returns a fake file in the open state. func (fs *FakeFS) Open(name string) (File, error) { if _, found := fs.m[name]; !found { diff --git a/pkg/fs/fs.go b/pkg/fs/fs.go index ecb064834..798fe572a 100644 --- a/pkg/fs/fs.go +++ b/pkg/fs/fs.go @@ -26,6 +26,7 @@ import ( type FileSystem interface { Create(name string) (File, error) Mkdir(name string) error + MkdirAll(name string) error Open(name string) (File, error) IsDir(name string) bool Exists(name string) bool diff --git a/pkg/fs/realfs.go b/pkg/fs/realfs.go index 42b72b676..82bbb92ef 100644 --- a/pkg/fs/realfs.go +++ b/pkg/fs/realfs.go @@ -40,6 +40,11 @@ func (realFS) Mkdir(name string) error { return os.Mkdir(name, 0777|os.ModeDir) } +// MkdirAll delegates to os.MkdirAll. +func (realFS) MkdirAll(name string) error { + return os.MkdirAll(name, 0777|os.ModeDir) +} + // Open delegates to os.Open. func (realFS) Open(name string) (File, error) { return os.Open(name) } diff --git a/pkg/transformerconfig/defaultconfig/defaultconfig.go b/pkg/transformerconfig/defaultconfig/defaultconfig.go index c257bc144..b7369a508 100644 --- a/pkg/transformerconfig/defaultconfig/defaultconfig.go +++ b/pkg/transformerconfig/defaultconfig/defaultconfig.go @@ -34,3 +34,15 @@ func GetDefaultPathConfigs() []byte { } return bytes.Join(configData, []byte("\n")) } + +// GetDefaultPathConfigStrings returns the default pathConfigs in string format +func GetDefaultPathConfigStrings() map[string]string { + result := make(map[string]string) + result["nameprefix"] = namePrefixPathConfigs + result["commonlabels"] = commonLabelPathConfigs + result["commonannotations"] = commonAnnotationPathConfigs + result["namespace"] = namespacePathConfigs + result["varreference"] = varReferencePathConfigs + result["namereference"] = namespacePathConfigs + return result +}