33// MPL was not distributed with this file, You can
44// obtain one at https://mozilla.org/MPL/2.0/.
55
6- use crate :: repository:: { ReadableRepository , FileBackend , RepositoryError , Result , WritableRepository , ProgressReporter , ProgressInfo , NoopProgressReporter } ;
7- use crate :: fmri:: Fmri ;
86use crate :: actions:: Manifest ;
7+ use crate :: fmri:: Fmri ;
8+ use crate :: repository:: {
9+ FileBackend , NoopProgressReporter , ProgressInfo , ProgressReporter , ReadableRepository ,
10+ RepositoryError , Result , WritableRepository ,
11+ } ;
912use std:: collections:: HashSet ;
1013use tempfile:: tempdir;
11- use tracing:: { info , debug } ;
14+ use tracing:: { debug , info } ;
1215
1316/// PackageReceiver handles downloading packages from a source repository
1417/// and storing them in a destination repository.
@@ -21,7 +24,11 @@ pub struct PackageReceiver<'a, S: ReadableRepository> {
2124impl < ' a , S : ReadableRepository > PackageReceiver < ' a , S > {
2225 /// Create a new PackageReceiver
2326 pub fn new ( source : & ' a mut S , dest : FileBackend ) -> Self {
24- Self { source, dest, progress : None }
27+ Self {
28+ source,
29+ dest,
30+ progress : None ,
31+ }
2532 }
2633
2734 /// Set the progress reporter
@@ -37,7 +44,12 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
3744 /// * `default_publisher` - The default publisher name if not specified in FMRI
3845 /// * `fmris` - List of FMRIs to receive
3946 /// * `recursive` - Whether to receive dependencies recursively
40- pub fn receive ( & mut self , default_publisher : Option < & str > , fmris : & [ Fmri ] , recursive : bool ) -> Result < ( ) > {
47+ pub fn receive (
48+ & mut self ,
49+ default_publisher : Option < & str > ,
50+ fmris : & [ Fmri ] ,
51+ recursive : bool ,
52+ ) -> Result < ( ) > {
4153 let mut processed = HashSet :: new ( ) ;
4254 let mut queue: Vec < Fmri > = fmris. to_vec ( ) ;
4355 let mut updated_publishers = HashSet :: new ( ) ;
@@ -53,36 +65,55 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
5365 while let Some ( fmri) = queue. pop ( ) {
5466 // If the FMRI doesn't have a version, we need to find the newest one
5567 let fmris_to_fetch = if fmri. version . is_none ( ) {
56- let publisher = fmri. publisher . as_deref ( ) . or ( default_publisher) . ok_or_else ( || {
57- RepositoryError :: Other ( format ! ( "No publisher specified for package {}" , fmri. name) )
58- } ) ?;
68+ let publisher =
69+ fmri. publisher
70+ . as_deref ( )
71+ . or ( default_publisher)
72+ . ok_or_else ( || {
73+ RepositoryError :: Other ( format ! (
74+ "No publisher specified for package {}" ,
75+ fmri. name
76+ ) )
77+ } ) ?;
5978
60- overall_progress = overall_progress. with_context ( format ! ( "Looking up newest version for {}" , fmri. name) ) ;
79+ overall_progress = overall_progress
80+ . with_context ( format ! ( "Looking up newest version for {}" , fmri. name) ) ;
6181 progress. update ( & overall_progress) ;
6282
6383 debug ! ( "No version specified for {}, looking up newest" , fmri. name) ;
64- let pkgs = self . source . list_packages ( Some ( publisher) , Some ( & fmri. name ) ) ?;
65-
84+ let pkgs = self
85+ . source
86+ . list_packages ( Some ( publisher) , Some ( & fmri. name ) ) ?;
87+
6688 // Group by package name to find the newest version for each
67- let mut by_name: std:: collections:: HashMap < String , Vec < crate :: repository:: PackageInfo > > = std:: collections:: HashMap :: new ( ) ;
89+ let mut by_name: std:: collections:: HashMap <
90+ String ,
91+ Vec < crate :: repository:: PackageInfo > ,
92+ > = std:: collections:: HashMap :: new ( ) ;
6893 for pi in pkgs {
6994 by_name. entry ( pi. fmri . name . clone ( ) ) . or_default ( ) . push ( pi) ;
7095 }
7196
7297 let mut results = Vec :: new ( ) ;
7398 for ( name, versions) in by_name {
74- let newest = versions. into_iter ( ) . max_by ( |a , b| {
75- a . fmri . to_string ( ) . cmp ( & b . fmri . to_string ( ) )
76- } ) ;
99+ let newest = versions
100+ . into_iter ( )
101+ . max_by ( |a , b| a . fmri . to_string ( ) . cmp ( & b . fmri . to_string ( ) ) ) ;
77102 if let Some ( pi) = newest {
78103 results. push ( pi. fmri ) ;
79104 } else {
80- info ! ( "Package {} not found in source for publisher {}" , name, publisher) ;
105+ info ! (
106+ "Package {} not found in source for publisher {}" ,
107+ name, publisher
108+ ) ;
81109 }
82110 }
83-
111+
84112 if results. is_empty ( ) {
85- info ! ( "Package {} not found in source for publisher {}" , fmri. name, publisher) ;
113+ info ! (
114+ "Package {} not found in source for publisher {}" ,
115+ fmri. name, publisher
116+ ) ;
86117 continue ;
87118 }
88119 // Update total_packages: remove the wildcard FMRI we just popped, and add actual results
@@ -93,9 +124,17 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
93124 } ;
94125
95126 for fmri_to_fetch in fmris_to_fetch {
96- let publisher_name = fmri_to_fetch. publisher . as_deref ( ) . or ( default_publisher) . ok_or_else ( || {
97- RepositoryError :: Other ( format ! ( "No publisher specified for package {}" , fmri_to_fetch. name) )
98- } ) ?. to_string ( ) ;
127+ let publisher_name = fmri_to_fetch
128+ . publisher
129+ . as_deref ( )
130+ . or ( default_publisher)
131+ . ok_or_else ( || {
132+ RepositoryError :: Other ( format ! (
133+ "No publisher specified for package {}" ,
134+ fmri_to_fetch. name
135+ ) )
136+ } ) ?
137+ . to_string ( ) ;
99138
100139 if !processed. insert ( fmri_to_fetch. clone ( ) ) {
101140 // If we already processed it (possibly as a dependency), don't count it again
@@ -110,7 +149,10 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
110149 . with_context ( format ! ( "Receiving {}" , fmri_to_fetch) ) ;
111150 progress. update ( & overall_progress) ;
112151
113- info ! ( "Receiving package {} from publisher {}" , fmri_to_fetch, publisher_name) ;
152+ info ! (
153+ "Receiving package {} from publisher {}" ,
154+ fmri_to_fetch, publisher_name
155+ ) ;
114156 let manifest = self . receive_one ( & publisher_name, & fmri_to_fetch) ?;
115157 updated_publishers. insert ( publisher_name. clone ( ) ) ;
116158
@@ -121,10 +163,10 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
121163 if dep_fmri. publisher . is_none ( ) {
122164 dep_fmri. publisher = Some ( publisher_name. clone ( ) ) ;
123165 }
124-
166+
125167 if !processed. contains ( & dep_fmri) && queued. insert ( dep_fmri. clone ( ) ) {
126- total_packages += 1 ;
127- queue. push ( dep_fmri) ;
168+ total_packages += 1 ;
169+ queue. push ( dep_fmri) ;
128170 }
129171 }
130172 }
@@ -134,7 +176,8 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
134176
135177 for pub_name in updated_publishers {
136178 info ! ( "Rebuilding metadata for publisher {}" , pub_name) ;
137- overall_progress = overall_progress. with_context ( format ! ( "Rebuilding metadata for {}" , pub_name) ) ;
179+ overall_progress =
180+ overall_progress. with_context ( format ! ( "Rebuilding metadata for {}" , pub_name) ) ;
138181 progress. update ( & overall_progress) ;
139182 self . dest . rebuild ( Some ( & pub_name) , false , false ) ?;
140183 }
@@ -147,10 +190,11 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
147190 /// Receive a single package
148191 fn receive_one ( & mut self , publisher : & str , fmri : & Fmri ) -> Result < Manifest > {
149192 let progress = self . progress . unwrap_or ( & NoopProgressReporter ) ;
150-
193+
151194 let manifest_text = self . source . fetch_manifest_text ( publisher, fmri) ?;
152- let manifest = Manifest :: parse_string ( manifest_text. clone ( ) ) . map_err ( RepositoryError :: from) ?;
153-
195+ let manifest =
196+ Manifest :: parse_string ( manifest_text. clone ( ) ) . map_err ( RepositoryError :: from) ?;
197+
154198 // Ensure publisher exists in destination
155199 let dest_info = self . dest . get_info ( ) ?;
156200 if !dest_info. publishers . iter ( ) . any ( |p| p. name == publisher) {
@@ -163,39 +207,50 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
163207 txn. set_legacy_manifest ( manifest_text) ;
164208
165209 let temp_dir = tempdir ( ) . map_err ( RepositoryError :: IoError ) ?;
166-
167- let payload_files: Vec < _ > = manifest. files . iter ( ) . filter ( |f| f. payload . is_some ( ) ) . collect ( ) ;
210+
211+ let payload_files: Vec < _ > = manifest
212+ . files
213+ . iter ( )
214+ . filter ( |f| f. payload . is_some ( ) )
215+ . collect ( ) ;
168216 let total_files = payload_files. len ( ) as u64 ;
169-
217+
170218 for ( i, file) in payload_files. into_iter ( ) . enumerate ( ) {
171219 if let Some ( payload) = & file. payload {
172220 let files_done = ( i + 1 ) as u64 ;
173221 let digest = & payload. primary_identifier . hash ;
174-
175- progress. update ( & ProgressInfo :: new ( format ! ( "Receiving payloads for {}" , fmri. name) )
176- . with_total ( total_files)
177- . with_current ( files_done)
178- . with_context ( format ! ( "Payload: {}" , digest) ) ) ;
222+
223+ progress. update (
224+ & ProgressInfo :: new ( format ! ( "Receiving payloads for {}" , fmri. name) )
225+ . with_total ( total_files)
226+ . with_current ( files_done)
227+ . with_context ( format ! ( "Payload: {}" , digest) ) ,
228+ ) ;
179229
180230 let temp_file_path = temp_dir. path ( ) . join ( digest) ;
181- debug ! ( "Fetching payload {} to {}" , digest, temp_file_path. display( ) ) ;
182- self . source . fetch_payload ( publisher, digest, & temp_file_path) ?;
231+ debug ! (
232+ "Fetching payload {} to {}" ,
233+ digest,
234+ temp_file_path. display( )
235+ ) ;
236+ self . source
237+ . fetch_payload ( publisher, digest, & temp_file_path) ?;
183238 txn. add_file ( file. clone ( ) , & temp_file_path) ?;
184239 }
185240 }
186241
187242 txn. update_manifest ( manifest. clone ( ) ) ;
188243 txn. commit ( ) ?;
189-
244+
190245 Ok ( manifest)
191246 }
192247}
193248
194249#[ cfg( test) ]
195250mod tests {
196251 use super :: * ;
197- use crate :: repository:: { FileBackend , RepositoryVersion } ;
198252 use crate :: actions:: Attr ;
253+ use crate :: repository:: { FileBackend , RepositoryVersion } ;
199254 use tempfile:: tempdir;
200255
201256 #[ test]
@@ -206,7 +261,7 @@ mod tests {
206261 // Create source repo with one package
207262 let mut source_repo = FileBackend :: create ( source_dir. path ( ) , RepositoryVersion :: V4 ) ?;
208263 source_repo. add_publisher ( "test" ) ?;
209-
264+
210265 let fmri = Fmri :: parse ( "pkg://test/pkgA@1.0" ) . unwrap ( ) ;
211266 let mut manifest = Manifest :: new ( ) ;
212267 manifest. attributes . push ( Attr {
@@ -245,15 +300,18 @@ mod tests {
245300 // Create source repo
246301 let mut source_repo = FileBackend :: create ( source_dir. path ( ) , RepositoryVersion :: V4 ) ?;
247302 source_repo. add_publisher ( "test" ) ?;
248-
303+
249304 let _fmri = Fmri :: parse ( "pkg://test/pkgA@1.0" ) . unwrap ( ) ;
250- let manifest_content = "set name=pkg.fmri value=pkg://test/pkgA@1.0\n set name=pkg.summary value=test\n " ;
251-
305+ let manifest_content =
306+ "set name=pkg.fmri value=pkg://test/pkgA@1.0\n set name=pkg.summary value=test\n " ;
307+
252308 // Manually write the manifest in IPS format to the source repo
253- let manifest_path = FileBackend :: construct_manifest_path ( source_dir. path ( ) , "test" , "pkgA" , "1.0" ) ;
254- std:: fs:: create_dir_all ( manifest_path. parent ( ) . unwrap ( ) ) . map_err ( RepositoryError :: IoError ) ?;
309+ let manifest_path =
310+ FileBackend :: construct_manifest_path ( source_dir. path ( ) , "test" , "pkgA" , "1.0" ) ;
311+ std:: fs:: create_dir_all ( manifest_path. parent ( ) . unwrap ( ) )
312+ . map_err ( RepositoryError :: IoError ) ?;
255313 std:: fs:: write ( & manifest_path, manifest_content) . map_err ( RepositoryError :: IoError ) ?;
256-
314+
257315 // Rebuild source repo to recognize the package
258316 source_repo. rebuild ( Some ( "test" ) , false , false ) ?;
259317
@@ -264,9 +322,11 @@ mod tests {
264322 receiver. receive ( Some ( "test" ) , & [ Fmri :: new ( "pkgA" ) ] , false ) ?;
265323
266324 // Verify dest repo has the package and the manifest is in IPS format
267- let dest_manifest_path = FileBackend :: construct_manifest_path ( dest_dir. path ( ) , "test" , "pkgA" , "1.0" ) ;
268- let content = std:: fs:: read_to_string ( & dest_manifest_path) . map_err ( RepositoryError :: IoError ) ?;
269-
325+ let dest_manifest_path =
326+ FileBackend :: construct_manifest_path ( dest_dir. path ( ) , "test" , "pkgA" , "1.0" ) ;
327+ let content =
328+ std:: fs:: read_to_string ( & dest_manifest_path) . map_err ( RepositoryError :: IoError ) ?;
329+
270330 assert_eq ! ( content, manifest_content) ;
271331 assert ! ( !content. starts_with( '{' ) , "Manifest should not be JSON" ) ;
272332
@@ -275,9 +335,16 @@ mod tests {
275335 let mut filename = json_path. file_name ( ) . unwrap ( ) . to_os_string ( ) ;
276336 filename. push ( ".json" ) ;
277337 json_path. set_file_name ( filename) ;
278- assert ! ( json_path. exists( ) , "JSON manifest should exist at {}" , json_path. display( ) ) ;
338+ assert ! (
339+ json_path. exists( ) ,
340+ "JSON manifest should exist at {}" ,
341+ json_path. display( )
342+ ) ;
279343 let json_content = std:: fs:: read_to_string ( & json_path) . map_err ( RepositoryError :: IoError ) ?;
280- assert ! ( json_content. starts_with( '{' ) , "JSON manifest should be JSON" ) ;
344+ assert ! (
345+ json_content. starts_with( '{' ) ,
346+ "JSON manifest should be JSON"
347+ ) ;
281348
282349 Ok ( ( ) )
283350 }
0 commit comments