Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PERF-1311 Async download command #178

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ Optionally, you may rename included `config-example.yml` to `config.yml` and set
Only one concurrent request per token is allowed.

## Changes
**3.1.0 (Feb 24, 2025)**
- Added support for async file download.

**3.0.0 (Jun 04, 2024)**
- Upgraded lokalise-go-api to v4, which includes breaking changes
- Added support for cursor based pagination for Keys and Translations endpoints
Expand Down
56 changes: 56 additions & 0 deletions cmd/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
downloadDestination string
downloadUnzipTo string
downloadKeepZip bool
downloadAsync bool

uploadOpts lokalise.FileUpload
uploadOptsConvertPlaceholders bool
Expand Down Expand Up @@ -193,6 +194,11 @@
Short: "Download files",
Long: "Exports project files as a .zip bundle. Generated bundle will be uploaded to an Amazon S3 bucket, which will be stored there for 12 months available to download. As the bundle is generated and uploaded you would get a response with the URL to the file. Requires Download files admin right.",
RunE: func(cmd *cobra.Command, args []string) error {
// Async export processed separately.
if downloadAsync {
return asyncDownload()
}

// preparing options
if downloadOptsLangMapping != "" {
var mappings []lokalise.LanguageMapping
Expand Down Expand Up @@ -242,6 +248,55 @@
},
}

func asyncDownload() error {
initResp, err := Api.Files().InitAsyncDownload(projectId, downloadOpts)

Check failure on line 252 in cmd/file.go

View workflow job for this annotation

GitHub Actions / goreleaser

Api.Files().InitAsyncDownload undefined (type *lokalise.FileService has no field or method InitAsyncDownload)
if err != nil {
return err
}

fmt.Printf("Process started with ID: %s\n", initResp.ProcessID)

var statusResp lokalise.QueuedProcessResponse

for {
time.Sleep(pollingFrequency)
fmt.Println("Checking download status...")

statusResp, err = Api.QueuedProcesses().Retrieve(projectId, initResp.ProcessID)
if err != nil {
return err
}

if statusResp.Process.Status == "finished" {
fmt.Println("Download ready!")
break
} else if statusResp.Process.Status == "failed" {
return fmt.Errorf("Download process failed!")
}

if statusResp.Process.Details.ItemsToProcess != nil && *statusResp.Process.Details.ItemsToProcess > 0 {

Check failure on line 277 in cmd/file.go

View workflow job for this annotation

GitHub Actions / goreleaser

statusResp.Process.Details.ItemsToProcess undefined (type interface{} has no field or method ItemsToProcess)
if statusResp.Process.Details.ItemsProcessed != nil {

Check failure on line 278 in cmd/file.go

View workflow job for this annotation

GitHub Actions / goreleaser

statusResp.Process.Details.ItemsProcessed undefined (type interface{} has no field or method ItemsProcessed)
progress := (float64(*statusResp.Process.Details.ItemsProcessed) / float64(*statusResp.Process.Details.ItemsToProcess)) * 100

Check failure on line 279 in cmd/file.go

View workflow job for this annotation

GitHub Actions / goreleaser

statusResp.Process.Details.ItemsProcessed undefined (type interface{} has no field or method ItemsProcessed)

Check failure on line 279 in cmd/file.go

View workflow job for this annotation

GitHub Actions / goreleaser

statusResp.Process.Details.ItemsToProcess undefined (type interface{} has no field or method ItemsToProcess)
fmt.Printf("Progress: %.2f%%\n", progress)
}
}
}

fileURL := statusResp.Process.Details.DownloadUrl

Check failure on line 285 in cmd/file.go

View workflow job for this annotation

GitHub Actions / goreleaser

statusResp.Process.Details.DownloadUrl undefined (type interface{} has no field or method DownloadUrl)
if fileURL == "" {
return fmt.Errorf("Getting download URL failed.")
}
fmt.Printf("Downloading file: %s\n", fileURL)

err = downloadAndUnzip(fileURL, downloadDestination, downloadUnzipTo)
if err != nil {
return err
}

return nil
}


func init() {
fileCmd.AddCommand(fileListCmd, fileUploadCmd, fileDownloadCmd)
rootCmd.AddCommand(fileCmd)
Expand All @@ -257,6 +312,7 @@
fs.StringVar(&downloadOpts.Format, "format", "", "File format (e.g. json, strings, xml). Must be file extension of any of the file formats we support. May also be ios_sdk or android_sdk for respective OTA SDK bundles. (required)")
_ = fileDownloadCmd.MarkFlagRequired("format")

fs.BoolVar(&downloadAsync, "async", false, "Enable asynchronous file download (download link active for 24 hours, ignoring json-only flag when active).")
fs.BoolVar(&downloadJsonOnly, "json-only", false, "Should only the API JSON response be returned.")
fs.BoolVar(&downloadKeepZip, "keep-zip", false, "Keep or delete ZIP file after being unpacked.")
fs.StringVar(&downloadDestination, "dest", "./", "Destination folder for ZIP file.")
Expand Down
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
)

const (
Version = "3.0.1"
Version = "3.1.0"
DefaultPageLimit = 5000
)

Expand Down
1 change: 1 addition & 0 deletions docs/lokalise2_file_download.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ lokalise2 file download [flags]
```
--add-newline-eof Enable to add new line at end of file (if supported by format).
--all-platforms Enable to include all platform keys. If disabled, only the keys, associated with the platform of the format will be exported.
--async Use async mode for file download. Download link will be active for 24 hours, and json-only param will be ignored if used.
--bundle-description string Description of the created bundle. Applies to ios_sdk or android_sdk OTA SDK bundles.
--bundle-structure string Bundle structure, used when original-filenames set to false. Allowed placeholders are %LANG_ISO%, %LANG_NAME%, %FORMAT% and %PROJECT_NAME%).
--custom-translation-status-ids strings Only translations attributed to selected custom statuses will be included. Leave empty for all.
Expand Down
Loading