We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Log message not replacing string format placeholder
[This line](https://github.com/docker/docker-py/blob/e9fab1432b974ceaa888b371e382dfcf2f6556e4/docker/auth.py#L205) in the `parse_auth` function in `auth.py` is using a string format placeholder but is not calling `format` on the string to replace it.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `docker/auth.py`
Content:
```
1 import base64
2 import json
3 import logging
4 import os
5 
6 import dockerpycreds
7 import six
8 
9 from . import errors
10 from .constants import IS_WINDOWS_PLATFORM
11 
12 INDEX_NAME = 'docker.io'
13 INDEX_URL = 'https://index.{0}/v1/'.format(INDEX_NAME)
14 DOCKER_CONFIG_FILENAME = os.path.join('.docker', 'config.json')
15 LEGACY_DOCKER_CONFIG_FILENAME = '.dockercfg'
16 TOKEN_USERNAME = '<token>'
17 
18 log = logging.getLogger(__name__)
19 
20 
21 def resolve_repository_name(repo_name):
22     if '://' in repo_name:
23         raise errors.InvalidRepository(
24             'Repository name cannot contain a scheme ({0})'.format(repo_name)
25         )
26 
27     index_name, remote_name = split_repo_name(repo_name)
28     if index_name[0] == '-' or index_name[-1] == '-':
29         raise errors.InvalidRepository(
30             'Invalid index name ({0}). Cannot begin or end with a'
31             ' hyphen.'.format(index_name)
32         )
33     return resolve_index_name(index_name), remote_name
34 
35 
36 def resolve_index_name(index_name):
37     index_name = convert_to_hostname(index_name)
38     if index_name == 'index.' + INDEX_NAME:
39         index_name = INDEX_NAME
40     return index_name
41 
42 
43 def get_config_header(client, registry):
44     log.debug('Looking for auth config')
45     if not client._auth_configs:
46         log.debug(
47             "No auth config in memory - loading from filesystem"
48         )
49         client._auth_configs = load_config()
50     authcfg = resolve_authconfig(client._auth_configs, registry)
51     # Do not fail here if no authentication exists for this
52     # specific registry as we can have a readonly pull. Just
53     # put the header if we can.
54     if authcfg:
55         log.debug('Found auth config')
56         # auth_config needs to be a dict in the format used by
57         # auth.py username , password, serveraddress, email
58         return encode_header(authcfg)
59     log.debug('No auth config found')
60     return None
61 
62 
63 def split_repo_name(repo_name):
64     parts = repo_name.split('/', 1)
65     if len(parts) == 1 or (
66         '.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost'
67     ):
68         # This is a docker index repo (ex: username/foobar or ubuntu)
69         return INDEX_NAME, repo_name
70     return tuple(parts)
71 
72 
73 def get_credential_store(authconfig, registry):
74     if not registry or registry == INDEX_NAME:
75         registry = 'https://index.docker.io/v1/'
76 
77     return authconfig.get('credHelpers', {}).get(registry) or authconfig.get(
78         'credsStore'
79     )
80 
81 
82 def resolve_authconfig(authconfig, registry=None):
83     """
84     Returns the authentication data from the given auth configuration for a
85     specific registry. As with the Docker client, legacy entries in the config
86     with full URLs are stripped down to hostnames before checking for a match.
87     Returns None if no match was found.
88     """
89 
90     if 'credHelpers' in authconfig or 'credsStore' in authconfig:
91         store_name = get_credential_store(authconfig, registry)
92         if store_name is not None:
93             log.debug(
94                 'Using credentials store "{0}"'.format(store_name)
95             )
96             return _resolve_authconfig_credstore(
97                 authconfig, registry, store_name
98             )
99 
100     # Default to the public index server
101     registry = resolve_index_name(registry) if registry else INDEX_NAME
102     log.debug("Looking for auth entry for {0}".format(repr(registry)))
103 
104     if registry in authconfig:
105         log.debug("Found {0}".format(repr(registry)))
106         return authconfig[registry]
107 
108     for key, config in six.iteritems(authconfig):
109         if resolve_index_name(key) == registry:
110             log.debug("Found {0}".format(repr(key)))
111             return config
112 
113     log.debug("No entry found")
114     return None
115 
116 
117 def _resolve_authconfig_credstore(authconfig, registry, credstore_name):
118     if not registry or registry == INDEX_NAME:
119         # The ecosystem is a little schizophrenic with index.docker.io VS
120         # docker.io - in that case, it seems the full URL is necessary.
121         registry = INDEX_URL
122     log.debug("Looking for auth entry for {0}".format(repr(registry)))
123     store = dockerpycreds.Store(credstore_name)
124     try:
125         data = store.get(registry)
126         res = {
127             'ServerAddress': registry,
128         }
129         if data['Username'] == TOKEN_USERNAME:
130             res['IdentityToken'] = data['Secret']
131         else:
132             res.update({
133                 'Username': data['Username'],
134                 'Password': data['Secret'],
135             })
136         return res
137     except dockerpycreds.CredentialsNotFound as e:
138         log.debug('No entry found')
139         return None
140     except dockerpycreds.StoreError as e:
141         raise errors.DockerException(
142             'Credentials store error: {0}'.format(repr(e))
143         )
144 
145 
146 def convert_to_hostname(url):
147     return url.replace('http://', '').replace('https://', '').split('/', 1)[0]
148 
149 
150 def decode_auth(auth):
151     if isinstance(auth, six.string_types):
152         auth = auth.encode('ascii')
153     s = base64.b64decode(auth)
154     login, pwd = s.split(b':', 1)
155     return login.decode('utf8'), pwd.decode('utf8')
156 
157 
158 def encode_header(auth):
159     auth_json = json.dumps(auth).encode('ascii')
160     return base64.urlsafe_b64encode(auth_json)
161 
162 
163 def parse_auth(entries, raise_on_error=False):
164     """
165     Parses authentication entries
166 
167     Args:
168       entries:        Dict of authentication entries.
169       raise_on_error: If set to true, an invalid format will raise
170                       InvalidConfigFile
171 
172     Returns:
173       Authentication registry.
174     """
175 
176     conf = {}
177     for registry, entry in six.iteritems(entries):
178         if not isinstance(entry, dict):
179             log.debug(
180                 'Config entry for key {0} is not auth config'.format(registry)
181             )
182             # We sometimes fall back to parsing the whole config as if it was
183             # the auth config by itself, for legacy purposes. In that case, we
184             # fail silently and return an empty conf if any of the keys is not
185             # formatted properly.
186             if raise_on_error:
187                 raise errors.InvalidConfigFile(
188                     'Invalid configuration for registry {0}'.format(registry)
189                 )
190             return {}
191         if 'identitytoken' in entry:
192             log.debug('Found an IdentityToken entry for registry {0}'.format(
193                 registry
194             ))
195             conf[registry] = {
196                 'IdentityToken': entry['identitytoken']
197             }
198             continue  # Other values are irrelevant if we have a token, skip.
199 
200         if 'auth' not in entry:
201             # Starting with engine v1.11 (API 1.23), an empty dictionary is
202             # a valid value in the auths config.
203             # https://github.com/docker/compose/issues/3265
204             log.debug(
205                 'Auth data for {0} is absent. Client might be using a '
206                 'credentials store instead.'
207             )
208             conf[registry] = {}
209             continue
210 
211         username, password = decode_auth(entry['auth'])
212         log.debug(
213             'Found entry (registry={0}, username={1})'
214             .format(repr(registry), repr(username))
215         )
216 
217         conf[registry] = {
218             'username': username,
219             'password': password,
220             'email': entry.get('email'),
221             'serveraddress': registry,
222         }
223     return conf
224 
225 
226 def find_config_file(config_path=None):
227     paths = list(filter(None, [
228         config_path,  # 1
229         config_path_from_environment(),  # 2
230         os.path.join(home_dir(), DOCKER_CONFIG_FILENAME),  # 3
231         os.path.join(home_dir(), LEGACY_DOCKER_CONFIG_FILENAME),  # 4
232     ]))
233 
234     log.debug("Trying paths: {0}".format(repr(paths)))
235 
236     for path in paths:
237         if os.path.exists(path):
238             log.debug("Found file at path: {0}".format(path))
239             return path
240 
241     log.debug("No config file found")
242 
243     return None
244 
245 
246 def config_path_from_environment():
247     config_dir = os.environ.get('DOCKER_CONFIG')
248     if not config_dir:
249         return None
250     return os.path.join(config_dir, os.path.basename(DOCKER_CONFIG_FILENAME))
251 
252 
253 def home_dir():
254     """
255     Get the user's home directory, using the same logic as the Docker Engine
256     client - use %USERPROFILE% on Windows, $HOME/getuid on POSIX.
257     """
258     if IS_WINDOWS_PLATFORM:
259         return os.environ.get('USERPROFILE', '')
260     else:
261         return os.path.expanduser('~')
262 
263 
264 def load_config(config_path=None):
265     """
266     Loads authentication data from a Docker configuration file in the given
267     root directory or if config_path is passed use given path.
268     Lookup priority:
269         explicit config_path parameter > DOCKER_CONFIG environment variable >
270         ~/.docker/config.json > ~/.dockercfg
271     """
272     config_file = find_config_file(config_path)
273 
274     if not config_file:
275         return {}
276 
277     try:
278         with open(config_file) as f:
279             data = json.load(f)
280             res = {}
281             if data.get('auths'):
282                 log.debug("Found 'auths' section")
283                 res.update(parse_auth(data['auths'], raise_on_error=True))
284             if data.get('HttpHeaders'):
285                 log.debug("Found 'HttpHeaders' section")
286                 res.update({'HttpHeaders': data['HttpHeaders']})
287             if data.get('credsStore'):
288                 log.debug("Found 'credsStore' section")
289                 res.update({'credsStore': data['credsStore']})
290             if data.get('credHelpers'):
291                 log.debug("Found 'credHelpers' section")
292                 res.update({'credHelpers': data['credHelpers']})
293             if res:
294                 return res
295             else:
296                 log.debug("Couldn't find 'auths' or 'HttpHeaders' sections")
297                 f.seek(0)
298                 return parse_auth(json.load(f))
299     except (IOError, KeyError, ValueError) as e:
300         # Likely missing new Docker config file or it's in an
301         # unknown format, continue to attempt to read old location
302         # and format.
303         log.debug(e)
304 
305     log.debug("Attempting to parse legacy auth file format")
306     try:
307         data = []
308         with open(config_file) as f:
309             for line in f.readlines():
310                 data.append(line.strip().split(' = ')[1])
311             if len(data) < 2:
312                 # Not enough data
313                 raise errors.InvalidConfigFile(
314                     'Invalid or empty configuration file!'
315                 )
316 
317         username, password = decode_auth(data[0])
318         return {
319             INDEX_NAME: {
320                 'username': username,
321                 'password': password,
322                 'email': data[1],
323                 'serveraddress': INDEX_URL,
324             }
325         }
326     except Exception as e:
327         log.debug(e)
328         pass
329 
330     log.debug("All parsing attempts failed - returning empty config")
331     return {}
332
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/docker/auth.py b/docker/auth.py
--- a/docker/auth.py
+++ b/docker/auth.py
@@ -203,7 +203,7 @@
             # https://github.com/docker/compose/issues/3265
             log.debug(
                 'Auth data for {0} is absent. Client might be using a '
-                'credentials store instead.'
+                'credentials store instead.'.format(registry)
             )
             conf[registry] = {}
             continue

{"golden_diff": "diff --git a/docker/auth.py b/docker/auth.py\n--- a/docker/auth.py\n+++ b/docker/auth.py\n@@ -203,7 +203,7 @@\n             # https://github.com/docker/compose/issues/3265\n             log.debug(\n                 'Auth data for {0} is absent. Client might be using a '\n-                'credentials store instead.'\n+                'credentials store instead.'.format(registry)\n             )\n             conf[registry] = {}\n             continue\n", "issue": "Log message not replacing string format placeholder\n[This line](https://github.com/docker/docker-py/blob/e9fab1432b974ceaa888b371e382dfcf2f6556e4/docker/auth.py#L205) in the `parse_auth` function in `auth.py` is using a string format placeholder but is not calling `format` on the string to replace it.\n", "before_files": [{"content": "import base64\nimport json\nimport logging\nimport os\n\nimport dockerpycreds\nimport six\n\nfrom . import errors\nfrom .constants import IS_WINDOWS_PLATFORM\n\nINDEX_NAME = 'docker.io'\nINDEX_URL = 'https://index.{0}/v1/'.format(INDEX_NAME)\nDOCKER_CONFIG_FILENAME = os.path.join('.docker', 'config.json')\nLEGACY_DOCKER_CONFIG_FILENAME = '.dockercfg'\nTOKEN_USERNAME = '<token>'\n\nlog = logging.getLogger(__name__)\n\n\ndef resolve_repository_name(repo_name):\n    if '://' in repo_name:\n        raise errors.InvalidRepository(\n            'Repository name cannot contain a scheme ({0})'.format(repo_name)\n        )\n\n    index_name, remote_name = split_repo_name(repo_name)\n    if index_name[0] == '-' or index_name[-1] == '-':\n        raise errors.InvalidRepository(\n            'Invalid index name ({0}). Cannot begin or end with a'\n            ' hyphen.'.format(index_name)\n        )\n    return resolve_index_name(index_name), remote_name\n\n\ndef resolve_index_name(index_name):\n    index_name = convert_to_hostname(index_name)\n    if index_name == 'index.' + INDEX_NAME:\n        index_name = INDEX_NAME\n    return index_name\n\n\ndef get_config_header(client, registry):\n    log.debug('Looking for auth config')\n    if not client._auth_configs:\n        log.debug(\n            \"No auth config in memory - loading from filesystem\"\n        )\n        client._auth_configs = load_config()\n    authcfg = resolve_authconfig(client._auth_configs, registry)\n    # Do not fail here if no authentication exists for this\n    # specific registry as we can have a readonly pull. Just\n    # put the header if we can.\n    if authcfg:\n        log.debug('Found auth config')\n        # auth_config needs to be a dict in the format used by\n        # auth.py username , password, serveraddress, email\n        return encode_header(authcfg)\n    log.debug('No auth config found')\n    return None\n\n\ndef split_repo_name(repo_name):\n    parts = repo_name.split('/', 1)\n    if len(parts) == 1 or (\n        '.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost'\n    ):\n        # This is a docker index repo (ex: username/foobar or ubuntu)\n        return INDEX_NAME, repo_name\n    return tuple(parts)\n\n\ndef get_credential_store(authconfig, registry):\n    if not registry or registry == INDEX_NAME:\n        registry = 'https://index.docker.io/v1/'\n\n    return authconfig.get('credHelpers', {}).get(registry) or authconfig.get(\n        'credsStore'\n    )\n\n\ndef resolve_authconfig(authconfig, registry=None):\n    \"\"\"\n    Returns the authentication data from the given auth configuration for a\n    specific registry. As with the Docker client, legacy entries in the config\n    with full URLs are stripped down to hostnames before checking for a match.\n    Returns None if no match was found.\n    \"\"\"\n\n    if 'credHelpers' in authconfig or 'credsStore' in authconfig:\n        store_name = get_credential_store(authconfig, registry)\n        if store_name is not None:\n            log.debug(\n                'Using credentials store \"{0}\"'.format(store_name)\n            )\n            return _resolve_authconfig_credstore(\n                authconfig, registry, store_name\n            )\n\n    # Default to the public index server\n    registry = resolve_index_name(registry) if registry else INDEX_NAME\n    log.debug(\"Looking for auth entry for {0}\".format(repr(registry)))\n\n    if registry in authconfig:\n        log.debug(\"Found {0}\".format(repr(registry)))\n        return authconfig[registry]\n\n    for key, config in six.iteritems(authconfig):\n        if resolve_index_name(key) == registry:\n            log.debug(\"Found {0}\".format(repr(key)))\n            return config\n\n    log.debug(\"No entry found\")\n    return None\n\n\ndef _resolve_authconfig_credstore(authconfig, registry, credstore_name):\n    if not registry or registry == INDEX_NAME:\n        # The ecosystem is a little schizophrenic with index.docker.io VS\n        # docker.io - in that case, it seems the full URL is necessary.\n        registry = INDEX_URL\n    log.debug(\"Looking for auth entry for {0}\".format(repr(registry)))\n    store = dockerpycreds.Store(credstore_name)\n    try:\n        data = store.get(registry)\n        res = {\n            'ServerAddress': registry,\n        }\n        if data['Username'] == TOKEN_USERNAME:\n            res['IdentityToken'] = data['Secret']\n        else:\n            res.update({\n                'Username': data['Username'],\n                'Password': data['Secret'],\n            })\n        return res\n    except dockerpycreds.CredentialsNotFound as e:\n        log.debug('No entry found')\n        return None\n    except dockerpycreds.StoreError as e:\n        raise errors.DockerException(\n            'Credentials store error: {0}'.format(repr(e))\n        )\n\n\ndef convert_to_hostname(url):\n    return url.replace('http://', '').replace('https://', '').split('/', 1)[0]\n\n\ndef decode_auth(auth):\n    if isinstance(auth, six.string_types):\n        auth = auth.encode('ascii')\n    s = base64.b64decode(auth)\n    login, pwd = s.split(b':', 1)\n    return login.decode('utf8'), pwd.decode('utf8')\n\n\ndef encode_header(auth):\n    auth_json = json.dumps(auth).encode('ascii')\n    return base64.urlsafe_b64encode(auth_json)\n\n\ndef parse_auth(entries, raise_on_error=False):\n    \"\"\"\n    Parses authentication entries\n\n    Args:\n      entries:        Dict of authentication entries.\n      raise_on_error: If set to true, an invalid format will raise\n                      InvalidConfigFile\n\n    Returns:\n      Authentication registry.\n    \"\"\"\n\n    conf = {}\n    for registry, entry in six.iteritems(entries):\n        if not isinstance(entry, dict):\n            log.debug(\n                'Config entry for key {0} is not auth config'.format(registry)\n            )\n            # We sometimes fall back to parsing the whole config as if it was\n            # the auth config by itself, for legacy purposes. In that case, we\n            # fail silently and return an empty conf if any of the keys is not\n            # formatted properly.\n            if raise_on_error:\n                raise errors.InvalidConfigFile(\n                    'Invalid configuration for registry {0}'.format(registry)\n                )\n            return {}\n        if 'identitytoken' in entry:\n            log.debug('Found an IdentityToken entry for registry {0}'.format(\n                registry\n            ))\n            conf[registry] = {\n                'IdentityToken': entry['identitytoken']\n            }\n            continue  # Other values are irrelevant if we have a token, skip.\n\n        if 'auth' not in entry:\n            # Starting with engine v1.11 (API 1.23), an empty dictionary is\n            # a valid value in the auths config.\n            # https://github.com/docker/compose/issues/3265\n            log.debug(\n                'Auth data for {0} is absent. Client might be using a '\n                'credentials store instead.'\n            )\n            conf[registry] = {}\n            continue\n\n        username, password = decode_auth(entry['auth'])\n        log.debug(\n            'Found entry (registry={0}, username={1})'\n            .format(repr(registry), repr(username))\n        )\n\n        conf[registry] = {\n            'username': username,\n            'password': password,\n            'email': entry.get('email'),\n            'serveraddress': registry,\n        }\n    return conf\n\n\ndef find_config_file(config_path=None):\n    paths = list(filter(None, [\n        config_path,  # 1\n        config_path_from_environment(),  # 2\n        os.path.join(home_dir(), DOCKER_CONFIG_FILENAME),  # 3\n        os.path.join(home_dir(), LEGACY_DOCKER_CONFIG_FILENAME),  # 4\n    ]))\n\n    log.debug(\"Trying paths: {0}\".format(repr(paths)))\n\n    for path in paths:\n        if os.path.exists(path):\n            log.debug(\"Found file at path: {0}\".format(path))\n            return path\n\n    log.debug(\"No config file found\")\n\n    return None\n\n\ndef config_path_from_environment():\n    config_dir = os.environ.get('DOCKER_CONFIG')\n    if not config_dir:\n        return None\n    return os.path.join(config_dir, os.path.basename(DOCKER_CONFIG_FILENAME))\n\n\ndef home_dir():\n    \"\"\"\n    Get the user's home directory, using the same logic as the Docker Engine\n    client - use %USERPROFILE% on Windows, $HOME/getuid on POSIX.\n    \"\"\"\n    if IS_WINDOWS_PLATFORM:\n        return os.environ.get('USERPROFILE', '')\n    else:\n        return os.path.expanduser('~')\n\n\ndef load_config(config_path=None):\n    \"\"\"\n    Loads authentication data from a Docker configuration file in the given\n    root directory or if config_path is passed use given path.\n    Lookup priority:\n        explicit config_path parameter > DOCKER_CONFIG environment variable >\n        ~/.docker/config.json > ~/.dockercfg\n    \"\"\"\n    config_file = find_config_file(config_path)\n\n    if not config_file:\n        return {}\n\n    try:\n        with open(config_file) as f:\n            data = json.load(f)\n            res = {}\n            if data.get('auths'):\n                log.debug(\"Found 'auths' section\")\n                res.update(parse_auth(data['auths'], raise_on_error=True))\n            if data.get('HttpHeaders'):\n                log.debug(\"Found 'HttpHeaders' section\")\n                res.update({'HttpHeaders': data['HttpHeaders']})\n            if data.get('credsStore'):\n                log.debug(\"Found 'credsStore' section\")\n                res.update({'credsStore': data['credsStore']})\n            if data.get('credHelpers'):\n                log.debug(\"Found 'credHelpers' section\")\n                res.update({'credHelpers': data['credHelpers']})\n            if res:\n                return res\n            else:\n                log.debug(\"Couldn't find 'auths' or 'HttpHeaders' sections\")\n                f.seek(0)\n                return parse_auth(json.load(f))\n    except (IOError, KeyError, ValueError) as e:\n        # Likely missing new Docker config file or it's in an\n        # unknown format, continue to attempt to read old location\n        # and format.\n        log.debug(e)\n\n    log.debug(\"Attempting to parse legacy auth file format\")\n    try:\n        data = []\n        with open(config_file) as f:\n            for line in f.readlines():\n                data.append(line.strip().split(' = ')[1])\n            if len(data) < 2:\n                # Not enough data\n                raise errors.InvalidConfigFile(\n                    'Invalid or empty configuration file!'\n                )\n\n        username, password = decode_auth(data[0])\n        return {\n            INDEX_NAME: {\n                'username': username,\n                'password': password,\n                'email': data[1],\n                'serveraddress': INDEX_URL,\n            }\n        }\n    except Exception as e:\n        log.debug(e)\n        pass\n\n    log.debug(\"All parsing attempts failed - returning empty config\")\n    return {}\n", "path": "docker/auth.py"}], "after_files": [{"content": "import base64\nimport json\nimport logging\nimport os\n\nimport dockerpycreds\nimport six\n\nfrom . import errors\nfrom .constants import IS_WINDOWS_PLATFORM\n\nINDEX_NAME = 'docker.io'\nINDEX_URL = 'https://index.{0}/v1/'.format(INDEX_NAME)\nDOCKER_CONFIG_FILENAME = os.path.join('.docker', 'config.json')\nLEGACY_DOCKER_CONFIG_FILENAME = '.dockercfg'\nTOKEN_USERNAME = '<token>'\n\nlog = logging.getLogger(__name__)\n\n\ndef resolve_repository_name(repo_name):\n    if '://' in repo_name:\n        raise errors.InvalidRepository(\n            'Repository name cannot contain a scheme ({0})'.format(repo_name)\n        )\n\n    index_name, remote_name = split_repo_name(repo_name)\n    if index_name[0] == '-' or index_name[-1] == '-':\n        raise errors.InvalidRepository(\n            'Invalid index name ({0}). Cannot begin or end with a'\n            ' hyphen.'.format(index_name)\n        )\n    return resolve_index_name(index_name), remote_name\n\n\ndef resolve_index_name(index_name):\n    index_name = convert_to_hostname(index_name)\n    if index_name == 'index.' + INDEX_NAME:\n        index_name = INDEX_NAME\n    return index_name\n\n\ndef get_config_header(client, registry):\n    log.debug('Looking for auth config')\n    if not client._auth_configs:\n        log.debug(\n            \"No auth config in memory - loading from filesystem\"\n        )\n        client._auth_configs = load_config()\n    authcfg = resolve_authconfig(client._auth_configs, registry)\n    # Do not fail here if no authentication exists for this\n    # specific registry as we can have a readonly pull. Just\n    # put the header if we can.\n    if authcfg:\n        log.debug('Found auth config')\n        # auth_config needs to be a dict in the format used by\n        # auth.py username , password, serveraddress, email\n        return encode_header(authcfg)\n    log.debug('No auth config found')\n    return None\n\n\ndef split_repo_name(repo_name):\n    parts = repo_name.split('/', 1)\n    if len(parts) == 1 or (\n        '.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost'\n    ):\n        # This is a docker index repo (ex: username/foobar or ubuntu)\n        return INDEX_NAME, repo_name\n    return tuple(parts)\n\n\ndef get_credential_store(authconfig, registry):\n    if not registry or registry == INDEX_NAME:\n        registry = 'https://index.docker.io/v1/'\n\n    return authconfig.get('credHelpers', {}).get(registry) or authconfig.get(\n        'credsStore'\n    )\n\n\ndef resolve_authconfig(authconfig, registry=None):\n    \"\"\"\n    Returns the authentication data from the given auth configuration for a\n    specific registry. As with the Docker client, legacy entries in the config\n    with full URLs are stripped down to hostnames before checking for a match.\n    Returns None if no match was found.\n    \"\"\"\n\n    if 'credHelpers' in authconfig or 'credsStore' in authconfig:\n        store_name = get_credential_store(authconfig, registry)\n        if store_name is not None:\n            log.debug(\n                'Using credentials store \"{0}\"'.format(store_name)\n            )\n            return _resolve_authconfig_credstore(\n                authconfig, registry, store_name\n            )\n\n    # Default to the public index server\n    registry = resolve_index_name(registry) if registry else INDEX_NAME\n    log.debug(\"Looking for auth entry for {0}\".format(repr(registry)))\n\n    if registry in authconfig:\n        log.debug(\"Found {0}\".format(repr(registry)))\n        return authconfig[registry]\n\n    for key, config in six.iteritems(authconfig):\n        if resolve_index_name(key) == registry:\n            log.debug(\"Found {0}\".format(repr(key)))\n            return config\n\n    log.debug(\"No entry found\")\n    return None\n\n\ndef _resolve_authconfig_credstore(authconfig, registry, credstore_name):\n    if not registry or registry == INDEX_NAME:\n        # The ecosystem is a little schizophrenic with index.docker.io VS\n        # docker.io - in that case, it seems the full URL is necessary.\n        registry = INDEX_URL\n    log.debug(\"Looking for auth entry for {0}\".format(repr(registry)))\n    store = dockerpycreds.Store(credstore_name)\n    try:\n        data = store.get(registry)\n        res = {\n            'ServerAddress': registry,\n        }\n        if data['Username'] == TOKEN_USERNAME:\n            res['IdentityToken'] = data['Secret']\n        else:\n            res.update({\n                'Username': data['Username'],\n                'Password': data['Secret'],\n            })\n        return res\n    except dockerpycreds.CredentialsNotFound as e:\n        log.debug('No entry found')\n        return None\n    except dockerpycreds.StoreError as e:\n        raise errors.DockerException(\n            'Credentials store error: {0}'.format(repr(e))\n        )\n\n\ndef convert_to_hostname(url):\n    return url.replace('http://', '').replace('https://', '').split('/', 1)[0]\n\n\ndef decode_auth(auth):\n    if isinstance(auth, six.string_types):\n        auth = auth.encode('ascii')\n    s = base64.b64decode(auth)\n    login, pwd = s.split(b':', 1)\n    return login.decode('utf8'), pwd.decode('utf8')\n\n\ndef encode_header(auth):\n    auth_json = json.dumps(auth).encode('ascii')\n    return base64.urlsafe_b64encode(auth_json)\n\n\ndef parse_auth(entries, raise_on_error=False):\n    \"\"\"\n    Parses authentication entries\n\n    Args:\n      entries:        Dict of authentication entries.\n      raise_on_error: If set to true, an invalid format will raise\n                      InvalidConfigFile\n\n    Returns:\n      Authentication registry.\n    \"\"\"\n\n    conf = {}\n    for registry, entry in six.iteritems(entries):\n        if not isinstance(entry, dict):\n            log.debug(\n                'Config entry for key {0} is not auth config'.format(registry)\n            )\n            # We sometimes fall back to parsing the whole config as if it was\n            # the auth config by itself, for legacy purposes. In that case, we\n            # fail silently and return an empty conf if any of the keys is not\n            # formatted properly.\n            if raise_on_error:\n                raise errors.InvalidConfigFile(\n                    'Invalid configuration for registry {0}'.format(registry)\n                )\n            return {}\n        if 'identitytoken' in entry:\n            log.debug('Found an IdentityToken entry for registry {0}'.format(\n                registry\n            ))\n            conf[registry] = {\n                'IdentityToken': entry['identitytoken']\n            }\n            continue  # Other values are irrelevant if we have a token, skip.\n\n        if 'auth' not in entry:\n            # Starting with engine v1.11 (API 1.23), an empty dictionary is\n            # a valid value in the auths config.\n            # https://github.com/docker/compose/issues/3265\n            log.debug(\n                'Auth data for {0} is absent. Client might be using a '\n                'credentials store instead.'.format(registry)\n            )\n            conf[registry] = {}\n            continue\n\n        username, password = decode_auth(entry['auth'])\n        log.debug(\n            'Found entry (registry={0}, username={1})'\n            .format(repr(registry), repr(username))\n        )\n\n        conf[registry] = {\n            'username': username,\n            'password': password,\n            'email': entry.get('email'),\n            'serveraddress': registry,\n        }\n    return conf\n\n\ndef find_config_file(config_path=None):\n    paths = list(filter(None, [\n        config_path,  # 1\n        config_path_from_environment(),  # 2\n        os.path.join(home_dir(), DOCKER_CONFIG_FILENAME),  # 3\n        os.path.join(home_dir(), LEGACY_DOCKER_CONFIG_FILENAME),  # 4\n    ]))\n\n    log.debug(\"Trying paths: {0}\".format(repr(paths)))\n\n    for path in paths:\n        if os.path.exists(path):\n            log.debug(\"Found file at path: {0}\".format(path))\n            return path\n\n    log.debug(\"No config file found\")\n\n    return None\n\n\ndef config_path_from_environment():\n    config_dir = os.environ.get('DOCKER_CONFIG')\n    if not config_dir:\n        return None\n    return os.path.join(config_dir, os.path.basename(DOCKER_CONFIG_FILENAME))\n\n\ndef home_dir():\n    \"\"\"\n    Get the user's home directory, using the same logic as the Docker Engine\n    client - use %USERPROFILE% on Windows, $HOME/getuid on POSIX.\n    \"\"\"\n    if IS_WINDOWS_PLATFORM:\n        return os.environ.get('USERPROFILE', '')\n    else:\n        return os.path.expanduser('~')\n\n\ndef load_config(config_path=None):\n    \"\"\"\n    Loads authentication data from a Docker configuration file in the given\n    root directory or if config_path is passed use given path.\n    Lookup priority:\n        explicit config_path parameter > DOCKER_CONFIG environment variable >\n        ~/.docker/config.json > ~/.dockercfg\n    \"\"\"\n    config_file = find_config_file(config_path)\n\n    if not config_file:\n        return {}\n\n    try:\n        with open(config_file) as f:\n            data = json.load(f)\n            res = {}\n            if data.get('auths'):\n                log.debug(\"Found 'auths' section\")\n                res.update(parse_auth(data['auths'], raise_on_error=True))\n            if data.get('HttpHeaders'):\n                log.debug(\"Found 'HttpHeaders' section\")\n                res.update({'HttpHeaders': data['HttpHeaders']})\n            if data.get('credsStore'):\n                log.debug(\"Found 'credsStore' section\")\n                res.update({'credsStore': data['credsStore']})\n            if data.get('credHelpers'):\n                log.debug(\"Found 'credHelpers' section\")\n                res.update({'credHelpers': data['credHelpers']})\n            if res:\n                return res\n            else:\n                log.debug(\"Couldn't find 'auths' or 'HttpHeaders' sections\")\n                f.seek(0)\n                return parse_auth(json.load(f))\n    except (IOError, KeyError, ValueError) as e:\n        # Likely missing new Docker config file or it's in an\n        # unknown format, continue to attempt to read old location\n        # and format.\n        log.debug(e)\n\n    log.debug(\"Attempting to parse legacy auth file format\")\n    try:\n        data = []\n        with open(config_file) as f:\n            for line in f.readlines():\n                data.append(line.strip().split(' = ')[1])\n            if len(data) < 2:\n                # Not enough data\n                raise errors.InvalidConfigFile(\n                    'Invalid or empty configuration file!'\n                )\n\n        username, password = decode_auth(data[0])\n        return {\n            INDEX_NAME: {\n                'username': username,\n                'password': password,\n                'email': data[1],\n                'serveraddress': INDEX_URL,\n            }\n        }\n    except Exception as e:\n        log.debug(e)\n        pass\n\n    log.debug(\"All parsing attempts failed - returning empty config\")\n    return {}\n", "path": "docker/auth.py"}]}