Coverage for src/gitlabracadabra/containers/manifest.py: 71%

38 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-10 17:02 +0100

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/>. 

16 

17from __future__ import annotations 

18 

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 

29 

30 

31class Manifest(ManifestBase): 

32 """Retrieve Manifest or Manifest list.""" 

33 

34 def manifests(self) -> list[Manifest]: 

35 """Get manifests of the manifest list. 

36 

37 Returns: 

38 A list of manifests. 

39 

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) 

47 

48 def tag_list(self) -> list[str]: 

49 """Get tags of the manifest. 

50 

51 Returns: 

52 A list of tags (strings). 

53 

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 

67 

68 def blobs(self) -> list[Blob]: 

69 """Get blobs of the manifest. 

70 

71 Returns: 

72 A list of blobs. 

73 

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) 

100 

101 def _manifests_v2(self) -> list[Manifest]: 

102 json = dict(self.json) 

103 if json["mediaType"] not in {DOCKER_MANIFEST_SCHEMA2_LIST, OCI_IMAGE_INDEX}: 103 ↛ 104line 103 didn't jump to line 104 because the condition on line 103 was never true

104 msg = "Unexpected manifest list type {}".format(json["mediaType"]) 

105 raise ValueError(msg) 

106 if json["schemaVersion"] != 2: # noqa: PLR2004 106 ↛ 107line 106 didn't jump to line 107 because the condition on line 106 was never true

107 msg = "Unexpected manifest schema version {}".format(json["schemaVersion"]) 

108 raise ValueError(msg) 

109 manifests = [] 

110 for manifest_json in json["manifests"]: 

111 manifest = Manifest( 

112 self.registry, 

113 self.manifest_name, 

114 digest=manifest_json["digest"], 

115 size=manifest_json["size"], 

116 mime_type=manifest_json["mediaType"], 

117 tag=self.tag, 

118 ) 

119 manifest.platform = manifest_json["platform"] 

120 manifests.append(manifest) 

121 return manifests