@@ -33,7 +33,7 @@ type StartMultipartUploadResponse struct {
3333type StartMultipartUploadRequest struct {
3434 FileSize int64 `json:"fileSize"`
3535}
36- type MultipartPresignedURl struct {
36+ type MultipartPresignedURL struct {
3737 ObjectName string `json:"objectName"`
3838 UploadID string `json:"UploadID"`
3939 PartNumber int `json:"partNumber"`
@@ -225,6 +225,9 @@ func (u *UploadsHTTPWrapper) UploadFileInMultipart(sourcesFile string, featureFl
225225 clientTimeout := viper .GetUint (commonParams .ClientTimeoutKey )
226226 path := viper .GetString (commonParams .CompleteMultipartUploadPathEnv )
227227 jsonBytes , err := json .Marshal (completeMultipartUpload )
228+ if err != nil {
229+ return nil , errors .Errorf ("Failed to marshal complete multipart upload request body - %s" , err .Error ())
230+ }
228231 resp , err := SendHTTPRequest (http .MethodPost , path , bytes .NewBuffer (jsonBytes ), true , clientTimeout )
229232 if err != nil {
230233 return nil , err
@@ -252,6 +255,9 @@ func startMultipartUpload(startMultipartUploadRequest StartMultipartUploadReques
252255 clientTimeout := viper .GetUint (commonParams .ClientTimeoutKey )
253256 path := viper .GetString (commonParams .StartMultiPartUploadPathEnv )
254257 jsonBytes , err := json .Marshal (startMultipartUploadRequest )
258+ if err != nil {
259+ return StartMultipartUploadResponse {}, errors .Errorf ("Failed to marshal start multipart upload request body - %s" , err .Error ())
260+ }
255261 resp , err := SendHTTPRequest (http .MethodPost , path , bytes .NewBuffer (jsonBytes ), true , clientTimeout )
256262 if err != nil {
257263 return StartMultipartUploadResponse {}, err
@@ -286,12 +292,12 @@ func getPresignedURLForMultipartUploading(response StartMultipartUploadResponse,
286292 clientTimeout := viper .GetUint (commonParams .ClientTimeoutKey )
287293 path := viper .GetString (commonParams .MultipartPresignedPathEnv )
288294
289- multipartPresignedURl := MultipartPresignedURl {
295+ multipartPresignedURL := MultipartPresignedURL {
290296 ObjectName : response .ObjectName ,
291297 UploadID : response .UploadID ,
292298 PartNumber : partNumber ,
293299 }
294- jsonBytes , err := json .Marshal (multipartPresignedURl )
300+ jsonBytes , err := json .Marshal (multipartPresignedURL )
295301 if err != nil {
296302 return "" , errors .Errorf ("Failed to marshal multipart upload presigned URL request body - %s" , err .Error ())
297303 }
@@ -329,7 +335,7 @@ func getPresignedURLForMultipartUploading(response StartMultipartUploadResponse,
329335 }
330336}
331337
332- func uploadPart (preSignedURL string , sourcesFile string , featureFlagsWrapper FeatureFlagsWrapper ) (string , error ) {
338+ func uploadPart (preSignedURL , sourcesFile string , featureFlagsWrapper FeatureFlagsWrapper ) (string , error ) {
333339 if preSignedURL == "" {
334340 return "" , errors .New ("preSignedURL is empty or nil" )
335341 }
@@ -383,41 +389,16 @@ func uploadPart(preSignedURL string, sourcesFile string, featureFlagsWrapper Fea
383389}
384390
385391func SplitZipBySizeGB (zipFilePath string ) ([]string , error ) {
386-
387- // Get part size in GB from config if config is not provided, default to 2 GB
388- partChunkSizeStr := viper .GetString (commonParams .MultipartFileSize )
389- partChunkSizeFloat , err := strconv .ParseFloat (partChunkSizeStr , 64 )
392+ partSizeBytes , err := getPartSizeBytes ()
390393 if err != nil {
391- return nil , fmt .Errorf ("invalid part size value: %w" , err )
392- }
393- // Truncate to integer
394- truncatedSize := int64 (partChunkSizeFloat )
395- if truncatedSize < 1 || truncatedSize > 5 {
396- // Enforce part size to be between 1 GB and 5 GB.
397- // If the configured part size is outside this range, default to 2 GB.
398- logger .PrintIfVerbose (fmt .Sprintf ("Configured part size %d GB is outside the allowed range (1 – 5 GB). Defaulting to 2 GB." , truncatedSize ))
399- truncatedSize = 2 // default to 2 GB if out of range
400- }
401- partSizeGB := float64 (truncatedSize )
402-
403- logger .PrintIfVerbose ("Splitting zip file into parts of size: " + fmt .Sprintf ("%.0f" , partSizeGB ) + " GB" )
404-
405- if partSizeGB <= 0 {
406- return nil , fmt .Errorf ("part size must be greater than 0 GB" )
394+ return nil , err
407395 }
408396
409- const bytesPerGB = 1024 * 1024 * 1024
410- partSizeBytes := int64 (partSizeGB * float64 (bytesPerGB ))
411-
412397 f , err := os .Open (zipFilePath )
413398 if err != nil {
414399 return nil , fmt .Errorf ("open input - %w" , err )
415400 }
416- defer func () {
417- if err := f .Close (); err != nil {
418- logger .PrintfIfVerbose ("warning: failed to close input file - %v" , err )
419- }
420- }()
401+ defer closeFileVerbose (f )
421402
422403 stat , err := f .Stat ()
423404 if err != nil {
@@ -427,12 +408,40 @@ func SplitZipBySizeGB(zipFilePath string) ([]string, error) {
427408 return nil , fmt .Errorf ("input file is empty" )
428409 }
429410
430- totalSize := stat .Size ()
411+ partSizes := calculatePartSizes (stat .Size (), partSizeBytes )
412+ partNames , err := createParts (f , partSizes )
413+ if err != nil {
414+ cleanUpTempParts (partNames )
415+ return nil , err
416+ }
417+
418+ return partNames , nil
419+ }
420+
421+ func getPartSizeBytes () (int64 , error ) {
422+ // Get part size in GB from config if config is not provided, default to 2 GB
423+ partChunkSizeStr := viper .GetString (commonParams .MultipartFileSize )
424+ partChunkSizeFloat , err := strconv .ParseFloat (partChunkSizeStr , 64 )
425+ if err != nil {
426+ return 0 , fmt .Errorf ("invalid part size value: %w" , err )
427+ }
428+ // Truncate to integer
429+ truncatedSize := int64 (partChunkSizeFloat )
430+ if truncatedSize < 1 || truncatedSize > 5 {
431+ // Enforce part size to be between 1 GB and 5 GB.
432+ // If the configured part size is outside this range, default to 2 GB.
433+ logger .PrintIfVerbose (fmt .Sprintf ("Configured part size %d GB is outside the allowed range (1 – 5 GB). Defaulting to 2 GB." , truncatedSize ))
434+ truncatedSize = 2
435+ }
436+ const bytesPerGB = 1024 * 1024 * 1024
437+ return int64 (float64 (truncatedSize ) * float64 (bytesPerGB )), nil
438+ }
439+
440+ func calculatePartSizes (totalSize , partSizeBytes int64 ) []int64 {
431441 numParts := int (totalSize / partSizeBytes )
432442 if totalSize % partSizeBytes != 0 {
433443 numParts ++
434444 }
435-
436445 partSizes := make ([]int64 , numParts )
437446 for i := 0 ; i < numParts ; i ++ {
438447 remaining := totalSize - int64 (i )* partSizeBytes
@@ -442,21 +451,16 @@ func SplitZipBySizeGB(zipFilePath string) ([]string, error) {
442451 partSizes [i ] = remaining
443452 }
444453 }
454+ return partSizes
455+ }
445456
446- partNames := make ([]string , numParts )
447- for i := 0 ; i < numParts ; i ++ {
457+ func createParts (f * os.File , partSizes []int64 ) ([]string , error ) {
458+ partNames := make ([]string , len (partSizes ))
459+ for i , size := range partSizes {
448460 partFile , err := os .CreateTemp ("" , fmt .Sprintf ("cx-part%d-*" , i + 1 ))
449461 if err != nil {
450- for j := 0 ; j < i ; j ++ {
451- if partNames [j ] != "" {
452- if err := os .Remove (partNames [j ]); err != nil && ! os .IsNotExist (err ) {
453- logger .PrintfIfVerbose ("warning: failed to remove part%d - %v" , j + 1 , err )
454- }
455- }
456- }
457- return nil , fmt .Errorf ("create part%d - %w" , i + 1 , err )
462+ return partNames , fmt .Errorf ("create part%d - %w" , i + 1 , err )
458463 }
459-
460464 offset := int64 (0 )
461465 for j := 0 ; j < i ; j ++ {
462466 offset += partSizes [j ]
@@ -470,10 +474,9 @@ func SplitZipBySizeGB(zipFilePath string) ([]string, error) {
470474 if err != nil {
471475 return nil , err
472476 }
473- return nil , fmt .Errorf ("seek to part%d - %w" , i + 1 , err )
477+ return partNames , fmt .Errorf ("seek to part%d - %w" , i + 1 , err )
474478 }
475-
476- if _ , err := io .CopyN (partFile , f , partSizes [i ]); err != nil && err != io .EOF {
479+ if _ , err := io .CopyN (partFile , f , size ); err != nil && err != io .EOF {
477480 err := partFile .Close ()
478481 if err != nil {
479482 return nil , err
@@ -482,22 +485,25 @@ func SplitZipBySizeGB(zipFilePath string) ([]string, error) {
482485 if err != nil {
483486 return nil , err
484487 }
485- return nil , fmt .Errorf ("copy to part%d - %w" , i + 1 , err )
488+ return partNames , fmt .Errorf ("copy to part%d - %w" , i + 1 , err )
486489 }
487-
488490 if err := partFile .Sync (); err != nil {
489491 logger .PrintfIfVerbose ("warning: failed to sync part%d - %v" , i + 1 , err )
490492 }
491493 if err := partFile .Close (); err != nil {
492494 logger .PrintfIfVerbose ("warning: failed to close part%d - %v" , i + 1 , err )
493495 }
494-
495496 partNames [i ] = partFile .Name ()
496497 }
497-
498498 return partNames , nil
499499}
500500
501+ func closeFileVerbose (f * os.File ) {
502+ if err := f .Close (); err != nil {
503+ logger .PrintfIfVerbose ("warning: failed to close input file - %v" , err )
504+ }
505+ }
506+
501507// cleanUpTempParts removes the temporary part files created during multipart upload.
502508func cleanUpTempParts (partList []string ) {
503509 cleanupMaxRetries := 3
0 commit comments