mirror of https://github.com/helm/helm.git
review: move ValueOptions to SDK
Signed-off-by: Joe Lanford <joe.lanford@gmail.com>
This commit is contained in:
parent
68ee30b48c
commit
8a4b70b1e3
|
@ -18,26 +18,20 @@ package main
|
|||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/cmd/helm/require"
|
||||
"helm.sh/helm/pkg/action"
|
||||
"helm.sh/helm/pkg/chart"
|
||||
"helm.sh/helm/pkg/chart/loader"
|
||||
"helm.sh/helm/pkg/cli"
|
||||
"helm.sh/helm/pkg/cli/values"
|
||||
"helm.sh/helm/pkg/downloader"
|
||||
"helm.sh/helm/pkg/getter"
|
||||
"helm.sh/helm/pkg/release"
|
||||
"helm.sh/helm/pkg/strvals"
|
||||
)
|
||||
|
||||
const installDesc = `
|
||||
|
@ -104,7 +98,7 @@ charts in a repository, use 'helm search'.
|
|||
|
||||
func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
|
||||
client := action.NewInstall(cfg)
|
||||
valueOpts := &ValueOptions{}
|
||||
valueOpts := &values.Options{}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "install [NAME] [CHART]",
|
||||
|
@ -126,7 +120,7 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func addInstallFlags(f *pflag.FlagSet, client *action.Install, valueOpts *ValueOptions) {
|
||||
func addInstallFlags(f *pflag.FlagSet, client *action.Install, valueOpts *values.Options) {
|
||||
f.BoolVar(&client.DryRun, "dry-run", false, "simulate an install")
|
||||
f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during install")
|
||||
f.BoolVar(&client.Replace, "replace", false, "re-use the given name, even if that name is already used. This is unsafe in production")
|
||||
|
@ -141,7 +135,7 @@ func addInstallFlags(f *pflag.FlagSet, client *action.Install, valueOpts *ValueO
|
|||
addChartPathOptionsFlags(f, &client.ChartPathOptions)
|
||||
}
|
||||
|
||||
func addValueOptionsFlags(f *pflag.FlagSet, v *ValueOptions) {
|
||||
func addValueOptionsFlags(f *pflag.FlagSet, v *values.Options) {
|
||||
f.StringSliceVarP(&v.ValueFiles, "values", "f", []string{}, "specify values in a YAML file or a URL(can specify multiple)")
|
||||
f.StringArrayVar(&v.Values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
|
||||
f.StringArrayVar(&v.StringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
|
||||
|
@ -159,7 +153,7 @@ func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) {
|
|||
f.StringVar(&c.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
|
||||
}
|
||||
|
||||
func runInstall(args []string, client *action.Install, valueOpts *ValueOptions, out io.Writer) (*release.Release, error) {
|
||||
func runInstall(args []string, client *action.Install, valueOpts *values.Options, out io.Writer) (*release.Release, error) {
|
||||
debug("Original chart version: %q", client.Version)
|
||||
if client.Version == "" && client.Devel {
|
||||
debug("setting version to >0.0.0-0")
|
||||
|
@ -232,89 +226,3 @@ func isChartInstallable(ch *chart.Chart) (bool, error) {
|
|||
}
|
||||
return false, errors.Errorf("%s charts are not installable", ch.Metadata.Type)
|
||||
}
|
||||
|
||||
type ValueOptions struct {
|
||||
ValueFiles []string
|
||||
StringValues []string
|
||||
Values []string
|
||||
}
|
||||
|
||||
// MergeValues merges values from files specified via -f/--values and
|
||||
// directly via --set or --set-string, marshaling them to YAML
|
||||
func (v *ValueOptions) MergeValues(settings cli.EnvSettings) (map[string]interface{}, error) {
|
||||
base := map[string]interface{}{}
|
||||
|
||||
// User specified a values files via -f/--values
|
||||
for _, filePath := range v.ValueFiles {
|
||||
currentMap := map[string]interface{}{}
|
||||
|
||||
bytes, err := readFile(filePath, settings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal(bytes, ¤tMap); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse %s", filePath)
|
||||
}
|
||||
// Merge with the previous map
|
||||
base = mergeMaps(base, currentMap)
|
||||
}
|
||||
|
||||
// User specified a value via --set
|
||||
for _, value := range v.Values {
|
||||
if err := strvals.ParseInto(value, base); err != nil {
|
||||
return nil, errors.Wrap(err, "failed parsing --set data")
|
||||
}
|
||||
}
|
||||
|
||||
// User specified a value via --set-string
|
||||
for _, value := range v.StringValues {
|
||||
if err := strvals.ParseIntoString(value, base); err != nil {
|
||||
return nil, errors.Wrap(err, "failed parsing --set-string data")
|
||||
}
|
||||
}
|
||||
|
||||
return base, nil
|
||||
}
|
||||
|
||||
func mergeMaps(a, b map[string]interface{}) map[string]interface{} {
|
||||
out := make(map[string]interface{}, len(a))
|
||||
for k, v := range a {
|
||||
out[k] = v
|
||||
}
|
||||
for k, v := range b {
|
||||
if v, ok := v.(map[string]interface{}); ok {
|
||||
if bv, ok := out[k]; ok {
|
||||
if bv, ok := bv.(map[string]interface{}); ok {
|
||||
out[k] = mergeMaps(bv, v)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
out[k] = v
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// readFile load a file from stdin, the local directory, or a remote file with a url.
|
||||
func readFile(filePath string, settings cli.EnvSettings) ([]byte, error) {
|
||||
if strings.TrimSpace(filePath) == "-" {
|
||||
return ioutil.ReadAll(os.Stdin)
|
||||
}
|
||||
u, _ := url.Parse(filePath)
|
||||
p := getter.All(settings)
|
||||
|
||||
// FIXME: maybe someone handle other protocols like ftp.
|
||||
getterConstructor, err := p.ByScheme(u.Scheme)
|
||||
|
||||
if err != nil {
|
||||
return ioutil.ReadFile(filePath)
|
||||
}
|
||||
|
||||
getter, err := getterConstructor(getter.WithURL(filePath))
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
data, err := getter.Get(filePath)
|
||||
return data.Bytes(), err
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
|
||||
"helm.sh/helm/pkg/action"
|
||||
"helm.sh/helm/pkg/cli/values"
|
||||
)
|
||||
|
||||
var longLintHelp = `
|
||||
|
@ -38,7 +39,7 @@ or recommendation, it will emit [WARNING] messages.
|
|||
|
||||
func newLintCmd(out io.Writer) *cobra.Command {
|
||||
client := action.NewLint()
|
||||
valueOpts := &ValueOptions{}
|
||||
valueOpts := &values.Options{}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "lint PATH",
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
|
||||
"helm.sh/helm/pkg/action"
|
||||
"helm.sh/helm/pkg/cli/values"
|
||||
"helm.sh/helm/pkg/downloader"
|
||||
"helm.sh/helm/pkg/getter"
|
||||
)
|
||||
|
@ -43,7 +44,7 @@ Versioned chart archives are used by Helm package repositories.
|
|||
|
||||
func newPackageCmd(out io.Writer) *cobra.Command {
|
||||
client := action.NewPackage()
|
||||
valueOpts := &ValueOptions{}
|
||||
valueOpts := &values.Options{}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "package [CHART_PATH] [...]",
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
"helm.sh/helm/cmd/helm/require"
|
||||
"helm.sh/helm/pkg/action"
|
||||
"helm.sh/helm/pkg/cli/values"
|
||||
)
|
||||
|
||||
const templateDesc = `
|
||||
|
@ -39,7 +40,7 @@ is done.
|
|||
func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
|
||||
var validate bool
|
||||
client := action.NewInstall(cfg)
|
||||
valueOpts := &ValueOptions{}
|
||||
valueOpts := &values.Options{}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "template [NAME] [CHART]",
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
"helm.sh/helm/cmd/helm/require"
|
||||
"helm.sh/helm/pkg/action"
|
||||
"helm.sh/helm/pkg/chart/loader"
|
||||
"helm.sh/helm/pkg/cli/values"
|
||||
"helm.sh/helm/pkg/storage/driver"
|
||||
)
|
||||
|
||||
|
@ -57,7 +58,7 @@ set for a key called 'foo', the 'newbar' value would take precedence:
|
|||
|
||||
func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
|
||||
client := action.NewUpgrade(cfg)
|
||||
valueOpts := &ValueOptions{}
|
||||
valueOpts := &values.Options{}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "upgrade [RELEASE] [CHART]",
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
Copyright The Helm 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 values
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/pkg/cli"
|
||||
"helm.sh/helm/pkg/getter"
|
||||
"helm.sh/helm/pkg/strvals"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
ValueFiles []string
|
||||
StringValues []string
|
||||
Values []string
|
||||
}
|
||||
|
||||
// MergeValues merges values from files specified via -f/--values and
|
||||
// directly via --set or --set-string, marshaling them to YAML
|
||||
func (opts *Options) MergeValues(settings cli.EnvSettings) (map[string]interface{}, error) {
|
||||
base := map[string]interface{}{}
|
||||
|
||||
// User specified a values files via -f/--values
|
||||
for _, filePath := range opts.ValueFiles {
|
||||
currentMap := map[string]interface{}{}
|
||||
|
||||
bytes, err := readFile(filePath, settings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal(bytes, ¤tMap); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse %s", filePath)
|
||||
}
|
||||
// Merge with the previous map
|
||||
base = mergeMaps(base, currentMap)
|
||||
}
|
||||
|
||||
// User specified a value via --set
|
||||
for _, value := range opts.Values {
|
||||
if err := strvals.ParseInto(value, base); err != nil {
|
||||
return nil, errors.Wrap(err, "failed parsing --set data")
|
||||
}
|
||||
}
|
||||
|
||||
// User specified a value via --set-string
|
||||
for _, value := range opts.StringValues {
|
||||
if err := strvals.ParseIntoString(value, base); err != nil {
|
||||
return nil, errors.Wrap(err, "failed parsing --set-string data")
|
||||
}
|
||||
}
|
||||
|
||||
return base, nil
|
||||
}
|
||||
|
||||
func mergeMaps(a, b map[string]interface{}) map[string]interface{} {
|
||||
out := make(map[string]interface{}, len(a))
|
||||
for k, v := range a {
|
||||
out[k] = v
|
||||
}
|
||||
for k, v := range b {
|
||||
if v, ok := v.(map[string]interface{}); ok {
|
||||
if bv, ok := out[k]; ok {
|
||||
if bv, ok := bv.(map[string]interface{}); ok {
|
||||
out[k] = mergeMaps(bv, v)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
out[k] = v
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// readFile load a file from stdin, the local directory, or a remote file with a url.
|
||||
func readFile(filePath string, settings cli.EnvSettings) ([]byte, error) {
|
||||
if strings.TrimSpace(filePath) == "-" {
|
||||
return ioutil.ReadAll(os.Stdin)
|
||||
}
|
||||
u, _ := url.Parse(filePath)
|
||||
p := getter.All(settings)
|
||||
|
||||
// FIXME: maybe someone handle other protocols like ftp.
|
||||
getterConstructor, err := p.ByScheme(u.Scheme)
|
||||
|
||||
if err != nil {
|
||||
return ioutil.ReadFile(filePath)
|
||||
}
|
||||
|
||||
getter, err := getterConstructor(getter.WithURL(filePath))
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
data, err := getter.Get(filePath)
|
||||
return data.Bytes(), err
|
||||
}
|
Loading…
Reference in New Issue