4
4
# arguments provided by the user.
5
5
6
6
import argparse
7
+ import json
7
8
import os
8
9
import sys
9
10
from cosalib .container_manifest import create_and_push_container_manifest
10
11
from cosalib .builds import Builds
11
12
from cosalib .meta import GenericBuildMeta
13
+ from cosalib .utils import runcmd
12
14
from cosalib .cmdlib import sha256sum_file
13
15
14
16
sys .path .insert (0 , os .path .dirname (os .path .abspath (__file__ )))
15
17
16
18
17
19
def main ():
18
20
args = parse_args ()
21
+ map_arch = {}
22
+ map_arch ['arm64' ] = 'aarch64'
23
+ map_arch ['amd64' ] = 'x86_64'
24
+
19
25
if args .authfile :
20
26
os .environ ["REGISTRY_AUTH_FILE" ] = args .authfile
21
27
if args .images :
@@ -37,6 +43,18 @@ def main():
37
43
# - Store the path to the container image in the container_images list
38
44
images = []
39
45
buildmetas = dict ()
46
+ registry_digests = {}
47
+ upload = False
48
+ # Collect registry_digests of current manifest list in remote registry
49
+ inspect = skopeo_inspect (f'{ args .repo } :{ args .tags [0 ]} ' , args .authfile )
50
+ if inspect .returncode == 0 :
51
+ manifests = json .loads (inspect .stdout )
52
+ for manifest in manifests ['manifests' ]:
53
+ arch = manifest ['platform' ]['architecture' ]
54
+ if arch in map_arch :
55
+ arch = map_arch [arch ]
56
+ registry_digests [arch ] = manifest ['digest' ]
57
+
40
58
for arch in args .arches :
41
59
if arch not in build_arches :
42
60
print (f"Requested architecture { arch } is not in { args .build } " )
@@ -48,6 +66,13 @@ def main():
48
66
if not buildmeta ['images' ][args .artifact ]:
49
67
print (f"No artifact { args .artifact } in { args .build } /{ arch } " )
50
68
raise Exception
69
+
70
+ # Checks if the meta digest matches each arch digest in the remote.
71
+ # If it doesn't match (or doesn't exist), we need to upload.
72
+ if 'digest' in buildmetas [arch ][args .metajsonname ]:
73
+ meta_digest = buildmetas [arch ][args .metajsonname ]['digest' ]
74
+ if meta_digest != registry_digests .get (arch ):
75
+ upload = True
51
76
ociarchive = os .path .join (builddir , buildmeta ['images' ][args .artifact ]['path' ])
52
77
ocisha256sum = buildmeta ['images' ][args .artifact ]['sha256' ]
53
78
if not os .path .exists (ociarchive ):
@@ -58,6 +83,10 @@ def main():
58
83
raise Exception
59
84
images .append (f"oci-archive:{ ociarchive } " )
60
85
86
+ if not upload and not args .force :
87
+ print ("Remote already matches desired state; skipping push. Use --force to override." )
88
+ return
89
+
61
90
# Create/Upload the manifest list to the container registry
62
91
manifest_info = create_and_push_container_manifest (
63
92
args .repo , args .tags , images , args .v2s2 )
@@ -68,10 +97,8 @@ def main():
68
97
assert len (manifest_info ['manifests' ]) == len (buildmetas )
69
98
for manifest in manifest_info ['manifests' ]:
70
99
arch = manifest ['platform' ]['architecture' ]
71
- if arch == 'arm64' :
72
- arch = 'aarch64'
73
- elif arch == 'amd64' :
74
- arch = 'x86_64'
100
+ if arch in map_arch :
101
+ arch = map_arch [arch ]
75
102
buildmetas [arch ][args .metajsonname ] = {
76
103
'image' : args .repo ,
77
104
'digest' : manifest ['digest' ]
@@ -107,6 +134,7 @@ Examples:
107
134
parser .add_argument ("--authfile" , help = "A file to use for registry auth" )
108
135
parser .add_argument ('--v2s2' , action = 'store_true' ,
109
136
help = 'Use old image manifest version 2 schema 2 format' )
137
+ parser .add_argument ("--force" , help = "Force manifest overwriting" , action = 'store_true' )
110
138
111
139
group = parser .add_mutually_exclusive_group (required = True )
112
140
group .add_argument ("--image" , dest = 'images' , action = 'append' , default = [],
@@ -126,5 +154,12 @@ Examples:
126
154
return parser .parse_args ()
127
155
128
156
157
+ def skopeo_inspect (fqin , authfile ):
158
+ args = ['skopeo' , 'inspect' , '--raw' ]
159
+ if authfile :
160
+ args += ['--authfile' , authfile ]
161
+ return runcmd ((args + [f'docker://{ fqin } ' ]), capture_output = True , check = False )
162
+
163
+
129
164
if __name__ == '__main__' :
130
165
sys .exit (main ())
0 commit comments