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 }