浏览代码

Refactor config into package

* Move CLI config management into cli/config
* Add ability to save current context
* Remove ability to rename the config file as this was never used

Signed-off-by: Christopher Crone <[email protected]>
Christopher Crone 5 年之前
父节点
当前提交
d46398dbef
共有 6 个文件被更改,包括 165 次插入59 次删除
  1. 96 0
      cli/config/config.go
  2. 23 31
      cli/config/flags.go
  3. 34 0
      cli/config/keys.go
  4. 7 8
      cli/main.go
  5. 5 19
      context/flags.go
  6. 0 1
      go.mod

+ 96 - 0
cli/config/config.go

@@ -0,0 +1,96 @@
+/*
+	Copyright (c) 2020 Docker Inc.
+
+	Permission is hereby granted, free of charge, to any person
+	obtaining a copy of this software and associated documentation
+	files (the "Software"), to deal in the Software without
+	restriction, including without limitation the rights to use, copy,
+	modify, merge, publish, distribute, sublicense, and/or sell copies
+	of the Software, and to permit persons to whom the Software is
+	furnished to do so, subject to the following conditions:
+
+	The above copyright notice and this permission notice shall be
+	included in all copies or substantial portions of the Software.
+
+	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+	EXPRESS OR IMPLIED,
+	INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+	IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+	HOLDERS BE LIABLE FOR ANY CLAIM,
+	DAMAGES OR OTHER LIABILITY,
+	WHETHER IN AN ACTION OF CONTRACT,
+	TORT OR OTHERWISE,
+	ARISING FROM, OUT OF OR IN CONNECTION WITH
+	THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package config
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+
+	"github.com/pkg/errors"
+)
+
+// LoadFile loads the docker configuration
+func LoadFile(dir string) (*File, error) {
+	f := &File{}
+	err := loadFile(configFilePath(dir), &f)
+	if err != nil {
+		return nil, err
+	}
+	return f, nil
+}
+
+// WriteCurrentContext writes the selected current context to the Docker
+// configuration file. Note, the validity of the context is not checked.
+func WriteCurrentContext(dir string, name string) error {
+	m := map[string]interface{}{}
+	path := configFilePath(dir)
+	err := loadFile(path, &m)
+	if err != nil {
+		return err
+	}
+	// Match existing CLI behavior
+	if name == "default" {
+		delete(m, currentContextKey)
+	} else {
+		m[currentContextKey] = name
+	}
+	return writeFile(path, m)
+}
+
+func writeFile(path string, content map[string]interface{}) error {
+	d, err := json.MarshalIndent(content, "", "\t")
+	if err != nil {
+		return errors.Wrap(err, "unable to marshal config")
+	}
+	err = ioutil.WriteFile(path, d, 0644)
+	return errors.Wrap(err, "unable to write config file")
+}
+
+func loadFile(path string, dest interface{}) error {
+	data, err := ioutil.ReadFile(path)
+	if err != nil {
+		if os.IsNotExist(err) {
+			// Not an error if there is no config, we're just using defaults
+			return nil
+		}
+		return errors.Wrap(err, "unable to read config file")
+	}
+	err = json.Unmarshal(data, dest)
+	return errors.Wrap(err, "unable to unmarshal config")
+}
+
+func configFilePath(dir string) string {
+	return filepath.Join(dir, ConfigFileName)
+}
+
+// File contains the current context from the docker configuration file
+type File struct {
+	CurrentContext string `json:"currentContext,omitempty"`
+}

+ 23 - 31
context/config.go → cli/config/flags.go

@@ -25,44 +25,36 @@
 	THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
-package context
+package config
 
 import (
-	"encoding/json"
-	"fmt"
 	"os"
 	"path/filepath"
+
+	"github.com/spf13/pflag"
+)
+
+const (
+	// ConfigFileName is the name of config file
+	ConfigFileName = "config.json"
+	// ConfigFileDir is the default folder where the config file is stored
+	ConfigFileDir = ".docker"
+	// ConfigFlagName is the name of the config flag
+	ConfigFlagName = "config"
 )
 
-// LoadConfigFile loads the docker configuration
-func LoadConfigFile(configDir string, configFileName string) (*ConfigFile, error) {
-	filename := filepath.Join(configDir, configFileName)
-	configFile := &ConfigFile{
-		Filename: filename,
-	}
+// ConfigFlags are the global CLI flags
+// nolint stutter
+type ConfigFlags struct {
+	Config string
+}
 
-	if _, err := os.Stat(filename); err == nil {
-		file, err := os.Open(filename)
-		if err != nil {
-			return nil, fmt.Errorf("can't read %s: %w", filename, err)
-		}
-		// nolint errcheck
-		defer file.Close()
-		err = json.NewDecoder(file).Decode(&configFile)
-		if err != nil {
-			err = fmt.Errorf("can't read %s: %w", filename, err)
-		}
-		return configFile, err
-	} else if !os.IsNotExist(err) {
-		// if file is there but we can't stat it for any reason other
-		// than it doesn't exist then stop
-		return nil, fmt.Errorf("can't read %s: %w", filename, err)
-	}
-	return configFile, nil
+// AddConfigFlags adds persistent (global) flags
+func (c *ConfigFlags) AddConfigFlags(flags *pflag.FlagSet) {
+	flags.StringVar(&c.Config, ConfigFlagName, filepath.Join(home(), ConfigFileDir), "Location of the client config files `DIRECTORY`")
 }
 
-// ConfigFile contains the current context from the docker configuration file
-type ConfigFile struct {
-	Filename       string `json:"-"` // Note: for internal use only
-	CurrentContext string `json:"currentContext,omitempty"`
+func home() string {
+	home, _ := os.UserHomeDir()
+	return home
 }

+ 34 - 0
cli/config/keys.go

@@ -0,0 +1,34 @@
+/*
+	Copyright (c) 2020 Docker Inc.
+
+	Permission is hereby granted, free of charge, to any person
+	obtaining a copy of this software and associated documentation
+	files (the "Software"), to deal in the Software without
+	restriction, including without limitation the rights to use, copy,
+	modify, merge, publish, distribute, sublicense, and/or sell copies
+	of the Software, and to permit persons to whom the Software is
+	furnished to do so, subject to the following conditions:
+
+	The above copyright notice and this permission notice shall be
+	included in all copies or substantial portions of the Software.
+
+	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+	EXPRESS OR IMPLIED,
+	INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+	IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+	HOLDERS BE LIABLE FOR ANY CLAIM,
+	DAMAGES OR OTHER LIABILITY,
+	WHETHER IN AN ACTION OF CONTRACT,
+	TORT OR OTHERWISE,
+	ARISING FROM, OUT OF OR IN CONNECTION WITH
+	THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package config
+
+const (
+	// currentContextKey is the key used in the Docker config file to set the
+	// default context
+	currentContextKey = "currentContext"
+)

+ 7 - 8
cli/main.go

@@ -48,6 +48,7 @@ import (
 	"github.com/docker/api/cli/cmd"
 	"github.com/docker/api/cli/cmd/compose"
 	"github.com/docker/api/cli/cmd/run"
+	cliconfig "github.com/docker/api/cli/config"
 	apicontext "github.com/docker/api/context"
 	"github.com/docker/api/context/store"
 )
@@ -57,7 +58,8 @@ var (
 )
 
 type mainOpts struct {
-	apicontext.Flags
+	apicontext.ContextFlags
+	cliconfig.ConfigFlags
 	debug bool
 }
 
@@ -123,7 +125,8 @@ func main() {
 	})
 
 	root.PersistentFlags().BoolVarP(&opts.debug, "debug", "d", false, "enable debug output in the logs")
-	opts.AddFlags(root.PersistentFlags())
+	opts.AddConfigFlags(root.PersistentFlags())
+	opts.AddContextFlags(root.PersistentFlags())
 
 	// populate the opts with the global flags
 	_ = root.PersistentFlags().Parse(os.Args[1:])
@@ -134,7 +137,7 @@ func main() {
 	ctx, cancel := newSigContext()
 	defer cancel()
 
-	config, err := apicontext.LoadConfigFile(opts.Config, "config.json")
+	config, err := cliconfig.LoadFile(opts.Config)
 	if err != nil {
 		logrus.Fatal("unable ot find configuration")
 	}
@@ -146,15 +149,11 @@ func main() {
 		currentContext = "default"
 	}
 
-	ctx = apicontext.WithCurrentContext(ctx, currentContext)
-	if err != nil {
-		logrus.Fatal(err)
-	}
-
 	s, err := store.New(store.WithRoot(opts.Config))
 	if err != nil {
 		logrus.Fatal(err)
 	}
+	ctx = apicontext.WithCurrentContext(ctx, currentContext)
 	ctx = store.WithContextStore(ctx, s)
 
 	if err = root.ExecuteContext(ctx); err != nil {

+ 5 - 19
context/flags.go

@@ -29,31 +29,17 @@ package context
 
 import (
 	"os"
-	"path/filepath"
 
-	"github.com/mitchellh/go-homedir"
 	"github.com/spf13/pflag"
 )
 
-const (
-	// ConfigFileName is the name of config file
-	ConfigFileName = "config.json"
-	configFileDir  = ".docker"
-)
-
-// Flags are the global cli flags
-type Flags struct {
-	Config  string
+// ContextFlags are the global CLI flags
+// nolint stutter
+type ContextFlags struct {
 	Context string
 }
 
-// AddFlags adds persistent (global) flags
-func (c *Flags) AddFlags(flags *pflag.FlagSet) {
-	flags.StringVar(&c.Config, "config", filepath.Join(home(), configFileDir), "Location of the client config files `DIRECTORY`")
+// AddContextFlags adds persistent (global) flags
+func (c *ContextFlags) AddContextFlags(flags *pflag.FlagSet) {
 	flags.StringVarP(&c.Context, "context", "c", os.Getenv("DOCKER_CONTEXT"), "context")
 }
-
-func home() string {
-	home, _ := homedir.Dir()
-	return home
-}

+ 0 - 1
go.mod

@@ -23,7 +23,6 @@ require (
 	github.com/gorilla/mux v1.7.4 // indirect
 	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
 	github.com/hashicorp/go-multierror v1.1.0
-	github.com/mitchellh/go-homedir v1.1.0
 	github.com/morikuni/aec v1.0.0 // indirect
 	github.com/onsi/gomega v1.9.0
 	github.com/opencontainers/go-digest v1.0.0-rc1