Skip to content

Commit c0ec551

Browse files
committed
Merge pull request #861 from docker/860-deprecate-resolve-repo-name
Update repo name resolution method
2 parents 43b0ea5 + 00c0baf commit c0ec551

File tree

5 files changed

+101
-55
lines changed

5 files changed

+101
-55
lines changed

docker/api/image.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,6 @@ def pull(self, repository, tag=None, stream=False,
158158
if not tag:
159159
repository, tag = utils.parse_repository_tag(repository)
160160
registry, repo_name = auth.resolve_repository_name(repository)
161-
if repo_name.count(":") == 1:
162-
repository, tag = repository.rsplit(":", 1)
163161

164162
params = {
165163
'tag': tag,
@@ -174,7 +172,8 @@ def pull(self, repository, tag=None, stream=False,
174172
log.debug('Looking for auth config')
175173
if not self._auth_configs:
176174
log.debug(
177-
"No auth config in memory - loading from filesystem")
175+
"No auth config in memory - loading from filesystem"
176+
)
178177
self._auth_configs = auth.load_config()
179178
authcfg = auth.resolve_authconfig(self._auth_configs, registry)
180179
# Do not fail here if no authentication exists for this

docker/auth/auth.py

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@
1616
import json
1717
import logging
1818
import os
19-
import warnings
2019

2120
import six
2221

23-
from .. import constants
2422
from .. import errors
2523

2624
INDEX_NAME = 'index.docker.io'
@@ -31,31 +29,29 @@
3129
log = logging.getLogger(__name__)
3230

3331

34-
def resolve_repository_name(repo_name, insecure=False):
35-
if insecure:
36-
warnings.warn(
37-
constants.INSECURE_REGISTRY_DEPRECATION_WARNING.format(
38-
'resolve_repository_name()'
39-
), DeprecationWarning
40-
)
41-
32+
def resolve_repository_name(repo_name):
4233
if '://' in repo_name:
4334
raise errors.InvalidRepository(
44-
'Repository name cannot contain a scheme ({0})'.format(repo_name))
45-
parts = repo_name.split('/', 1)
46-
if '.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost':
47-
# This is a docker index repo (ex: foo/bar or ubuntu)
48-
return INDEX_NAME, repo_name
49-
if len(parts) < 2:
50-
raise errors.InvalidRepository(
51-
'Invalid repository name ({0})'.format(repo_name))
35+
'Repository name cannot contain a scheme ({0})'.format(repo_name)
36+
)
5237

53-
if 'index.docker.io' in parts[0]:
38+
index_name, remote_name = split_repo_name(repo_name)
39+
if index_name[0] == '-' or index_name[-1] == '-':
5440
raise errors.InvalidRepository(
55-
'Invalid repository name, try "{0}" instead'.format(parts[1])
41+
'Invalid index name ({0}). Cannot begin or end with a'
42+
' hyphen.'.format(index_name)
5643
)
44+
return index_name, remote_name
45+
5746

58-
return parts[0], parts[1]
47+
def split_repo_name(repo_name):
48+
parts = repo_name.split('/', 1)
49+
if len(parts) == 1 or (
50+
'.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost'
51+
):
52+
# This is a docker index repo (ex: username/foobar or ubuntu)
53+
return INDEX_NAME, repo_name
54+
return tuple(parts)
5955

6056

6157
def resolve_authconfig(authconfig, registry=None):

docker/utils/utils.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -283,16 +283,14 @@ def convert_volume_binds(binds):
283283
return result
284284

285285

286-
def parse_repository_tag(repo):
287-
column_index = repo.rfind(':')
288-
if column_index < 0:
289-
return repo, None
290-
tag = repo[column_index + 1:]
291-
slash_index = tag.find('/')
292-
if slash_index < 0:
293-
return repo[:column_index], tag
294-
295-
return repo, None
286+
def parse_repository_tag(repo_name):
287+
parts = repo_name.rsplit('@', 1)
288+
if len(parts) == 2:
289+
return tuple(parts)
290+
parts = repo_name.rsplit(':', 1)
291+
if len(parts) == 2 and '/' not in parts[1]:
292+
return tuple(parts)
293+
return repo_name, None
296294

297295

298296
# Based on utils.go:ParseHost http://tinyurl.com/nkahcfh

tests/unit/auth_test.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import tempfile
1010

1111
from docker import auth
12+
from docker import errors
1213

1314
from .. import base
1415

@@ -29,25 +30,31 @@ def test_803_urlsafe_encode(self):
2930
assert b'_' in encoded
3031

3132

32-
class ResolveAuthTest(base.BaseTestCase):
33-
auth_config = {
34-
'https://index.docker.io/v1/': {'auth': 'indexuser'},
35-
'my.registry.net': {'auth': 'privateuser'},
36-
'http://legacy.registry.url/v1/': {'auth': 'legacyauth'}
37-
}
38-
33+
class ResolveRepositoryNameTest(base.BaseTestCase):
3934
def test_resolve_repository_name_hub_library_image(self):
4035
self.assertEqual(
4136
auth.resolve_repository_name('image'),
4237
('index.docker.io', 'image'),
4338
)
4439

40+
def test_resolve_repository_name_dotted_hub_library_image(self):
41+
self.assertEqual(
42+
auth.resolve_repository_name('image.valid'),
43+
('index.docker.io', 'image.valid')
44+
)
45+
4546
def test_resolve_repository_name_hub_image(self):
4647
self.assertEqual(
4748
auth.resolve_repository_name('username/image'),
4849
('index.docker.io', 'username/image'),
4950
)
5051

52+
def test_explicit_hub_index_library_image(self):
53+
self.assertEqual(
54+
auth.resolve_repository_name('index.docker.io/image'),
55+
('index.docker.io', 'image')
56+
)
57+
5158
def test_resolve_repository_name_private_registry(self):
5259
self.assertEqual(
5360
auth.resolve_repository_name('my.registry.net/image'),
@@ -90,6 +97,20 @@ def test_resolve_repository_name_localhost_with_username(self):
9097
('localhost', 'username/image'),
9198
)
9299

100+
def test_invalid_index_name(self):
101+
self.assertRaises(
102+
errors.InvalidRepository,
103+
lambda: auth.resolve_repository_name('-gecko.com/image')
104+
)
105+
106+
107+
class ResolveAuthTest(base.BaseTestCase):
108+
auth_config = {
109+
'https://index.docker.io/v1/': {'auth': 'indexuser'},
110+
'my.registry.net': {'auth': 'privateuser'},
111+
'http://legacy.registry.url/v1/': {'auth': 'legacyauth'}
112+
}
113+
93114
def test_resolve_authconfig_hostname_only(self):
94115
self.assertEqual(
95116
auth.resolve_authconfig(self.auth_config, 'my.registry.net'),

tests/unit/utils_test.py

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -352,23 +352,55 @@ def test_parse_host_empty_value(self):
352352
assert parse_host(val, 'win32') == tcp_port
353353

354354

355+
class ParseRepositoryTagTest(base.BaseTestCase):
356+
sha = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
357+
358+
def test_index_image_no_tag(self):
359+
self.assertEqual(
360+
parse_repository_tag("root"), ("root", None)
361+
)
362+
363+
def test_index_image_tag(self):
364+
self.assertEqual(
365+
parse_repository_tag("root:tag"), ("root", "tag")
366+
)
367+
368+
def test_index_user_image_no_tag(self):
369+
self.assertEqual(
370+
parse_repository_tag("user/repo"), ("user/repo", None)
371+
)
372+
373+
def test_index_user_image_tag(self):
374+
self.assertEqual(
375+
parse_repository_tag("user/repo:tag"), ("user/repo", "tag")
376+
)
377+
378+
def test_private_reg_image_no_tag(self):
379+
self.assertEqual(
380+
parse_repository_tag("url:5000/repo"), ("url:5000/repo", None)
381+
)
382+
383+
def test_private_reg_image_tag(self):
384+
self.assertEqual(
385+
parse_repository_tag("url:5000/repo:tag"), ("url:5000/repo", "tag")
386+
)
387+
388+
def test_index_image_sha(self):
389+
self.assertEqual(
390+
parse_repository_tag("root@sha256:{0}".format(self.sha)),
391+
("root", "sha256:{0}".format(self.sha))
392+
)
393+
394+
def test_private_reg_image_sha(self):
395+
self.assertEqual(
396+
parse_repository_tag("url:5000/repo@sha256:{0}".format(self.sha)),
397+
("url:5000/repo", "sha256:{0}".format(self.sha))
398+
)
399+
400+
355401
class UtilsTest(base.BaseTestCase):
356402
longMessage = True
357403

358-
def test_parse_repository_tag(self):
359-
self.assertEqual(parse_repository_tag("root"),
360-
("root", None))
361-
self.assertEqual(parse_repository_tag("root:tag"),
362-
("root", "tag"))
363-
self.assertEqual(parse_repository_tag("user/repo"),
364-
("user/repo", None))
365-
self.assertEqual(parse_repository_tag("user/repo:tag"),
366-
("user/repo", "tag"))
367-
self.assertEqual(parse_repository_tag("url:5000/repo"),
368-
("url:5000/repo", None))
369-
self.assertEqual(parse_repository_tag("url:5000/repo:tag"),
370-
("url:5000/repo", "tag"))
371-
372404
def test_parse_bytes(self):
373405
self.assertEqual(parse_bytes("512MB"), (536870912))
374406
self.assertEqual(parse_bytes("512M"), (536870912))

0 commit comments

Comments
 (0)