aboutsummaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2023-04-05 15:46:27 +0200
committerGitHub <noreply@github.com>2023-04-05 15:46:27 +0200
commit2f2b57afc88b58b3bfde83a6c3313717db4aeb39 (patch)
tree78be48695102728c1fac8870be9228c437b375da /client
parent7f4d68f7da482bbc24ed4914be7931f0f9e52444 (diff)
parentc6cd74032d58b2ee5afd6e3d78f748fabc0b9d04 (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.go85
-rw-r--r--client/go/internal/cli/cmd/config_test.go8
-rw-r--r--client/go/internal/cli/cmd/deploy_test.go3
-rw-r--r--client/go/internal/cli/cmd/root.go10
-rw-r--r--client/go/internal/cli/cmd/visit_test.go2
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)
}
}