Skip to content

Commit cc33931

Browse files
committed
Move ImageName from osbs-client to util.
Refactor to keep string behavior identical for parser. Signed-off-by: Tim van Katwijk <[email protected]>
1 parent 1d4f9fa commit cc33931

File tree

3 files changed

+426
-225
lines changed

3 files changed

+426
-225
lines changed

dockerfile_parse/parser.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from .constants import DOCKERFILE_FILENAME, COMMENT_INSTRUCTION
2121
from .util import (b2u, extract_key_values, get_key_val_dictionary,
22-
u2b, Context, WordSplitter)
22+
u2b, Context, WordSplitter, ImageName)
2323

2424

2525
logger = logging.getLogger(__name__)
@@ -880,7 +880,9 @@ def image_from(from_value):
880880
)?
881881
""")
882882
match = re.match(regex, from_value)
883-
return match.group('image', 'name') if match else (None, None)
883+
image = ImageName.parse(match.group('image')) if match else None
884+
name = match.group('name') if match else None
885+
return image, name
884886

885887

886888
def _endline(line):

dockerfile_parse/util.py

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def __init__(self, s, args=None, envs=None):
5454
:param envs: dict, environment variables to use; if None, do not
5555
attempt substitution
5656
"""
57-
self.stream = StringIO(s)
57+
self.stream = StringIO(str(s))
5858
self.args = args
5959
self.envs = envs
6060

@@ -332,3 +332,121 @@ def get_values(self, context_type):
332332
if context_type.upper() == "LABEL":
333333
return self.labels
334334
raise ValueError("Unexpected context type: " + context_type)
335+
336+
337+
class ImageName(object):
338+
"""Represent an image.
339+
Naming Conventions
340+
==================
341+
registry.somewhere/namespace/image_name:tag
342+
|-----------------| registry, reg_uri
343+
|---------| namespace
344+
|--------------------------------------| repository
345+
|--------------------| image name
346+
|--| tag
347+
|------------------------| image
348+
|------------------------------------------| image
349+
"""
350+
351+
def __init__(self, registry=None, namespace=None, repo=None, tag=None):
352+
self.registry = registry
353+
self.namespace = namespace
354+
self.repo = repo
355+
self.tag = tag
356+
357+
@classmethod
358+
def parse(cls, image_name):
359+
result = cls()
360+
361+
if not image_name or image_name.isspace():
362+
return ImageName()
363+
364+
if isinstance(image_name, cls):
365+
return image_name
366+
367+
# registry.org/namespace/repo:tag
368+
s = image_name.split('/', 2)
369+
370+
if len(s) == 2:
371+
if '.' in s[0] or ':' in s[0]:
372+
result.registry = s[0] if s[0] else None
373+
else:
374+
result.namespace = s[0]
375+
elif len(s) == 3:
376+
result.registry = s[0] if s[0] else None
377+
result.namespace = s[1]
378+
result.repo = s[-1]
379+
380+
for sep in '@:':
381+
try:
382+
result.repo, result.tag = result.repo.rsplit(sep, 1)
383+
except ValueError:
384+
continue
385+
break
386+
387+
return result
388+
389+
def to_str(self, registry=True, tag=True, explicit_tag=False,
390+
explicit_namespace=False):
391+
if self.repo is None:
392+
raise RuntimeError('No image repository specified')
393+
394+
result = self.get_repo(explicit_namespace)
395+
396+
if tag and self.tag and ':' in self.tag:
397+
result = '{0}@{1}'.format(result, self.tag)
398+
elif tag and self.tag:
399+
result = '{0}:{1}'.format(result, self.tag)
400+
elif tag and explicit_tag:
401+
result = '{0}:{1}'.format(result, 'latest')
402+
403+
if registry and self.registry:
404+
result = '{0}/{1}'.format(self.registry, result)
405+
406+
return result
407+
408+
def get_repo(self, explicit_namespace=False):
409+
result = self.repo
410+
if self.namespace:
411+
result = '{0}/{1}'.format(self.namespace, result)
412+
elif explicit_namespace:
413+
result = '{0}/{1}'.format('library', result)
414+
return result
415+
416+
def enclose(self, organization):
417+
if self.namespace == organization:
418+
return
419+
420+
repo_parts = [self.repo]
421+
if self.namespace:
422+
repo_parts.insert(0, self.namespace)
423+
424+
self.namespace = organization
425+
self.repo = '-'.join(repo_parts)
426+
427+
def __str__(self):
428+
return self.to_str(registry=True, tag=True)
429+
430+
def __repr__(self):
431+
return (
432+
"ImageName(registry={s.registry!r}, namespace={s.namespace!r},"
433+
" repo={s.repo!r}, tag={s.tag!r})"
434+
).format(s=self)
435+
436+
def __eq__(self, other):
437+
if type(other) == str:
438+
return self.__str__() == other
439+
elif type(other) == type(self):
440+
return self.__dict__ == other.__dict__
441+
else:
442+
return NotImplemented
443+
444+
def __hash__(self):
445+
return hash(self.to_str())
446+
447+
def copy(self):
448+
return ImageName(
449+
registry=self.registry,
450+
namespace=self.namespace,
451+
repo=self.repo,
452+
tag=self.tag)

0 commit comments

Comments
 (0)