diff --git a/bindings-python/build/lib/gci/__init__.py b/bindings-python/build/lib/gci/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/bindings-python/build/lib/gci/componentmodel.py b/bindings-python/build/lib/gci/componentmodel.py new file mode 100644 index 00000000..b6bdc650 --- /dev/null +++ b/bindings-python/build/lib/gci/componentmodel.py @@ -0,0 +1,169 @@ +import dataclasses +import enum +import io +import typing + +import dacite +import yaml + +dc = dataclasses.dataclass + + +class SchemaVersion(enum.Enum): + V1 = 'v1' + V2 = 'v2' + + +class AccessType(enum.Enum): + OCI_REGISTRY = 'ociRegistry' + GITHUB = 'github' + HTTP = 'http' + NONE = 'None' # the resource is only declared informally (e.g. generic) + + +class SourceType(enum.Enum): + GIT = 'git' + + +class ResourceType(enum.Enum): + OCI_IMAGE = 'ociImage' + GENERIC = 'generic' + + +@dc(frozen=True) +class ResourceAccess: + type: AccessType + + +@dc(frozen=True) +class OciAccess(ResourceAccess): + imageReference: str + + +@dc(frozen=True) +class GithubAccess(ResourceAccess): + repoUrl: str + ref: str + type: AccessType + + +@dc(frozen=True) +class HttpAccess(ResourceAccess): + url: str + + +@dc(frozen=True) +class Label: + name: str + value: typing.Union[str, int, float, bool, dict] + + +class Provider(enum.Enum): + ''' + internal: from repositoryContext-owner + external: from 3rd-party (not repositoryContext-owner) + ''' + INTERNAL = 'internal' + EXTERNAL = 'external' + + +@dc(frozen=True) +class Metadata: + schemaVersion: SchemaVersion = SchemaVersion.V2 + + + +@dc(frozen=True) +class ComponentReference: + name: str + version: str + labels: typing.List[Label] = dataclasses.field(default_factory=list) + + +@dc(frozen=True) +class Resource: + name: str + version: str + type: ResourceType + access: typing.Union[ + ResourceAccess, + OciAccess, + GithubAccess, + HttpAccess, + None + ] + labels: typing.List[Label] = dataclasses.field(default_factory=list) + + +@dc +class RepositoryContext: + baseUrl: str + type: AccessType = AccessType.OCI_REGISTRY + + +@dc +class ComponentSource: + name: str + access: typing.Union[ + GithubAccess, + ] + type: SourceType = SourceType.GIT + labels: typing.List[Label] = dataclasses.field(default_factory=list) + + +@dc +class Component: + name: str # must be valid URL w/o schema + version: str # relaxed semver + + repositoryContexts: typing.List[RepositoryContext] + provider: Provider + + sources: typing.List[ComponentSource] + componentReferences: typing.List[ComponentReference] + localResources: typing.List[Resource] + externalResources: typing.List[Resource] + + labels: typing.List[Label] = dataclasses.field(default_factory=list) + + +@dc +class ComponentDescriptor: + meta: Metadata + component: Component + + @staticmethod + def from_dict(component_descriptor_dict: dict): + component_descriptor = dacite.from_dict( + data_class=ComponentDescriptor, + data=component_descriptor_dict, + config=dacite.Config( + cast=[ + AccessType, + Provider, + ResourceType, + SchemaVersion, + SourceType, + ] + ) + ) + + return component_descriptor + + def to_fobj(self, fileobj: io.BytesIO): + raw_dict = dataclasses.asdict(self) + yaml.dump( + data=raw_dict, + stream=fileobj, + Dumper=EnumValueYamlDumper, + ) + + +class EnumValueYamlDumper(yaml.SafeDumper): + ''' + a yaml.SafeDumper that will dump enum objects using their values + ''' + def represent_data(self, data): + if isinstance(data, enum.Enum): + return self.represent_data(data.value) + return super().represent_data(data) diff --git a/bindings-python/build/lib/gci/oci.py b/bindings-python/build/lib/gci/oci.py new file mode 100644 index 00000000..e607f845 --- /dev/null +++ b/bindings-python/build/lib/gci/oci.py @@ -0,0 +1,57 @@ +import dataclasses +import io +import logging +import os +import tarfile +import typing +import yaml + +import gci.componentmodel + +logger = logging.getLogger(__name__) + +component_descriptor_fname = 'component-descriptor.yaml' + + +def component_descriptor_to_tarfileobj( + component_descriptor: typing.Union[dict, gci.componentmodel.ComponentDescriptor], +): + if not isinstance(component_descriptor, dict): + component_descriptor = dataclasses.asdict(component_descriptor) + + component_descriptor_buf = io.BytesIO( + yaml.dump( + data=component_descriptor, + Dumper=gci.componentmodel.EnumValueYamlDumper, + ).encode('utf-8') + ) + component_descriptor_buf.seek(0, os.SEEK_END) + component_descriptor_leng = component_descriptor_buf.tell() + component_descriptor_buf.seek(0) + + tar_buf = io.BytesIO() + + tf = tarfile.open(mode='w', fileobj=tar_buf) + + tar_info = tarfile.TarInfo(name=component_descriptor_fname) + tar_info.size = component_descriptor_leng + + tf.addfile(tarinfo=tar_info, fileobj=component_descriptor_buf) + tf.fileobj.seek(0) + + return tf.fileobj + + +def component_descriptor_from_tarfileobj( + fileobj: io.BytesIO, +): + with tarfile.open(fileobj=fileobj, mode='r') as tf: + component_descriptor_info = tf.getmember(component_descriptor_fname) + raw_dict = yaml.safe_load(tf.extractfile(component_descriptor_info).read()) + + logger.debug(raw_dict) + + if raw_dict is None: + raise ValueError('Component Descriptor appears to be empty') + + return gci.componentmodel.ComponentDescriptor.from_dict(raw_dict) diff --git a/bindings-python/dist/gardener-component-model-0.0.0.tar.gz b/bindings-python/dist/gardener-component-model-0.0.0.tar.gz new file mode 100644 index 00000000..c1a306c9 Binary files /dev/null and b/bindings-python/dist/gardener-component-model-0.0.0.tar.gz differ diff --git a/bindings-python/dist/gardener_component_model-0.0.0-py3-none-any.whl b/bindings-python/dist/gardener_component_model-0.0.0-py3-none-any.whl new file mode 100644 index 00000000..47e76ae4 Binary files /dev/null and b/bindings-python/dist/gardener_component_model-0.0.0-py3-none-any.whl differ diff --git a/bindings-python/gardener_component_model.egg-info/PKG-INFO b/bindings-python/gardener_component_model.egg-info/PKG-INFO new file mode 100644 index 00000000..ecd78013 --- /dev/null +++ b/bindings-python/gardener_component_model.egg-info/PKG-INFO @@ -0,0 +1,9 @@ +Metadata-Version: 1.2 +Name: gardener-component-model +Version: 0.0.0 +Summary: Gardener Component Model +Home-page: UNKNOWN +License: UNKNOWN +Description: UNKNOWN +Platform: UNKNOWN +Requires-Python: >=3.8.* diff --git a/bindings-python/gardener_component_model.egg-info/SOURCES.txt b/bindings-python/gardener_component_model.egg-info/SOURCES.txt new file mode 100644 index 00000000..4b584b00 --- /dev/null +++ b/bindings-python/gardener_component_model.egg-info/SOURCES.txt @@ -0,0 +1,9 @@ +setup.py +gardener_component_model.egg-info/PKG-INFO +gardener_component_model.egg-info/SOURCES.txt +gardener_component_model.egg-info/dependency_links.txt +gardener_component_model.egg-info/requires.txt +gardener_component_model.egg-info/top_level.txt +gci/__init__.py +gci/componentmodel.py +gci/oci.py \ No newline at end of file diff --git a/bindings-python/gardener_component_model.egg-info/dependency_links.txt b/bindings-python/gardener_component_model.egg-info/dependency_links.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/bindings-python/gardener_component_model.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/bindings-python/gardener_component_model.egg-info/requires.txt b/bindings-python/gardener_component_model.egg-info/requires.txt new file mode 100644 index 00000000..1f97717c --- /dev/null +++ b/bindings-python/gardener_component_model.egg-info/requires.txt @@ -0,0 +1,2 @@ +jsonschema +PyYaml diff --git a/bindings-python/gardener_component_model.egg-info/top_level.txt b/bindings-python/gardener_component_model.egg-info/top_level.txt new file mode 100644 index 00000000..2e47c913 --- /dev/null +++ b/bindings-python/gardener_component_model.egg-info/top_level.txt @@ -0,0 +1 @@ +gci