diff --git a/cmd/delete.go b/cmd/delete.go index f7df57efdbd4e7c86d23d045ef5d3359c0d6d360..5ebe5ba30d0cee04b0e713a04264e6b9d959bd2c 100644 --- a/cmd/delete.go +++ b/cmd/delete.go @@ -55,7 +55,7 @@ var deleteCmd = &cobra.Command{ return err } - objs, err := readObjs(cmd, args) + objs, err := expandEnvCmdObjs(cmd, args) if err != nil { return err } diff --git a/cmd/diff.go b/cmd/diff.go index 22664a2215d192de30e6fd926a1b180f0df2828a..887631a0ce73267dfc30938167bbfb9bce420353 100644 --- a/cmd/diff.go +++ b/cmd/diff.go @@ -53,7 +53,7 @@ var diffCmd = &cobra.Command{ return err } - objs, err := readObjs(cmd, args) + objs, err := expandEnvCmdObjs(cmd, args) if err != nil { return err } diff --git a/cmd/root.go b/cmd/root.go index 1b836b76ebf0dae49a7f89bb33ad521e5af5a8c0..7f24777cd2cf1210d8f48bacf7e8104addf5d6f1 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -35,7 +35,6 @@ import ( "k8s.io/client-go/tools/clientcmd" "github.com/ksonnet/kubecfg/metadata" - "github.com/ksonnet/kubecfg/pkg/kubecfg" "github.com/ksonnet/kubecfg/template" "github.com/ksonnet/kubecfg/utils" @@ -245,10 +244,14 @@ func restClientPool(cmd *cobra.Command) (dynamic.ClientPool, discovery.Discovery return pool, discoCache, nil } +// addEnvCmdFlags adds the flags that are common to the family of commands +// whose form is `[<env>|-f <file-name>]`, e.g., `update` and `delete`. func addEnvCmdFlags(cmd *cobra.Command) { cmd.PersistentFlags().StringArrayP(flagFile, flagFileShort, nil, "Filename or directory that contains the configuration to apply (accepts YAML, JSON, and Jsonnet)") } +// parseEnvCmd parses the family of commands that come in the form `[<env>|-f +// <file-name>]`, e.g., `update` and `delete`. func parseEnvCmd(cmd *cobra.Command, args []string) (*string, []string, error) { flags := cmd.Flags() @@ -265,8 +268,13 @@ func parseEnvCmd(cmd *cobra.Command, args []string) (*string, []string, error) { return env, files, nil } -func readObjs(cmd *cobra.Command, args []string) ([]*unstructured.Unstructured, error) { - env, f, err := parseEnvCmd(cmd, args) +// expandEnvCmdObjs finds and expands templates for the family of commands of +// the form `[<env>|-f <file-name>]`, e.g., `update` and `delete`. That is, if +// the user passes a list of files, we will expand all templates in those files, +// while if a user passes an environment name, we will expand all component +// files using that environment. +func expandEnvCmdObjs(cmd *cobra.Command, args []string) ([]*unstructured.Unstructured, error) { + env, fileNames, err := parseEnvCmd(cmd, args) if err != nil { return nil, err } @@ -281,10 +289,40 @@ func readObjs(cmd *cobra.Command, args []string) ([]*unstructured.Unstructured, return nil, err } - files, err := kubecfg.GetFiles(metadata.AbsPath(cwd), env, f) - if err != nil { - return nil, err + // + // Get all filenames that contain templates to expand. Importantly, we need to + // enforce the form `[<env-name>|-f <file-name>]`; that is, we need to make + // sure that the user either passed an environment name or a `-f` flag. + // + + envPresent := env != nil + filesPresent := len(fileNames) > 0 + + // This is equivalent to: `if !xor(envPresent, filesPresent) {` + if envPresent && filesPresent { + return nil, fmt.Errorf("Either an environment name or a file list is required, but not both") + } else if !envPresent && !filesPresent { + return nil, fmt.Errorf("Must specify either an environment or a file list") } - return expander.Expand(files) + if envPresent { + manager, err := metadata.Find(metadata.AbsPath(cwd)) + if err != nil { + return nil, err + } + + libPath, vendorLibPath := manager.LibPaths() + expander.FlagJpath = append([]string{string(libPath), string(vendorLibPath)}, expander.FlagJpath...) + + fileNames, err = manager.ComponentPaths() + if err != nil { + return nil, err + } + } + + // + // Expand templates. + // + + return expander.Expand(fileNames) } diff --git a/cmd/show.go b/cmd/show.go index 5ea288e549043adc1e299f3ca29f21ae32fa4259..9e4ac5c53d173ad4d0760667cfc9dec87f88262c 100644 --- a/cmd/show.go +++ b/cmd/show.go @@ -45,7 +45,7 @@ var showCmd = &cobra.Command{ return err } - objs, err := readObjs(cmd, args) + objs, err := expandEnvCmdObjs(cmd, args) if err != nil { return err } diff --git a/cmd/update.go b/cmd/update.go index 41b104bde18b4c8741c2a73fe7cbc536298bbafe..8f0e72120a7b8eb8b9748de24d03256a11fb1385 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -101,7 +101,7 @@ local configuration. Accepts JSON, YAML, or Jsonnet.`, return err } - objs, err := readObjs(cmd, args) + objs, err := expandEnvCmdObjs(cmd, args) if err != nil { return err } diff --git a/cmd/validate.go b/cmd/validate.go index 171c1e3d50376b23c887d7c05cb3ca1a0b5cf0b3..f05f75e95ec3917bd5fbd1d4a48245f6454348ee 100644 --- a/cmd/validate.go +++ b/cmd/validate.go @@ -39,7 +39,7 @@ var validateCmd = &cobra.Command{ return err } - objs, err := readObjs(cmd, args) + objs, err := expandEnvCmdObjs(cmd, args) if err != nil { return err } diff --git a/metadata/interface.go b/metadata/interface.go index bc58d16ba114ffbfb78da45f94ba63046a38a5ed..5c81943b69a4432399f4241d8698f09344b84778 100644 --- a/metadata/interface.go +++ b/metadata/interface.go @@ -20,6 +20,7 @@ type AbsPaths []string type Manager interface { Root() AbsPath ComponentPaths() (AbsPaths, error) + LibPaths() (libPath, vendorLibPath AbsPath) // // TODO: Fill in methods as we need them. // diff --git a/metadata/manager.go b/metadata/manager.go index 2bfb04c78525d726e38df915eb27a0e391b0a903..5da4157709e3ce4ec0f2024d0424c0acf4f89f15 100644 --- a/metadata/manager.go +++ b/metadata/manager.go @@ -126,7 +126,7 @@ func (m *manager) Root() AbsPath { } func (m *manager) ComponentPaths() (AbsPaths, error) { - paths := []string{} + paths := AbsPaths{} err := afero.Walk(m.appFS, string(m.componentsPath), func(path string, info os.FileInfo, err error) error { if err != nil { return err @@ -144,6 +144,10 @@ func (m *manager) ComponentPaths() (AbsPaths, error) { return paths, nil } +func (m *manager) LibPaths() (libPath, vendorLibPath AbsPath) { + return m.libPath, m.vendorLibDir +} + func (m *manager) cacheClusterSpecData(name string, specData []byte) error { envPath := string(appendToAbsPath(m.schemaDir, name)) err := m.appFS.MkdirAll(envPath, os.ModePerm) diff --git a/pkg/kubecfg/common.go b/pkg/kubecfg/common.go deleted file mode 100644 index 305f707347db1204db5e103e56605223458bd15c..0000000000000000000000000000000000000000 --- a/pkg/kubecfg/common.go +++ /dev/null @@ -1,33 +0,0 @@ -package kubecfg - -import ( - "fmt" - - "github.com/ksonnet/kubecfg/metadata" -) - -func GetFiles(wd metadata.AbsPath, env *string, files []string) ([]string, error) { - envPresent := env != nil - filesPresent := len(files) > 0 - - // This is equivalent to: `if !xor(envPresent, filesPresent) {` - if envPresent && filesPresent { - return nil, fmt.Errorf("Either an environment name or a file list is required, but not both") - } else if !envPresent && !filesPresent { - return nil, fmt.Errorf("Must specify either an environment or a file list") - } - - if envPresent { - manager, err := metadata.Find(wd) - if err != nil { - return nil, err - } - - files, err = manager.ComponentPaths() - if err != nil { - return nil, err - } - } - - return files, nil -}