@@ -2,20 +2,54 @@ package uploaders
22
33import (
44 "fmt"
5+ "io"
6+ "os"
7+ "path/filepath"
58
9+ "github.com/bitrise-io/go-utils/log"
10+ "github.com/bitrise-io/go-utils/pathutil"
611 "github.com/bitrise-steplib/steps-deploy-to-bitrise-io/deployment"
712)
813
14+ const snapshotFileSizeLimitInBytes = 1024 * 1024 * 1024
15+
916// DeployFile ...
1017func DeployFile (item deployment.DeployableItem , buildURL , token string ) (ArtifactURLs , error ) {
18+ pth := item .Path
1119 fileSize , err := fileSizeInBytes (item .Path )
1220 if err != nil {
13- return ArtifactURLs {}, fmt .Errorf ("get file size: %s" , err )
21+ return ArtifactURLs {}, fmt .Errorf ("get file size: %w" , err )
22+ }
23+
24+ // TODO: This is a workaround to avoid uploading a file that is being modified during the upload process,
25+ // which can cause an issue like: request body larger than specified content length at file upload.
26+ deploySnapshot := false
27+ if fileSize <= snapshotFileSizeLimitInBytes {
28+ snapshotPth , err := createSnapshot (pth )
29+ if err != nil {
30+ log .Warnf ("failed to create snapshot of %s: %s" , pth , err )
31+ } else {
32+ defer func () {
33+ if err := os .Remove (snapshotPth ); err != nil {
34+ log .Warnf ("Failed to remove snapshot file: %s" , err )
35+ }
36+ }()
37+ pth = snapshotPth
38+ deploySnapshot = true
39+ }
40+ }
41+
42+ if deploySnapshot {
43+ log .Printf ("Deploying snapshot of original file: %s" , pth )
44+ } else {
45+ log .Printf ("Deploying file: %s" , pth )
1446 }
15- artifact := ArtifactArgs {
16- Path : item .Path ,
47+
48+ artifact := ArtifactArgs {
49+ Path : pth ,
1750 FileSize : fileSize ,
1851 }
52+
1953 uploadURL , artifactID , err := createArtifact (buildURL , token , artifact , "file" , "" )
2054 if err != nil {
2155 return ArtifactURLs {}, fmt .Errorf ("create file artifact: %s %w" , artifact .Path , err )
@@ -31,3 +65,38 @@ func DeployFile(item deployment.DeployableItem, buildURL, token string) (Artifac
3165 }
3266 return artifactURLs , nil
3367}
68+
69+ // createSnapshot copies a file to a temporary directory with the same file name.
70+ func createSnapshot (originalPath string ) (string , error ) {
71+ originalFile , err := os .Open (originalPath )
72+ if err != nil {
73+ return "" , fmt .Errorf ("failed to open original file: %w" , err )
74+ }
75+ defer func () {
76+ if err := originalFile .Close (); err != nil {
77+ log .Warnf ("Failed to close original file: %s" , err )
78+ }
79+ }()
80+
81+ tmpDir , err := pathutil .NormalizedOSTempDirPath ("snapshot" )
82+ if err != nil {
83+ return "" , fmt .Errorf ("failed to create temp directory: %w" , err )
84+ }
85+
86+ tmpFilePath := filepath .Join (tmpDir , filepath .Base (originalPath ))
87+ tmpFile , err := os .Create (tmpFilePath )
88+ if err != nil {
89+ return "" , fmt .Errorf ("failed to create temp file: %w" , err )
90+ }
91+ defer func () {
92+ if err := tmpFile .Close (); err != nil {
93+ log .Warnf ("Failed to close temp file: %s" , err )
94+ }
95+ }()
96+
97+ if _ , err := io .Copy (tmpFile , originalFile ); err != nil {
98+ return "" , fmt .Errorf ("failed to copy contents: %w" , err )
99+ }
100+
101+ return tmpFilePath , nil
102+ }
0 commit comments