From 2242bfb91bd19e17b44ea2202dbb6824062e88ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20G=C3=B6drei?= Date: Fri, 2 Aug 2024 11:39:14 +0200 Subject: [PATCH] Deploy the snapshot of generic files under 1GB file size (#207) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Deploy the snapshot of generic files under 1GB file size * Code cleanup * Log snapshot deployment * Update uploaders/fileuploader.go Co-authored-by: Olivér Falvai --------- Co-authored-by: Olivér Falvai --- main.go | 2 -- uploaders/fileuploader.go | 75 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index b09356a..b8e2aa1 100644 --- a/main.go +++ b/main.go @@ -544,8 +544,6 @@ func deploySingleItem(item deployment.DeployableItem, config Config, androidArti return uploaders.DeployXcarchive(item, config.BuildURL, config.APIToken) default: - logger.Printf("Deploying file: %s", pth) - return uploaders.DeployFile(item, config.BuildURL, config.APIToken) } } diff --git a/uploaders/fileuploader.go b/uploaders/fileuploader.go index a655e5b..5ef5e70 100644 --- a/uploaders/fileuploader.go +++ b/uploaders/fileuploader.go @@ -2,20 +2,54 @@ package uploaders import ( "fmt" + "io" + "os" + "path/filepath" + "github.com/bitrise-io/go-utils/log" + "github.com/bitrise-io/go-utils/pathutil" "github.com/bitrise-steplib/steps-deploy-to-bitrise-io/deployment" ) +const snapshotFileSizeLimitInBytes = 1024 * 1024 * 1024 + // DeployFile ... func DeployFile(item deployment.DeployableItem, buildURL, token string) (ArtifactURLs, error) { + pth := item.Path fileSize, err := fileSizeInBytes(item.Path) if err != nil { - return ArtifactURLs{}, fmt.Errorf("get file size: %s", err) + return ArtifactURLs{}, fmt.Errorf("get file size: %w", err) + } + + // TODO: This is a workaround to avoid uploading a file that is being modified during the upload process, + // which can cause an issue like: request body larger than specified content length at file upload. + deploySnapshot := false + if fileSize <= snapshotFileSizeLimitInBytes { + snapshotPth, err := createSnapshot(pth) + if err != nil { + log.Warnf("failed to create snapshot of %s: %s", pth, err) + } else { + defer func() { + if err := os.Remove(snapshotPth); err != nil { + log.Warnf("Failed to remove snapshot file: %s", err) + } + }() + pth = snapshotPth + deploySnapshot = true + } + } + + if deploySnapshot { + log.Printf("Deploying snapshot of original file: %s", pth) + } else { + log.Printf("Deploying file: %s", pth) } - artifact := ArtifactArgs { - Path: item.Path, + + artifact := ArtifactArgs{ + Path: pth, FileSize: fileSize, } + uploadURL, artifactID, err := createArtifact(buildURL, token, artifact, "file", "") if err != nil { 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 } return artifactURLs, nil } + +// createSnapshot copies a file to a temporary directory with the same file name. +func createSnapshot(originalPath string) (string, error) { + originalFile, err := os.Open(originalPath) + if err != nil { + return "", fmt.Errorf("failed to open original file: %w", err) + } + defer func() { + if err := originalFile.Close(); err != nil { + log.Warnf("Failed to close original file: %s", err) + } + }() + + tmpDir, err := pathutil.NormalizedOSTempDirPath("snapshot") + if err != nil { + return "", fmt.Errorf("failed to create temp directory: %w", err) + } + + tmpFilePath := filepath.Join(tmpDir, filepath.Base(originalPath)) + tmpFile, err := os.Create(tmpFilePath) + if err != nil { + return "", fmt.Errorf("failed to create temp file: %w", err) + } + defer func() { + if err := tmpFile.Close(); err != nil { + log.Warnf("Failed to close temp file: %s", err) + } + }() + + if _, err := io.Copy(tmpFile, originalFile); err != nil { + return "", fmt.Errorf("failed to copy contents: %w", err) + } + + return tmpFilePath, nil +}