From f87d7ed8647065a09a299fa078e59e8cbc794ca2 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 29 Jul 2022 11:58:37 +0200 Subject: [PATCH] context use: don't create/update config file and directories if not needed Avoid updating the config-file if nothing changed. This also prevents creating the file and config-directory if the default is used and no config-file existed yet. `config.Save()` performs various steps (creating the directory, updating or copying permissions, etc etc), which are not needed if the defaults are used; https://github.com/docker/cli/blob/a445d97c2536f0de37469d0ea9881288d6c49cbf/cli/config/configfile/file.go#L135-L176 Signed-off-by: Sebastiaan van Stijn --- cli/command/context/use.go | 11 ++++++++--- cli/command/context/use_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/cli/command/context/use.go b/cli/command/context/use.go index cba4f92dad..c24a0c6ecb 100644 --- a/cli/command/context/use.go +++ b/cli/command/context/use.go @@ -37,9 +37,14 @@ func RunUse(dockerCli command.Cli, name string) error { configValue = name } dockerConfig := dockerCli.ConfigFile() - dockerConfig.CurrentContext = configValue - if err := dockerConfig.Save(); err != nil { - return err + // Avoid updating the config-file if nothing changed. This also prevents + // creating the file and config-directory if the default is used and + // no config-file existed yet. + if dockerConfig.CurrentContext != configValue { + dockerConfig.CurrentContext = configValue + if err := dockerConfig.Save(); err != nil { + return err + } } fmt.Fprintln(dockerCli.Out(), name) fmt.Fprintf(dockerCli.Err(), "Current context is now %q\n", name) diff --git a/cli/command/context/use_test.go b/cli/command/context/use_test.go index 3053cc03b2..13be26425f 100644 --- a/cli/command/context/use_test.go +++ b/cli/command/context/use_test.go @@ -2,6 +2,9 @@ package context import ( "bytes" + "errors" + "io" + "os" "path/filepath" "testing" @@ -10,6 +13,7 @@ import ( "github.com/docker/cli/cli/config/configfile" "github.com/docker/cli/cli/context/store" "github.com/docker/cli/cli/flags" + "github.com/docker/docker/pkg/homedir" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) @@ -46,6 +50,34 @@ func TestUseNoExist(t *testing.T) { assert.Check(t, store.IsErrContextDoesNotExist(err)) } +// TestUseDefaultWithoutConfigFile verifies that the CLI does not create +// the default config file and directory when using the default context. +func TestUseDefaultWithoutConfigFile(t *testing.T) { + // We must use a temporary home-directory, because this test covers + // the _default_ configuration file. If we specify a custom configuration + // file, the CLI produces an error if the file doesn't exist. + tmpHomeDir := t.TempDir() + t.Setenv(homedir.Key(), tmpHomeDir) + configDir := filepath.Join(tmpHomeDir, ".docker") + configFilePath := filepath.Join(configDir, "config.json") + + // Verify config-dir and -file don't exist before + _, err := os.Stat(configDir) + assert.Check(t, errors.Is(err, os.ErrNotExist)) + _, err = os.Stat(configFilePath) + assert.Check(t, errors.Is(err, os.ErrNotExist)) + + cli, err := command.NewDockerCli(command.WithCombinedStreams(io.Discard)) + assert.NilError(t, err) + assert.NilError(t, newUseCommand(cli).RunE(nil, []string{"default"})) + + // Verify config-dir and -file don't exist after + _, err = os.Stat(configDir) + assert.Check(t, errors.Is(err, os.ErrNotExist)) + _, err = os.Stat(configFilePath) + assert.Check(t, errors.Is(err, os.ErrNotExist)) +} + func TestUseHostOverride(t *testing.T) { t.Setenv("DOCKER_HOST", "tcp://ed:2375/")