diff options
author | Jon Bratseth <bratseth@gmail.com> | 2023-04-05 15:46:27 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-05 15:46:27 +0200 |
commit | 2f2b57afc88b58b3bfde83a6c3313717db4aeb39 (patch) | |
tree | 78be48695102728c1fac8870be9228c437b375da /client | |
parent | 7f4d68f7da482bbc24ed4914be7931f0f9e52444 (diff) | |
parent | c6cd74032d58b2ee5afd6e3d78f748fabc0b9d04 (diff) |
Merge pull request #26675 from vespa-engine/mpolden/local-config
Read local config when in an application package sub-directory
Diffstat (limited to 'client')
-rw-r--r-- | client/go/internal/cli/cmd/config.go | 85 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/config_test.go | 8 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/deploy_test.go | 3 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/root.go | 10 | ||||
-rw-r--r-- | client/go/internal/cli/cmd/visit_test.go | 2 |
5 files changed, 79 insertions, 29 deletions
diff --git a/client/go/internal/cli/cmd/config.go b/client/go/internal/cli/cmd/config.go index fd049864096..3dd4b04509c 100644 --- a/client/go/internal/cli/cmd/config.go +++ b/client/go/internal/cli/cmd/config.go @@ -150,6 +150,18 @@ $ vespa config set --local wait 600 if _, err := cli.applicationPackageFrom(nil, false); err != nil { return fmt.Errorf("failed to write local configuration: %w", err) } + if cli.config.local == nil { + wd, err := os.Getwd() + if err != nil { + return nil + } + localDir := filepath.Join(wd, ".vespa") + newConfig, err := readConfigIn(localDir, cli.config.environment, cli.config.flags) + if err != nil { + return err + } + cli.config.local = newConfig + } config = cli.config.local } if err := config.set(args[0], args[1]); err != nil { @@ -187,6 +199,10 @@ $ vespa config unset --local application return fmt.Errorf("failed to write local configuration: %w", err) } config = cli.config.local + if config == nil { + cli.printWarning("no local configuration present") + return nil + } } if err := config.unset(args[0]); err != nil { return err @@ -219,7 +235,7 @@ $ vespa config get --local RunE: func(cmd *cobra.Command, args []string) error { config := cli.config if localArg { - if cli.config.local.isEmpty() { + if cli.config.local == nil { cli.printWarning("no local configuration present") return nil } @@ -255,23 +271,36 @@ type KeyPair struct { PrivateKeyFile string } -func loadConfig(environment map[string]string, flags map[string]*pflag.Flag) (*Config, error) { - home, err := vespaCliHome(environment) +func loadConfig(environment map[string]string, flags map[string]*pflag.Flag, workDir string) (*Config, error) { + dir, err := vespaCliHome(environment) if err != nil { return nil, fmt.Errorf("could not detect config directory: %w", err) } - config, err := loadConfigFrom(home, environment, flags) + config, err := readConfigIn(dir, environment, flags) if err != nil { return nil, err } - // Load local config from working directory by default - if err := config.loadLocalConfigFrom("."); err != nil { + if workDir == "" { + workDir, err = os.Getwd() + if err != nil { + return nil, err + } + } + localDir, err := config.findLocalConfigDir(workDir) + if err != nil { return nil, err } + if localDir != "" { + localConfig, err := readConfigIn(localDir, environment, flags) + if err != nil { + return nil, err + } + config.local = localConfig + } return config, nil } -func loadConfigFrom(dir string, environment map[string]string, flags map[string]*pflag.Flag) (*Config, error) { +func readConfigIn(dir string, environment map[string]string, flags map[string]*pflag.Flag) (*Config, error) { cacheDir, err := vespaCliCacheDir(environment) if err != nil { return nil, fmt.Errorf("could not detect cache directory: %w", err) @@ -307,18 +336,30 @@ func athenzPath(filename string) (string, error) { return filepath.Join(userHome, ".athenz", filename), nil } -func (c *Config) loadLocalConfigFrom(parent string) error { - home := filepath.Join(parent, ".vespa") - _, err := os.Stat(home) - if err != nil && !os.IsNotExist(err) { - return err +func (c *Config) findLocalConfigDir(dir string) (string, error) { + userHome, err := os.UserHomeDir() + if err != nil { + return "", err } - config, err := loadConfigFrom(home, c.environment, c.flags) + dir, err = filepath.Abs(dir) if err != nil { - return err + return "", err } - c.local = config - return nil + for dir != userHome { + vespaDir := filepath.Join(dir, ".vespa") + _, err := os.Stat(vespaDir) + if err == nil { + return vespaDir, nil + } else if err != nil && !os.IsNotExist(err) { + return "", err + } + parent := filepath.Clean(filepath.Join(dir, "..")) + if parent == dir { + break + } + dir = parent + } + return "", nil } func (c *Config) write() error { @@ -527,8 +568,6 @@ func (c *Config) applicationFilePath(app vespa.ApplicationID, name string) (stri return filepath.Join(appDir, name), nil } -func (c *Config) isEmpty() bool { return len(c.config.Keys()) == 0 } - // list returns the options that have been set in this configuration. If includeUnset is true, also return options that // haven't been set. func (c *Config) list(includeUnset bool) []string { @@ -544,12 +583,12 @@ func (c *Config) list(includeUnset bool) []string { } // flagValue returns the set value and default value of the named flag. -func (c *Config) flagValue(name string) (string, string) { +func (c *Config) flagValue(name string) (string, string, bool) { f, ok := c.flags[name] if !ok { - return "", "" + return "", "", ok } - return f.Value.String(), f.DefValue + return f.Value.String(), f.DefValue, f.Changed } // getNonEmpty returns value of given option, if that value is non-empty @@ -564,9 +603,9 @@ func (c *Config) getNonEmpty(option string) (string, bool) { // get returns the value associated with option, from the most preferred source in the following order: flag > local // config > global config. func (c *Config) get(option string) (string, bool) { - flagValue, flagDefault := c.flagValue(option) + flagValue, flagDefault, changed := c.flagValue(option) // explicit flag value always takes precedence over everything else - if flagValue != flagDefault { + if changed { return flagValue, true } // ... then local config, if option is explicitly defined there diff --git a/client/go/internal/cli/cmd/config_test.go b/client/go/internal/cli/cmd/config_test.go index 612904061de..34c26ce4572 100644 --- a/client/go/internal/cli/cmd/config_test.go +++ b/client/go/internal/cli/cmd/config_test.go @@ -28,6 +28,7 @@ func TestConfig(t *testing.T) { assertConfigCommand(t, configHome, "", "config", "set", "target", "http://127.0.0.1:8080") assertConfigCommand(t, configHome, "", "config", "set", "target", "https://127.0.0.1") assertConfigCommand(t, configHome, "target = https://127.0.0.1\n", "config", "get", "target") + assertConfigCommand(t, configHome, "target = local\n", "config", "get", "-t", "local", "target") // application assertConfigCommandErr(t, configHome, "Error: invalid application: \"foo\"\n", "config", "set", "application", "foo") @@ -103,7 +104,14 @@ func TestLocalConfig(t *testing.T) { // get reads global option if unset locally assertConfigCommand(t, configHome, "target = cloud\n", "config", "get", "target") + // get prints local config when in a a sub-directory of the application package + subDir := filepath.Join(rootDir, "a", "b") + require.Nil(t, os.MkdirAll(subDir, 0755)) + require.Nil(t, os.Chdir(subDir)) + assertConfigCommand(t, configHome, "instance = foo\n", "config", "get", "--local") + // get merges settings from local and global config + require.Nil(t, os.Chdir(rootDir)) assertConfigCommand(t, configHome, "", "config", "set", "--local", "application", "t1.a1") assertConfigCommand(t, configHome, `application = t1.a1.default cluster = <unset> diff --git a/client/go/internal/cli/cmd/deploy_test.go b/client/go/internal/cli/cmd/deploy_test.go index 9eaf878bc5e..f97177373eb 100644 --- a/client/go/internal/cli/cmd/deploy_test.go +++ b/client/go/internal/cli/cmd/deploy_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/vespa-engine/vespa/client/go/internal/mock" "github.com/vespa-engine/vespa/client/go/internal/vespa" ) @@ -111,7 +112,7 @@ func assertDeploy(applicationPackage string, arguments []string, t *testing.T) { cli, stdout, _ := newTestCLI(t) client := &mock.HTTPClient{} cli.httpClient = client - assert.Nil(t, cli.Run(arguments...)) + require.Nil(t, cli.Run(arguments...)) assert.Equal(t, "\nSuccess: Deployed "+applicationPackage+"\n", stdout.String()) diff --git a/client/go/internal/cli/cmd/root.go b/client/go/internal/cli/cmd/root.go index 58e940d59ef..5f993fe2a02 100644 --- a/client/go/internal/cli/cmd/root.go +++ b/client/go/internal/cli/cmd/root.go @@ -46,6 +46,7 @@ type CLI struct { cmd *cobra.Command config *Config + flags map[string]*pflag.Flag version version.Version httpClient util.HTTPClient @@ -151,7 +152,8 @@ For detailed description of flags and configuration, see 'vespa help config'. }, } cli.isTerminal = func() bool { return isTerminal(cli.Stdout) && isTerminal(cli.Stderr) } - if err := cli.loadConfig(); err != nil { + cli.flags = cli.configureFlags() + if err := cli.loadConfig(""); err != nil { return nil, err } cli.configureSpinner() @@ -160,8 +162,8 @@ For detailed description of flags and configuration, see 'vespa help config'. return &cli, nil } -func (c *CLI) loadConfig() error { - config, err := loadConfig(c.Environment, c.configureFlags()) +func (c *CLI) loadConfig(workDir string) error { + config, err := loadConfig(c.Environment, c.flags, workDir) if err != nil { return err } @@ -540,7 +542,7 @@ func (c *CLI) applicationPackageFrom(args []string, requirePackaging bool) (vesp } if stat.IsDir() { // Using an explicit application directory, look for local config in that directory too - if err := c.config.loadLocalConfigFrom(path); err != nil { + if err := c.loadConfig(path); err != nil { return vespa.ApplicationPackage{}, err } } diff --git a/client/go/internal/cli/cmd/visit_test.go b/client/go/internal/cli/cmd/visit_test.go index 4302680b9d9..b6e5b893e0b 100644 --- a/client/go/internal/cli/cmd/visit_test.go +++ b/client/go/internal/cli/cmd/visit_test.go @@ -47,7 +47,7 @@ func TestQuoteFunc(t *testing.T) { res := quoteArgForUrl(s) if i < 32 || i > 127 { assert.Equal(t, "a+z", res) - } else { + } else if testing.Verbose() { // go test -v fmt.Printf("res %3d => '%s'\n", i, res) } } |