1
1
use std:: borrow:: Cow ;
2
- #[ cfg( not( windows) ) ]
3
- use std:: fs;
4
2
use std:: io:: Write as _;
5
- #[ cfg( not( windows) ) ]
6
- use std:: os:: unix:: fs:: PermissionsExt as _;
7
- use std:: path:: { Path , PathBuf } ;
3
+ use std:: path:: Path ;
8
4
9
5
use anyhow:: { anyhow, bail, Context as _, Result } ;
10
6
use clap:: { Arg , ArgAction , ArgMatches , Command } ;
11
7
use indicatif:: ProgressStyle ;
12
- use itertools:: Itertools as _;
13
8
use log:: { debug, info, warn} ;
14
9
use sha1_smol:: Digest ;
15
10
use symbolic:: common:: ByteView ;
16
- use walkdir:: WalkDir ;
17
11
use zip:: write:: SimpleFileOptions ;
18
12
use zip:: { DateTime , ZipWriter } ;
19
13
@@ -28,7 +22,7 @@ use crate::utils::fs::TempFile;
28
22
use crate :: utils:: mobile_app:: {
29
23
handle_asset_catalogs, ipa_to_xcarchive, is_apple_app, is_ipa_file,
30
24
} ;
31
- use crate :: utils:: mobile_app:: { is_aab_file, is_apk_file, is_zip_file} ;
25
+ use crate :: utils:: mobile_app:: { is_aab_file, is_apk_file, is_zip_file, normalize_directory } ;
32
26
use crate :: utils:: progress:: ProgressBar ;
33
27
use crate :: utils:: vcs;
34
28
@@ -271,22 +265,6 @@ fn normalize_file(path: &Path, bytes: &[u8]) -> Result<TempFile> {
271
265
Ok ( temp_file)
272
266
}
273
267
274
- fn sort_entries ( path : & Path ) -> Result < std:: vec:: IntoIter < ( PathBuf , PathBuf ) > > {
275
- Ok ( WalkDir :: new ( path)
276
- . follow_links ( true )
277
- . into_iter ( )
278
- . filter_map ( Result :: ok)
279
- . filter ( |entry| entry. path ( ) . is_file ( ) )
280
- . map ( |entry| {
281
- let entry_path = entry. into_path ( ) ;
282
- let relative_path = entry_path. strip_prefix ( path) ?. to_owned ( ) ;
283
- Ok ( ( entry_path, relative_path) )
284
- } )
285
- . collect :: < Result < Vec < _ > > > ( ) ?
286
- . into_iter ( )
287
- . sorted_by ( |( _, a) , ( _, b) | a. cmp ( b) ) )
288
- }
289
-
290
268
fn handle_directory ( path : & Path ) -> Result < TempFile > {
291
269
let temp_dir = TempDir :: create ( ) ?;
292
270
#[ cfg( all( target_os = "macos" , target_arch = "aarch64" ) ) ]
@@ -296,78 +274,6 @@ fn handle_directory(path: &Path) -> Result<TempFile> {
296
274
normalize_directory ( path, temp_dir. path ( ) )
297
275
}
298
276
299
- // For XCArchive directories, we'll zip the entire directory
300
- fn normalize_directory ( path : & Path , parsed_assets_path : & Path ) -> Result < TempFile > {
301
- debug ! ( "Creating normalized zip for directory: {}" , path. display( ) ) ;
302
-
303
- let temp_file = TempFile :: create ( ) ?;
304
- let mut zip = ZipWriter :: new ( temp_file. open ( ) ?) ;
305
-
306
- let mut file_count = 0 ;
307
- let directory_name = path. file_name ( ) . expect ( "Failed to get basename" ) ;
308
-
309
- // Collect and sort entries for deterministic ordering
310
- // This is important to ensure stable sha1 checksums for the zip file as
311
- // an optimization is used to avoid re-uploading the same chunks if they're already on the server.
312
- let entries = sort_entries ( path) ?;
313
-
314
- // Need to set the last modified time to a fixed value to ensure consistent checksums
315
- // This is important as an optimization to avoid re-uploading the same chunks if they're already on the server
316
- // but the last modified time being different will cause checksums to be different.
317
- let options = SimpleFileOptions :: default ( )
318
- . compression_method ( zip:: CompressionMethod :: Stored )
319
- . last_modified_time ( DateTime :: default ( ) ) ;
320
-
321
- for ( entry_path, relative_path) in entries {
322
- let zip_path = format ! (
323
- "{}/{}" ,
324
- directory_name. to_string_lossy( ) ,
325
- relative_path. to_string_lossy( )
326
- ) ;
327
- debug ! ( "Adding file to zip: {}" , zip_path) ;
328
-
329
- #[ cfg( not( windows) ) ]
330
- // On Unix, we need to preserve the file permissions.
331
- let options = options. unix_permissions ( fs:: metadata ( & entry_path) ?. permissions ( ) . mode ( ) ) ;
332
-
333
- zip. start_file ( zip_path, options) ?;
334
- let file_byteview = ByteView :: open ( & entry_path) ?;
335
- zip. write_all ( file_byteview. as_slice ( ) ) ?;
336
- file_count += 1 ;
337
- }
338
-
339
- // Add parsed assets to the zip in a "ParsedAssets" directory
340
- if parsed_assets_path. exists ( ) {
341
- debug ! (
342
- "Adding parsed assets from: {}" ,
343
- parsed_assets_path. display( )
344
- ) ;
345
-
346
- let parsed_assets_entries = sort_entries ( parsed_assets_path) ?;
347
-
348
- for ( entry_path, relative_path) in parsed_assets_entries {
349
- let zip_path = format ! (
350
- "{}/ParsedAssets/{}" ,
351
- directory_name. to_string_lossy( ) ,
352
- relative_path. to_string_lossy( )
353
- ) ;
354
- debug ! ( "Adding parsed asset to zip: {}" , zip_path) ;
355
-
356
- zip. start_file ( zip_path, options) ?;
357
- let file_byteview = ByteView :: open ( & entry_path) ?;
358
- zip. write_all ( file_byteview. as_slice ( ) ) ?;
359
- file_count += 1 ;
360
- }
361
- }
362
-
363
- zip. finish ( ) ?;
364
- debug ! (
365
- "Successfully created normalized zip for directory with {} files" ,
366
- file_count
367
- ) ;
368
- Ok ( temp_file)
369
- }
370
-
371
277
fn upload_file (
372
278
api : & AuthenticatedApi ,
373
279
bytes : & [ u8 ] ,
0 commit comments