Skip to content

Commit

Permalink
Move ImageName from osbs-client to util.
Browse files Browse the repository at this point in the history
Refactor to keep string behavior identical for parser.
  • Loading branch information
tim-vk committed Nov 30, 2022
1 parent 1d4f9fa commit f6502b9
Show file tree
Hide file tree
Showing 3 changed files with 428 additions and 226 deletions.
6 changes: 4 additions & 2 deletions dockerfile_parse/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from .constants import DOCKERFILE_FILENAME, COMMENT_INSTRUCTION
from .util import (b2u, extract_key_values, get_key_val_dictionary,
u2b, Context, WordSplitter)
u2b, Context, WordSplitter, ImageName)


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -880,7 +880,9 @@ def image_from(from_value):
)?
""")
match = re.match(regex, from_value)
return match.group('image', 'name') if match else (None, None)
image = ImageName.parse(match.group('image')) if match else None
name = match.group('name') if match else None
return image, name


def _endline(line):
Expand Down
126 changes: 124 additions & 2 deletions dockerfile_parse/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ class WordSplitter(object):
SQUOTE = "'"
DQUOTE = '"'

def __init__(self, s, args=None, envs=None):
def __init__(self, s: str, args=None, envs=None):
"""
:param s: str, string to process
:param args: dict, build arguments to use; if None, do not
attempt substitution
:param envs: dict, environment variables to use; if None, do not
attempt substitution
"""
self.stream = StringIO(s)
self.stream = StringIO(str(s))
self.args = args
self.envs = envs

Expand Down Expand Up @@ -332,3 +332,125 @@ def get_values(self, context_type):
if context_type.upper() == "LABEL":
return self.labels
raise ValueError("Unexpected context type: " + context_type)


class ImageName(object):
"""Represent an image.
Naming Conventions
==================
registry.somewhere/namespace/image_name:tag
|-----------------| registry, reg_uri
|---------| namespace
|--------------------------------------| repository
|--------------------| image name
|--| tag
|------------------------| image
|------------------------------------------| image
"""

def __init__(self, registry=None, namespace=None, repo=None, tag=None):
self.registry = registry
self.namespace = namespace
self.repo = repo
self.tag = tag

@classmethod
def parse(cls, image_name: str):
result = cls()

if not image_name or image_name.isspace():
return ImageName()

if isinstance(image_name, cls):
logger.debug("Attempting to parse ImageName %s as an ImageName", image_name)
return image_name

# registry.org/namespace/repo:tag
s = image_name.split('/', 2)

if len(s) == 2:
if '.' in s[0] or ':' in s[0]:
result.registry = s[0] if s[0] else None
else:
result.namespace = s[0]
elif len(s) == 3:
result.registry = s[0] if s[0] else None
result.namespace = s[1]
result.repo = s[-1]

for sep in '@:':
try:
result.repo, result.tag = result.repo.rsplit(sep, 1)
except ValueError:
continue
break

return result

def to_str(self, registry=True, tag=True, explicit_tag=False,
explicit_namespace=False):
if self.repo is None:
raise RuntimeError('No image repository specified')

result = self.get_repo(explicit_namespace)

if tag and self.tag and ':' in self.tag:
result = '{0}@{1}'.format(result, self.tag)
elif tag and self.tag:
result = '{0}:{1}'.format(result, self.tag)
elif tag and explicit_tag:
result = '{0}:{1}'.format(result, 'latest')

if registry and self.registry:
result = '{0}/{1}'.format(self.registry, result)

return result

def get_repo(self, explicit_namespace=False):
result = self.repo
if self.namespace:
result = '{0}/{1}'.format(self.namespace, result)
elif explicit_namespace:
result = '{0}/{1}'.format('library', result)
return result

def enclose(self, organization):
if self.namespace == organization:
return

repo_parts = [self.repo]
if self.namespace:
repo_parts.insert(0, self.namespace)

self.namespace = organization
self.repo = '-'.join(repo_parts)

def __str__(self):
return self.to_str(registry=True, tag=True)

def __repr__(self):
return (
"ImageName(registry={s.registry!r}, namespace={s.namespace!r},"
" repo={s.repo!r}, tag={s.tag!r})"
).format(s=self)

def __eq__(self, other):
if type(other) == str:
return self.__str__() == other
elif type(other) == type(self):
return self.__dict__ == other.__dict__
else:
return NotImplemented

def __ne__(self, other):
return not self == other

def __hash__(self):
return hash(self.to_str())

def copy(self):
return ImageName(
registry=self.registry,
namespace=self.namespace,
repo=self.repo,
tag=self.tag)
Loading

0 comments on commit f6502b9

Please sign in to comment.