github.com/xeptore/docker-cli@v20.10.14+incompatible/cli/config/config.go (about)

     1  package config
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  	"sync"
    10  
    11  	"github.com/docker/cli/cli/config/configfile"
    12  	"github.com/docker/cli/cli/config/credentials"
    13  	"github.com/docker/cli/cli/config/types"
    14  	"github.com/docker/docker/pkg/homedir"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  const (
    19  	// ConfigFileName is the name of config file
    20  	ConfigFileName = "config.json"
    21  	configFileDir  = ".docker"
    22  	oldConfigfile  = ".dockercfg"
    23  	contextsDir    = "contexts"
    24  )
    25  
    26  var (
    27  	initConfigDir = new(sync.Once)
    28  	configDir     string
    29  	homeDir       string
    30  )
    31  
    32  // resetHomeDir is used in testing to reset the "homeDir" package variable to
    33  // force re-lookup of the home directory between tests.
    34  func resetHomeDir() {
    35  	homeDir = ""
    36  }
    37  
    38  func getHomeDir() string {
    39  	if homeDir == "" {
    40  		homeDir = homedir.Get()
    41  	}
    42  	return homeDir
    43  }
    44  
    45  // resetConfigDir is used in testing to reset the "configDir" package variable
    46  // and its sync.Once to force re-lookup between tests.
    47  func resetConfigDir() {
    48  	configDir = ""
    49  	initConfigDir = new(sync.Once)
    50  }
    51  
    52  func setConfigDir() {
    53  	if configDir != "" {
    54  		return
    55  	}
    56  	configDir = os.Getenv("DOCKER_CONFIG")
    57  	if configDir == "" {
    58  		configDir = filepath.Join(getHomeDir(), configFileDir)
    59  	}
    60  }
    61  
    62  // Dir returns the directory the configuration file is stored in
    63  func Dir() string {
    64  	initConfigDir.Do(setConfigDir)
    65  	return configDir
    66  }
    67  
    68  // ContextStoreDir returns the directory the docker contexts are stored in
    69  func ContextStoreDir() string {
    70  	return filepath.Join(Dir(), contextsDir)
    71  }
    72  
    73  // SetDir sets the directory the configuration file is stored in
    74  func SetDir(dir string) {
    75  	configDir = filepath.Clean(dir)
    76  }
    77  
    78  // Path returns the path to a file relative to the config dir
    79  func Path(p ...string) (string, error) {
    80  	path := filepath.Join(append([]string{Dir()}, p...)...)
    81  	if !strings.HasPrefix(path, Dir()+string(filepath.Separator)) {
    82  		return "", errors.Errorf("path %q is outside of root config directory %q", path, Dir())
    83  	}
    84  	return path, nil
    85  }
    86  
    87  // LegacyLoadFromReader is a convenience function that creates a ConfigFile object from
    88  // a non-nested reader
    89  func LegacyLoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) {
    90  	configFile := configfile.ConfigFile{
    91  		AuthConfigs: make(map[string]types.AuthConfig),
    92  	}
    93  	err := configFile.LegacyLoadFromReader(configData)
    94  	return &configFile, err
    95  }
    96  
    97  // LoadFromReader is a convenience function that creates a ConfigFile object from
    98  // a reader
    99  func LoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) {
   100  	configFile := configfile.ConfigFile{
   101  		AuthConfigs: make(map[string]types.AuthConfig),
   102  	}
   103  	err := configFile.LoadFromReader(configData)
   104  	return &configFile, err
   105  }
   106  
   107  // Load reads the configuration files in the given directory, and sets up
   108  // the auth config information and returns values.
   109  // FIXME: use the internal golang config parser
   110  func Load(configDir string) (*configfile.ConfigFile, error) {
   111  	cfg, _, err := load(configDir)
   112  	return cfg, err
   113  }
   114  
   115  // TODO remove this temporary hack, which is used to warn about the deprecated ~/.dockercfg file
   116  // so we can remove the bool return value and collapse this back into `Load`
   117  func load(configDir string) (*configfile.ConfigFile, bool, error) {
   118  	printLegacyFileWarning := false
   119  
   120  	if configDir == "" {
   121  		configDir = Dir()
   122  	}
   123  
   124  	filename := filepath.Join(configDir, ConfigFileName)
   125  	configFile := configfile.New(filename)
   126  
   127  	// Try happy path first - latest config file
   128  	if file, err := os.Open(filename); err == nil {
   129  		defer file.Close()
   130  		err = configFile.LoadFromReader(file)
   131  		if err != nil {
   132  			err = errors.Wrap(err, filename)
   133  		}
   134  		return configFile, printLegacyFileWarning, err
   135  	} else if !os.IsNotExist(err) {
   136  		// if file is there but we can't stat it for any reason other
   137  		// than it doesn't exist then stop
   138  		return configFile, printLegacyFileWarning, errors.Wrap(err, filename)
   139  	}
   140  
   141  	// Can't find latest config file so check for the old one
   142  	filename = filepath.Join(getHomeDir(), oldConfigfile)
   143  	if file, err := os.Open(filename); err == nil {
   144  		printLegacyFileWarning = true
   145  		defer file.Close()
   146  		if err := configFile.LegacyLoadFromReader(file); err != nil {
   147  			return configFile, printLegacyFileWarning, errors.Wrap(err, filename)
   148  		}
   149  	}
   150  	return configFile, printLegacyFileWarning, nil
   151  }
   152  
   153  // LoadDefaultConfigFile attempts to load the default config file and returns
   154  // an initialized ConfigFile struct if none is found.
   155  func LoadDefaultConfigFile(stderr io.Writer) *configfile.ConfigFile {
   156  	configFile, printLegacyFileWarning, err := load(Dir())
   157  	if err != nil {
   158  		fmt.Fprintf(stderr, "WARNING: Error loading config file: %v\n", err)
   159  	}
   160  	if printLegacyFileWarning {
   161  		_, _ = fmt.Fprintln(stderr, "WARNING: Support for the legacy ~/.dockercfg configuration file and file-format is deprecated and will be removed in an upcoming release")
   162  	}
   163  	if !configFile.ContainsAuth() {
   164  		configFile.CredentialsStore = credentials.DetectDefaultStore(configFile.CredentialsStore)
   165  	}
   166  	return configFile
   167  }