diff --git a/README.md b/README.md index 822af986..f37caafc 100644 --- a/README.md +++ b/README.md @@ -58,14 +58,6 @@ This file can exist anywhere in the file system, and can be used with the `--con $ clc -c test/config.yaml ``` -If there is a `config.yaml` in the same directory with the CLC binary and the configuration was not explicitly set, CLC tries to load that configuration file: -``` -$ ls -lh -total 17M --rwxrwxr-x 1 yuce yuce 17M Nov 26 23:11 clc* --rw------- 1 yuce yuce 200 Nov 26 23:12 config.yaml -``` - `configs` directory in `$CLC_HOME` is special, it contains all the configurations known to CLC. Known configurations can be directly specified by their names, instead of the full path. `clc config list` command lists the configurations known to CLC: @@ -80,6 +72,9 @@ $ clc -c pr-3066 ``` If no configuration is specified, the `default` configuration is used if it exists. +The name of the default configuration may be overriden using the `CLC_CONFIG` environment variable. + +If there's only a single named configuration, then it is used if the configuration is not specified with `-c`/`--config`. #### Configuration format diff --git a/clc/config/config_test.go b/clc/config/config_it_test.go similarity index 95% rename from clc/config/config_test.go rename to clc/config/config_it_test.go index 26fa5c35..043ebb42 100644 --- a/clc/config/config_test.go +++ b/clc/config/config_it_test.go @@ -2,6 +2,7 @@ package config_test import ( "bytes" + "context" "crypto/tls" "fmt" "os" @@ -14,6 +15,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/hazelcast/hazelcast-commandline-client/internal/it" "github.com/hazelcast/hazelcast-commandline-client/internal/serialization" "github.com/hazelcast/hazelcast-commandline-client/internal/types" @@ -298,6 +300,18 @@ func TestConvertKeyValuesToMap(t *testing.T) { assert.Equal(t, target, m) } +func TestSingleConfig(t *testing.T) { + tcx := it.TestContext{T: t} + tcx.Tester(func(tcx it.TestContext) { + p := MustValue(config.NewWizardProvider("")) + ctx := context.Background() + ec := it.NewExecuteContext(nil) + cfg, err := p.ClientConfig(ctx, ec) + assert.NoError(t, err) + assert.Equal(t, []string{"localhost:10000"}, cfg.Cluster.Network.Addresses) + }) +} + func userHostName() string { u := MustValue(user.Current()) host := MustValue(os.Hostname()) diff --git a/clc/config/file_provider.go b/clc/config/file_provider.go index 4fe8628c..4371f8e8 100644 --- a/clc/config/file_provider.go +++ b/clc/config/file_provider.go @@ -53,11 +53,11 @@ func NewFileProvider(path string) (*FileProvider, error) { func (p *FileProvider) load(path string) error { path = paths.ResolveConfigPath(path) + if path == "" { + // there is no default config, user will be prompted for config later + return nil + } if !paths.Exists(path) { - if path == "" { - // there is no default config, user will be prompted for config later - return nil - } return fmt.Errorf("configuration does not exist %s: %w", path, os.ErrNotExist) } p.path = path diff --git a/clc/config/wizard_provider.go b/clc/config/wizard_provider.go index 71b395f4..06f82c6b 100644 --- a/clc/config/wizard_provider.go +++ b/clc/config/wizard_provider.go @@ -11,7 +11,6 @@ import ( "github.com/spf13/pflag" "github.com/hazelcast/hazelcast-commandline-client/clc" - "github.com/hazelcast/hazelcast-commandline-client/clc/ux/stage" "github.com/hazelcast/hazelcast-commandline-client/internal/terminal" "github.com/hazelcast/hazelcast-commandline-client/clc/config/wizard" @@ -64,57 +63,50 @@ func maybeUnwrapStdout(ec plug.ExecContext) any { func (p *WizardProvider) ClientConfig(ctx context.Context, ec plug.ExecContext) (hazelcast.Config, error) { cfg, err := p.fp.Load().ClientConfig(ctx, ec) + if err == nil { + // note that comparing err to nil + return cfg, nil + } + var configName string + if !errors.Is(err, clcerrors.ErrNoClusterConfig) { + return hazelcast.Config{}, err + } + cs, err := FindAll(paths.Configs()) if err != nil { + if errors.Is(err, os.ErrNotExist) { + return hazelcast.Config{}, clcerrors.ErrNoClusterConfig + } + } + if len(cs) == 0 { + return hazelcast.Config{}, clcerrors.ErrNoClusterConfig + } + if len(cs) == 1 { + configName = cs[0] + } + if configName == "" { if terminal.IsPipe(maybeUnwrapStdout(ec)) { return hazelcast.Config{}, errNoConfig } // ask the config to the user - name, err := p.runWizard(ctx, ec) + configName, err = p.runWizard(cs) if err != nil { return hazelcast.Config{}, err } - fp, err := NewFileProvider(name) - if err != nil { - return cfg, err - } - config, err := fp.ClientConfig(ctx, ec) - if err != nil { - return hazelcast.Config{}, err - } - p.fp.Store(fp) - return config, nil } - return cfg, nil -} - -func (p *WizardProvider) runWizard(ctx context.Context, ec plug.ExecContext) (string, error) { - cs, err := FindAll(paths.Configs()) + fp, err := NewFileProvider(configName) if err != nil { - if errors.Is(err, os.ErrNotExist) { - err = os.MkdirAll(paths.Configs(), 0700) - } - if err != nil { - return "", err - } + return cfg, err } - if len(cs) == 0 { - m := wizard.InitialModel() - mv, err := tea.NewProgram(m).Run() - if err != nil { - return "", err - } - if mv.View() == "" { - return "", clcerrors.ErrNoClusterConfig - } - args := m.GetInputs() - stages := MakeImportStages(ec, args[0]) - _, err = stage.Execute(ctx, ec, args[1], stage.NewFixedProvider(stages...)) - if err != nil { - return "", err - } - return args[0], nil + config, err := fp.ClientConfig(ctx, ec) + if err != nil { + return hazelcast.Config{}, err } - m := wizard.InitializeList(cs) + p.fp.Store(fp) + return config, nil +} + +func (p *WizardProvider) runWizard(configNames []string) (string, error) { + m := wizard.InitializeList(configNames) model, err := tea.NewProgram(m).Run() if err != nil { return "", err diff --git a/docs/modules/ROOT/pages/configuration.adoc b/docs/modules/ROOT/pages/configuration.adoc index 3601d5fd..2077147a 100644 --- a/docs/modules/ROOT/pages/configuration.adoc +++ b/docs/modules/ROOT/pages/configuration.adoc @@ -10,17 +10,6 @@ This file can exist anywhere in the file system, and can be used with the `--con clc -c test/config.yaml ---- -//TIP: If you try to run an operation that requires a client connection before you have added any configuration, CLC will prompt the configuration wizard to import a {hazelcast-cloud} configuration. For details, see xref:config-wizard.adoc[CLC Configuration Wizard]. - -If there is a `config.yaml` in the same directory with the CLC binary and the configuration was not explicitly set, CLC tries to load that configuration file: -[source, bash] ----- -ls -lh -total 17M --rwxrwxr-x 1 yuce yuce 17M Nov 26 23:11 clc* --rw------- 1 yuce yuce 200 Nov 26 23:12 config.yaml ----- - `configs` directory in `$CLC_HOME` is special, it contains all the configurations known to CLC. You can use the `clc home` command in order to see where `$CLC_HOME` is: [source, bash] ---- @@ -42,6 +31,9 @@ $ clc -c pr-3066 ---- If no configuration is specified, the `default` configuration is used. +The name of the default configuration may be overriden using the `CLC_CONFIG` environment variable. + +If there's only a single named configuration, then it is used if the configuration is not specified with `-c`/`--config`. == CLC Configuration with Command-Line Parameters