@@ -39,20 +39,27 @@ pub fn load_credentials(repo: &str) -> Result<RegistryAuth, CredentialRetrievalE
3939#[ derive( Clone ) ]
4040pub struct Registry {
4141 client : Client ,
42+ use_monolithic_push : bool ,
4243 auth : RegistryAuth ,
4344}
4445
4546impl Registry {
46- pub fn with_config ( auth : RegistryAuth , insecure_registies : & [ String ] ) -> Self {
47+ pub fn with_config (
48+ auth : RegistryAuth ,
49+ insecure_registies : & [ String ] ,
50+ use_monolithic_push : bool ,
51+ ) -> Self {
4752 let config = ClientConfig {
4853 protocol : ClientProtocol :: HttpsExcept (
4954 [ insecure_registies, & [ "localhost" . to_string ( ) ] ] . concat ( ) ,
5055 ) ,
56+ use_monolithic_push,
5157 ..ClientConfig :: default ( )
5258 } ;
5359
5460 Self {
5561 client : Client :: new ( config) ,
62+ use_monolithic_push,
5663 auth,
5764 }
5865 }
@@ -74,23 +81,40 @@ impl Registry {
7481 }
7582 }
7683
77- pub async fn push (
84+ async fn monolithic_push (
7885 & mut self ,
7986 mut progress : Item ,
8087 image_ref : & Reference ,
8188 image : Image ,
8289 ) -> Result < Option < PushResponse > , PushError > {
83- let registry = image_ref . resolve_registry ( ) ;
84- self . client . store_auth_if_needed ( registry , & self . auth ) . await ;
90+ progress . init ( None , None ) ;
91+ progress . info ( "pushing image" ) ;
8592
86- if let Some ( digest) = self . try_resolve_digest ( & self . auth , image_ref) . await ? {
87- // If the digest matches the image's digest, we can skip pushing
88- if digest == image. digest {
89- progress. info ( "image already exists, skipping push" ) ;
90- return Ok ( None ) ;
91- }
92- }
93+ let image_urls = self
94+ . client
95+ . push (
96+ image_ref,
97+ & image. layers ,
98+ image. config ,
99+ & self . auth ,
100+ image. manifest . into ( ) ,
101+ )
102+ . await ?;
103+
104+ progress. done ( "image pushed" ) ;
93105
106+ Ok ( Some ( PushResponse {
107+ config_url : image_urls. config_url ,
108+ manifest_url : image_urls. manifest_url ,
109+ } ) )
110+ }
111+
112+ async fn layered_push (
113+ & mut self ,
114+ mut progress : Item ,
115+ image_ref : & Reference ,
116+ image : Image ,
117+ ) -> Result < Option < PushResponse > , PushError > {
94118 progress. init ( Some ( image. layers . len ( ) ) , None ) ;
95119 progress. info ( "pushing image" ) ;
96120
@@ -118,10 +142,12 @@ impl Registry {
118142 // Retry on digest mismatch (400) and invalid range (416) errors.
119143 // Root cause unknown; we should probably look into this but retry is safe for now.
120144 // Retrying on 5xx server errors is also acceptable.
121- Err ( e @ OciDistributionError :: ServerError {
122- code : 400 | 416 | 500 ..599 ,
123- ..
124- } ) => {
145+ Err (
146+ e @ OciDistributionError :: ServerError {
147+ code : 400 | 416 | 500 ..599 ,
148+ ..
149+ } ,
150+ ) => {
125151 last_err = Some ( e) ;
126152 tokio:: time:: sleep ( Duration :: from_secs ( i * 2 ) ) . await ;
127153 }
@@ -160,4 +186,28 @@ impl Registry {
160186 manifest_url,
161187 } ) )
162188 }
189+
190+ pub async fn push (
191+ & mut self ,
192+ mut progress : Item ,
193+ image_ref : & Reference ,
194+ image : Image ,
195+ ) -> Result < Option < PushResponse > , PushError > {
196+ let registry = image_ref. resolve_registry ( ) ;
197+ self . client . store_auth_if_needed ( registry, & self . auth ) . await ;
198+
199+ if let Some ( digest) = self . try_resolve_digest ( & self . auth , image_ref) . await ? {
200+ // If the digest matches the image's digest, we can skip pushing
201+ if digest == image. digest {
202+ progress. info ( "image already exists, skipping push" ) ;
203+ return Ok ( None ) ;
204+ }
205+ }
206+
207+ if self . use_monolithic_push {
208+ return self . monolithic_push ( progress, image_ref, image) . await ;
209+ }
210+
211+ self . layered_push ( progress, image_ref, image) . await
212+ }
163213}
0 commit comments