From 30e3620eaea88cf33fd7deb8c88359469c27b3f7 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Thu, 21 Apr 2016 18:37:08 -0400 Subject: [PATCH] Refactor cliconfig so that the default constructor can exist in the package. Signed-off-by: Daniel Nephin --- api/client/cli.go | 3 +- api/client/login.go | 12 +- cliconfig/config.go | 196 ++--------------------- cliconfig/config_test.go | 32 +--- cliconfig/configfile/file.go | 177 ++++++++++++++++++++ cliconfig/configfile/file_test.go | 27 ++++ cliconfig/credentials/default_store.go | 4 +- cliconfig/credentials/file_store.go | 6 +- cliconfig/credentials/file_store_test.go | 3 +- cliconfig/credentials/native_store.go | 4 +- 10 files changed, 243 insertions(+), 221 deletions(-) create mode 100644 cliconfig/configfile/file.go create mode 100644 cliconfig/configfile/file_test.go diff --git a/api/client/cli.go b/api/client/cli.go index ed0a75dc81..653d6b43ce 100644 --- a/api/client/cli.go +++ b/api/client/cli.go @@ -11,6 +11,7 @@ import ( "github.com/docker/docker/api" cliflags "github.com/docker/docker/cli/flags" "github.com/docker/docker/cliconfig" + "github.com/docker/docker/cliconfig/configfile" "github.com/docker/docker/cliconfig/credentials" "github.com/docker/docker/dockerversion" "github.com/docker/docker/opts" @@ -27,7 +28,7 @@ type DockerCli struct { init func() error // configFile has the client configuration file - configFile *cliconfig.ConfigFile + configFile *configfile.ConfigFile // in holds the input stream and closer (io.ReadCloser) for the client. in io.ReadCloser // out holds the output stream (io.Writer) for the client. diff --git a/api/client/login.go b/api/client/login.go index a772348c8d..0bba8d2909 100644 --- a/api/client/login.go +++ b/api/client/login.go @@ -11,7 +11,7 @@ import ( "golang.org/x/net/context" Cli "github.com/docker/docker/cli" - "github.com/docker/docker/cliconfig" + "github.com/docker/docker/cliconfig/configfile" "github.com/docker/docker/cliconfig/credentials" flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/term" @@ -143,33 +143,33 @@ func readInput(in io.Reader, out io.Writer) string { // getCredentials loads the user credentials from a credentials store. // The store is determined by the config file settings. -func getCredentials(c *cliconfig.ConfigFile, serverAddress string) (types.AuthConfig, error) { +func getCredentials(c *configfile.ConfigFile, serverAddress string) (types.AuthConfig, error) { s := loadCredentialsStore(c) return s.Get(serverAddress) } -func getAllCredentials(c *cliconfig.ConfigFile) (map[string]types.AuthConfig, error) { +func getAllCredentials(c *configfile.ConfigFile) (map[string]types.AuthConfig, error) { s := loadCredentialsStore(c) return s.GetAll() } // storeCredentials saves the user credentials in a credentials store. // The store is determined by the config file settings. -func storeCredentials(c *cliconfig.ConfigFile, auth types.AuthConfig) error { +func storeCredentials(c *configfile.ConfigFile, auth types.AuthConfig) error { s := loadCredentialsStore(c) return s.Store(auth) } // eraseCredentials removes the user credentials from a credentials store. // The store is determined by the config file settings. -func eraseCredentials(c *cliconfig.ConfigFile, serverAddress string) error { +func eraseCredentials(c *configfile.ConfigFile, serverAddress string) error { s := loadCredentialsStore(c) return s.Erase(serverAddress) } // loadCredentialsStore initializes a new credentials store based // in the settings provided in the configuration file. -func loadCredentialsStore(c *cliconfig.ConfigFile) credentials.Store { +func loadCredentialsStore(c *configfile.ConfigFile) credentials.Store { if c.CredentialsStore != "" { return credentials.NewNativeStore(c) } diff --git a/cliconfig/config.go b/cliconfig/config.go index d42366c23f..a5a1303943 100644 --- a/cliconfig/config.go +++ b/cliconfig/config.go @@ -1,15 +1,12 @@ package cliconfig import ( - "encoding/base64" - "encoding/json" "fmt" "io" - "io/ioutil" "os" "path/filepath" - "strings" + "github.com/docker/docker/cliconfig/configfile" "github.com/docker/docker/pkg/homedir" "github.com/docker/engine-api/types" ) @@ -46,94 +43,19 @@ func SetConfigDir(dir string) { configDir = dir } -// ConfigFile ~/.docker/config.json file info -type ConfigFile struct { - AuthConfigs map[string]types.AuthConfig `json:"auths"` - HTTPHeaders map[string]string `json:"HttpHeaders,omitempty"` - PsFormat string `json:"psFormat,omitempty"` - ImagesFormat string `json:"imagesFormat,omitempty"` - DetachKeys string `json:"detachKeys,omitempty"` - CredentialsStore string `json:"credsStore,omitempty"` - filename string // Note: not serialized - for internal use only -} - // NewConfigFile initializes an empty configuration file for the given filename 'fn' -func NewConfigFile(fn string) *ConfigFile { - return &ConfigFile{ +func NewConfigFile(fn string) *configfile.ConfigFile { + return &configfile.ConfigFile{ AuthConfigs: make(map[string]types.AuthConfig), HTTPHeaders: make(map[string]string), - filename: fn, + Filename: fn, } } -// LegacyLoadFromReader reads the non-nested configuration data given and sets up the -// auth config information with given directory and populates the receiver object -func (configFile *ConfigFile) LegacyLoadFromReader(configData io.Reader) error { - b, err := ioutil.ReadAll(configData) - if err != nil { - return err - } - - if err := json.Unmarshal(b, &configFile.AuthConfigs); err != nil { - arr := strings.Split(string(b), "\n") - if len(arr) < 2 { - return fmt.Errorf("The Auth config file is empty") - } - authConfig := types.AuthConfig{} - origAuth := strings.Split(arr[0], " = ") - if len(origAuth) != 2 { - return fmt.Errorf("Invalid Auth config file") - } - authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1]) - if err != nil { - return err - } - authConfig.ServerAddress = defaultIndexserver - configFile.AuthConfigs[defaultIndexserver] = authConfig - } else { - for k, authConfig := range configFile.AuthConfigs { - authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth) - if err != nil { - return err - } - authConfig.Auth = "" - authConfig.ServerAddress = k - configFile.AuthConfigs[k] = authConfig - } - } - return nil -} - -// LoadFromReader reads the configuration data given and sets up the auth config -// information with given directory and populates the receiver object -func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error { - if err := json.NewDecoder(configData).Decode(&configFile); err != nil { - return err - } - var err error - for addr, ac := range configFile.AuthConfigs { - ac.Username, ac.Password, err = decodeAuth(ac.Auth) - if err != nil { - return err - } - ac.Auth = "" - ac.ServerAddress = addr - configFile.AuthConfigs[addr] = ac - } - return nil -} - -// ContainsAuth returns whether there is authentication configured -// in this file or not. -func (configFile *ConfigFile) ContainsAuth() bool { - return configFile.CredentialsStore != "" || - (configFile.AuthConfigs != nil && len(configFile.AuthConfigs) > 0) -} - // LegacyLoadFromReader is a convenience function that creates a ConfigFile object from // a non-nested reader -func LegacyLoadFromReader(configData io.Reader) (*ConfigFile, error) { - configFile := ConfigFile{ +func LegacyLoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) { + configFile := configfile.ConfigFile{ AuthConfigs: make(map[string]types.AuthConfig), } err := configFile.LegacyLoadFromReader(configData) @@ -142,8 +64,8 @@ func LegacyLoadFromReader(configData io.Reader) (*ConfigFile, error) { // LoadFromReader is a convenience function that creates a ConfigFile object from // a reader -func LoadFromReader(configData io.Reader) (*ConfigFile, error) { - configFile := ConfigFile{ +func LoadFromReader(configData io.Reader) (*configfile.ConfigFile, error) { + configFile := configfile.ConfigFile{ AuthConfigs: make(map[string]types.AuthConfig), } err := configFile.LoadFromReader(configData) @@ -153,32 +75,32 @@ func LoadFromReader(configData io.Reader) (*ConfigFile, error) { // Load reads the configuration files in the given directory, and sets up // the auth config information and returns values. // FIXME: use the internal golang config parser -func Load(configDir string) (*ConfigFile, error) { +func Load(configDir string) (*configfile.ConfigFile, error) { if configDir == "" { configDir = ConfigDir() } - configFile := ConfigFile{ + configFile := configfile.ConfigFile{ AuthConfigs: make(map[string]types.AuthConfig), - filename: filepath.Join(configDir, ConfigFileName), + Filename: filepath.Join(configDir, ConfigFileName), } // Try happy path first - latest config file - if _, err := os.Stat(configFile.filename); err == nil { - file, err := os.Open(configFile.filename) + if _, err := os.Stat(configFile.Filename); err == nil { + file, err := os.Open(configFile.Filename) if err != nil { - return &configFile, fmt.Errorf("%s - %v", configFile.filename, err) + return &configFile, fmt.Errorf("%s - %v", configFile.Filename, err) } defer file.Close() err = configFile.LoadFromReader(file) if err != nil { - err = fmt.Errorf("%s - %v", configFile.filename, err) + err = fmt.Errorf("%s - %v", configFile.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 &configFile, fmt.Errorf("%s - %v", configFile.filename, err) + return &configFile, fmt.Errorf("%s - %v", configFile.Filename, err) } // Can't find latest config file so check for the old one @@ -201,89 +123,3 @@ func Load(configDir string) (*ConfigFile, error) { } return &configFile, nil } - -// SaveToWriter encodes and writes out all the authorization information to -// the given writer -func (configFile *ConfigFile) SaveToWriter(writer io.Writer) error { - // Encode sensitive data into a new/temp struct - tmpAuthConfigs := make(map[string]types.AuthConfig, len(configFile.AuthConfigs)) - for k, authConfig := range configFile.AuthConfigs { - authCopy := authConfig - // encode and save the authstring, while blanking out the original fields - authCopy.Auth = encodeAuth(&authCopy) - authCopy.Username = "" - authCopy.Password = "" - authCopy.ServerAddress = "" - tmpAuthConfigs[k] = authCopy - } - - saveAuthConfigs := configFile.AuthConfigs - configFile.AuthConfigs = tmpAuthConfigs - defer func() { configFile.AuthConfigs = saveAuthConfigs }() - - data, err := json.MarshalIndent(configFile, "", "\t") - if err != nil { - return err - } - _, err = writer.Write(data) - return err -} - -// Save encodes and writes out all the authorization information -func (configFile *ConfigFile) Save() error { - if configFile.Filename() == "" { - return fmt.Errorf("Can't save config with empty filename") - } - - if err := os.MkdirAll(filepath.Dir(configFile.filename), 0700); err != nil { - return err - } - f, err := os.OpenFile(configFile.filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) - if err != nil { - return err - } - defer f.Close() - return configFile.SaveToWriter(f) -} - -// Filename returns the name of the configuration file -func (configFile *ConfigFile) Filename() string { - return configFile.filename -} - -// encodeAuth creates a base64 encoded string to containing authorization information -func encodeAuth(authConfig *types.AuthConfig) string { - if authConfig.Username == "" && authConfig.Password == "" { - return "" - } - - authStr := authConfig.Username + ":" + authConfig.Password - msg := []byte(authStr) - encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg))) - base64.StdEncoding.Encode(encoded, msg) - return string(encoded) -} - -// decodeAuth decodes a base64 encoded string and returns username and password -func decodeAuth(authStr string) (string, string, error) { - if authStr == "" { - return "", "", nil - } - - decLen := base64.StdEncoding.DecodedLen(len(authStr)) - decoded := make([]byte, decLen) - authByte := []byte(authStr) - n, err := base64.StdEncoding.Decode(decoded, authByte) - if err != nil { - return "", "", err - } - if n > decLen { - return "", "", fmt.Errorf("Something went wrong decoding auth config") - } - arr := strings.SplitN(string(decoded), ":", 2) - if len(arr) != 2 { - return "", "", fmt.Errorf("Invalid auth configuration file") - } - password := strings.Trim(arr[1], "\x00") - return arr[0], password, nil -} diff --git a/cliconfig/config_test.go b/cliconfig/config_test.go index 30c1777007..78b360cc2c 100644 --- a/cliconfig/config_test.go +++ b/cliconfig/config_test.go @@ -7,8 +7,8 @@ import ( "strings" "testing" + "github.com/docker/docker/cliconfig/configfile" "github.com/docker/docker/pkg/homedir" - "github.com/docker/engine-api/types" ) func TestEmptyConfigDir(t *testing.T) { @@ -26,8 +26,8 @@ func TestEmptyConfigDir(t *testing.T) { } expectedConfigFilename := filepath.Join(tmpHome, ConfigFileName) - if config.Filename() != expectedConfigFilename { - t.Fatalf("Expected config filename %s, got %s", expectedConfigFilename, config.Filename()) + if config.Filename != expectedConfigFilename { + t.Fatalf("Expected config filename %s, got %s", expectedConfigFilename, config.Filename) } // Now save it and make sure it shows up in new form @@ -377,7 +377,7 @@ func TestJsonWithPsFormat(t *testing.T) { } // Save it and make sure it shows up in new form -func saveConfigAndValidateNewFormat(t *testing.T, config *ConfigFile, homeFolder string) string { +func saveConfigAndValidateNewFormat(t *testing.T, config *configfile.ConfigFile, homeFolder string) string { if err := config.Save(); err != nil { t.Fatalf("Failed to save: %q", err) } @@ -415,8 +415,8 @@ func TestConfigFile(t *testing.T) { configFilename := "configFilename" configFile := NewConfigFile(configFilename) - if configFile.Filename() != configFilename { - t.Fatalf("Expected %s, got %s", configFilename, configFile.Filename()) + if configFile.Filename != configFilename { + t.Fatalf("Expected %s, got %s", configFilename, configFile.Filename) } } @@ -543,23 +543,3 @@ func TestLegacyJsonSaveWithNoFile(t *testing.T) { t.Fatalf("Should have save in new form: \n%s\n not \n%s", string(buf), expConfStr) } } - -func TestEncodeAuth(t *testing.T) { - newAuthConfig := &types.AuthConfig{Username: "ken", Password: "test"} - authStr := encodeAuth(newAuthConfig) - decAuthConfig := &types.AuthConfig{} - var err error - decAuthConfig.Username, decAuthConfig.Password, err = decodeAuth(authStr) - if err != nil { - t.Fatal(err) - } - if newAuthConfig.Username != decAuthConfig.Username { - t.Fatal("Encode Username doesn't match decoded Username") - } - if newAuthConfig.Password != decAuthConfig.Password { - t.Fatal("Encode Password doesn't match decoded Password") - } - if authStr != "a2VuOnRlc3Q=" { - t.Fatal("AuthString encoding isn't correct.") - } -} diff --git a/cliconfig/configfile/file.go b/cliconfig/configfile/file.go new file mode 100644 index 0000000000..7c94e27dce --- /dev/null +++ b/cliconfig/configfile/file.go @@ -0,0 +1,177 @@ +package configfile + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/docker/engine-api/types" +) + +const ( + // This constant is only used for really old config files when the + // URL wasn't saved as part of the config file and it was just + // assumed to be this value. + defaultIndexserver = "https://index.docker.io/v1/" +) + +// ConfigFile ~/.docker/config.json file info +type ConfigFile struct { + AuthConfigs map[string]types.AuthConfig `json:"auths"` + HTTPHeaders map[string]string `json:"HttpHeaders,omitempty"` + PsFormat string `json:"psFormat,omitempty"` + ImagesFormat string `json:"imagesFormat,omitempty"` + DetachKeys string `json:"detachKeys,omitempty"` + CredentialsStore string `json:"credsStore,omitempty"` + Filename string `json:"-"` // Note: for internal use only +} + +// LegacyLoadFromReader reads the non-nested configuration data given and sets up the +// auth config information with given directory and populates the receiver object +func (configFile *ConfigFile) LegacyLoadFromReader(configData io.Reader) error { + b, err := ioutil.ReadAll(configData) + if err != nil { + return err + } + + if err := json.Unmarshal(b, &configFile.AuthConfigs); err != nil { + arr := strings.Split(string(b), "\n") + if len(arr) < 2 { + return fmt.Errorf("The Auth config file is empty") + } + authConfig := types.AuthConfig{} + origAuth := strings.Split(arr[0], " = ") + if len(origAuth) != 2 { + return fmt.Errorf("Invalid Auth config file") + } + authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1]) + if err != nil { + return err + } + authConfig.ServerAddress = defaultIndexserver + configFile.AuthConfigs[defaultIndexserver] = authConfig + } else { + for k, authConfig := range configFile.AuthConfigs { + authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth) + if err != nil { + return err + } + authConfig.Auth = "" + authConfig.ServerAddress = k + configFile.AuthConfigs[k] = authConfig + } + } + return nil +} + +// LoadFromReader reads the configuration data given and sets up the auth config +// information with given directory and populates the receiver object +func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error { + if err := json.NewDecoder(configData).Decode(&configFile); err != nil { + return err + } + var err error + for addr, ac := range configFile.AuthConfigs { + ac.Username, ac.Password, err = decodeAuth(ac.Auth) + if err != nil { + return err + } + ac.Auth = "" + ac.ServerAddress = addr + configFile.AuthConfigs[addr] = ac + } + return nil +} + +// ContainsAuth returns whether there is authentication configured +// in this file or not. +func (configFile *ConfigFile) ContainsAuth() bool { + return configFile.CredentialsStore != "" || + (configFile.AuthConfigs != nil && len(configFile.AuthConfigs) > 0) +} + +// SaveToWriter encodes and writes out all the authorization information to +// the given writer +func (configFile *ConfigFile) SaveToWriter(writer io.Writer) error { + // Encode sensitive data into a new/temp struct + tmpAuthConfigs := make(map[string]types.AuthConfig, len(configFile.AuthConfigs)) + for k, authConfig := range configFile.AuthConfigs { + authCopy := authConfig + // encode and save the authstring, while blanking out the original fields + authCopy.Auth = encodeAuth(&authCopy) + authCopy.Username = "" + authCopy.Password = "" + authCopy.ServerAddress = "" + tmpAuthConfigs[k] = authCopy + } + + saveAuthConfigs := configFile.AuthConfigs + configFile.AuthConfigs = tmpAuthConfigs + defer func() { configFile.AuthConfigs = saveAuthConfigs }() + + data, err := json.MarshalIndent(configFile, "", "\t") + if err != nil { + return err + } + _, err = writer.Write(data) + return err +} + +// Save encodes and writes out all the authorization information +func (configFile *ConfigFile) Save() error { + if configFile.Filename == "" { + return fmt.Errorf("Can't save config with empty filename") + } + + if err := os.MkdirAll(filepath.Dir(configFile.Filename), 0700); err != nil { + return err + } + f, err := os.OpenFile(configFile.Filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + return err + } + defer f.Close() + return configFile.SaveToWriter(f) +} + +// encodeAuth creates a base64 encoded string to containing authorization information +func encodeAuth(authConfig *types.AuthConfig) string { + if authConfig.Username == "" && authConfig.Password == "" { + return "" + } + + authStr := authConfig.Username + ":" + authConfig.Password + msg := []byte(authStr) + encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg))) + base64.StdEncoding.Encode(encoded, msg) + return string(encoded) +} + +// decodeAuth decodes a base64 encoded string and returns username and password +func decodeAuth(authStr string) (string, string, error) { + if authStr == "" { + return "", "", nil + } + + decLen := base64.StdEncoding.DecodedLen(len(authStr)) + decoded := make([]byte, decLen) + authByte := []byte(authStr) + n, err := base64.StdEncoding.Decode(decoded, authByte) + if err != nil { + return "", "", err + } + if n > decLen { + return "", "", fmt.Errorf("Something went wrong decoding auth config") + } + arr := strings.SplitN(string(decoded), ":", 2) + if len(arr) != 2 { + return "", "", fmt.Errorf("Invalid auth configuration file") + } + password := strings.Trim(arr[1], "\x00") + return arr[0], password, nil +} diff --git a/cliconfig/configfile/file_test.go b/cliconfig/configfile/file_test.go new file mode 100644 index 0000000000..15eecb73e2 --- /dev/null +++ b/cliconfig/configfile/file_test.go @@ -0,0 +1,27 @@ +package configfile + +import ( + "testing" + + "github.com/docker/engine-api/types" +) + +func TestEncodeAuth(t *testing.T) { + newAuthConfig := &types.AuthConfig{Username: "ken", Password: "test"} + authStr := encodeAuth(newAuthConfig) + decAuthConfig := &types.AuthConfig{} + var err error + decAuthConfig.Username, decAuthConfig.Password, err = decodeAuth(authStr) + if err != nil { + t.Fatal(err) + } + if newAuthConfig.Username != decAuthConfig.Username { + t.Fatal("Encode Username doesn't match decoded Username") + } + if newAuthConfig.Password != decAuthConfig.Password { + t.Fatal("Encode Password doesn't match decoded Password") + } + if authStr != "a2VuOnRlc3Q=" { + t.Fatal("AuthString encoding isn't correct.") + } +} diff --git a/cliconfig/credentials/default_store.go b/cliconfig/credentials/default_store.go index b5fc47ccb3..b4733709b1 100644 --- a/cliconfig/credentials/default_store.go +++ b/cliconfig/credentials/default_store.go @@ -3,12 +3,12 @@ package credentials import ( "os/exec" - "github.com/docker/docker/cliconfig" + "github.com/docker/docker/cliconfig/configfile" ) // DetectDefaultStore sets the default credentials store // if the host includes the default store helper program. -func DetectDefaultStore(c *cliconfig.ConfigFile) { +func DetectDefaultStore(c *configfile.ConfigFile) { if c.CredentialsStore != "" { // user defined return diff --git a/cliconfig/credentials/file_store.go b/cliconfig/credentials/file_store.go index 8e7edd624a..cf1c89fcc5 100644 --- a/cliconfig/credentials/file_store.go +++ b/cliconfig/credentials/file_store.go @@ -3,18 +3,18 @@ package credentials import ( "strings" - "github.com/docker/docker/cliconfig" + "github.com/docker/docker/cliconfig/configfile" "github.com/docker/engine-api/types" ) // fileStore implements a credentials store using // the docker configuration file to keep the credentials in plain text. type fileStore struct { - file *cliconfig.ConfigFile + file *configfile.ConfigFile } // NewFileStore creates a new file credentials store. -func NewFileStore(file *cliconfig.ConfigFile) Store { +func NewFileStore(file *configfile.ConfigFile) Store { return &fileStore{ file: file, } diff --git a/cliconfig/credentials/file_store_test.go b/cliconfig/credentials/file_store_test.go index 668b6f097d..f087f04e75 100644 --- a/cliconfig/credentials/file_store_test.go +++ b/cliconfig/credentials/file_store_test.go @@ -5,10 +5,11 @@ import ( "testing" "github.com/docker/docker/cliconfig" + "github.com/docker/docker/cliconfig/configfile" "github.com/docker/engine-api/types" ) -func newConfigFile(auths map[string]types.AuthConfig) *cliconfig.ConfigFile { +func newConfigFile(auths map[string]types.AuthConfig) *configfile.ConfigFile { tmp, _ := ioutil.TempFile("", "docker-test") name := tmp.Name() tmp.Close() diff --git a/cliconfig/credentials/native_store.go b/cliconfig/credentials/native_store.go index 9b8997dd64..e81de437e2 100644 --- a/cliconfig/credentials/native_store.go +++ b/cliconfig/credentials/native_store.go @@ -9,7 +9,7 @@ import ( "strings" "github.com/Sirupsen/logrus" - "github.com/docker/docker/cliconfig" + "github.com/docker/docker/cliconfig/configfile" "github.com/docker/engine-api/types" ) @@ -52,7 +52,7 @@ type nativeStore struct { // NewNativeStore creates a new native store that // uses a remote helper program to manage credentials. -func NewNativeStore(file *cliconfig.ConfigFile) Store { +func NewNativeStore(file *configfile.ConfigFile) Store { return &nativeStore{ commandFn: shellCommandFn(file.CredentialsStore), fileStore: NewFileStore(file),