Coverage for src/gitlabracadabra/containers/manifest.py: 72%
40 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-07 22:55 +0200
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-07 22:55 +0200
1#
2# Copyright (C) 2019-2025 Mathieu Parent <math.parent@gmail.com>
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU Lesser General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
17from __future__ import annotations
19from gitlabracadabra.containers.blob import Blob
20from gitlabracadabra.containers.const import (
21 DOCKER_MANIFEST_SCHEMA1,
22 DOCKER_MANIFEST_SCHEMA1_SIGNED,
23 DOCKER_MANIFEST_SCHEMA2,
24 DOCKER_MANIFEST_SCHEMA2_LIST,
25 OCI_IMAGE_INDEX,
26 OCI_IMAGE_MANIFEST,
27)
28from gitlabracadabra.containers.manifest_base import ManifestBase
31class Manifest(ManifestBase):
32 """Retrieve Manifest or Manifest list."""
34 def manifests(self) -> list[Manifest]:
35 """Get manifests of the manifest list.
37 Returns:
38 A list of manifests.
40 Raises:
41 ValueError: Unsupported manifest list type.
42 """
43 if self.mime_type in {DOCKER_MANIFEST_SCHEMA2_LIST, OCI_IMAGE_INDEX}: 43 ↛ 45line 43 didn't jump to line 45 because the condition on line 43 was always true
44 return self._manifests_v2()
45 msg = f"Unsupported manifest list type {self.mime_type}"
46 raise ValueError(msg)
48 def tag_list(self) -> list[str]:
49 """Get tags of the manifest.
51 Returns:
52 A list of tags (strings).
54 Raises:
55 ValueError: Expected list got something else.
56 """
57 response = self._registry.request(
58 "get",
59 f"/v2/{self.manifest_name}/tags/list",
60 scopes={self.scope()},
61 )
62 tags = response.json().get("tags")
63 if not isinstance(tags, list): 63 ↛ 64line 63 didn't jump to line 64 because the condition on line 63 was never true
64 msg = f"Expected list got {type(tags)}"
65 raise TypeError(msg)
66 return tags
68 def blobs(self) -> list[Blob]:
69 """Get blobs of the manifest.
71 Returns:
72 A list of blobs.
74 Raises:
75 ValueError: Unsupported media type.
76 """
77 if self.mime_type in {DOCKER_MANIFEST_SCHEMA2, OCI_IMAGE_MANIFEST}:
78 return [
79 Blob(
80 self.registry,
81 self.manifest_name,
82 layer_json["digest"],
83 size=layer_json["size"],
84 mime_type=layer_json["mediaType"],
85 )
86 for layer_json in self.json.get("layers")
87 ]
88 if self.mime_type in {DOCKER_MANIFEST_SCHEMA1, DOCKER_MANIFEST_SCHEMA1_SIGNED}: 88 ↛ 98line 88 didn't jump to line 98 because the condition on line 88 was always true
89 return [
90 Blob(
91 self.registry,
92 self.manifest_name,
93 fs_layer_json["blobSum"],
94 mime_type="application/octet-stream",
95 )
96 for fs_layer_json in self.json.get("fsLayers")
97 ]
98 msg = f"Unsupported media type: {self.mime_type}"
99 raise ValueError(msg)
101 def _manifests_v2(self) -> list[Manifest]:
102 json = dict(self.json)
103 schema_version = json.get("schemaVersion")
104 media_type = json.get("mediaType")
105 if schema_version != 2: # noqa: PLR2004 105 ↛ 106line 105 didn't jump to line 106 because the condition on line 105 was never true
106 msg = f"Unexpected schema version {schema_version} in OCI Image Index"
107 raise ValueError(msg)
108 if media_type not in {DOCKER_MANIFEST_SCHEMA2_LIST, OCI_IMAGE_INDEX, None}: 108 ↛ 109line 108 didn't jump to line 109 because the condition on line 108 was never true
109 msg = f"Unexpected media type {media_type} in OCI Image Index"
110 raise ValueError(msg)
111 manifests = []
112 for manifest_json in json["manifests"]:
113 manifest = Manifest(
114 self.registry,
115 self.manifest_name,
116 digest=manifest_json["digest"],
117 size=manifest_json["size"],
118 mime_type=manifest_json["mediaType"],
119 tag=self.tag,
120 )
121 manifest.platform = manifest_json["platform"]
122 manifests.append(manifest)
123 return manifests