in internal/platform/utils/utils.go [131:222]
func DownloadFile(filepath string, url string, auth string, spinner *pterm.SpinnerPrinter) error {
headReq, err := http.NewRequest("HEAD", url, nil)
if err != nil {
return fmt.Errorf("error creating HEAD request: %w", err)
}
if auth != "" {
headReq.Header.Add("Authorization", fmt.Sprintf("Bearer %s", auth))
}
response, err := http.DefaultClient.Do(headReq)
if err != nil {
return fmt.Errorf("error making HEAD request: %w", err)
}
if response.StatusCode != http.StatusOK {
return fmt.Errorf("response from %s (HEAD): %s", url, response.Status)
}
sizeStr := response.Header.Get("Content-Length")
if sizeStr == "" {
sizeStr = "-1"
}
size, err := strconv.Atoi(sizeStr)
if err != nil {
return fmt.Errorf("error converting Content-Length to integer: %w", err)
}
getReq, err := http.NewRequest("GET", url, nil)
if err != nil {
return fmt.Errorf("error creating GET request: %w", err)
}
if auth != "" {
getReq.Header.Add("Authorization", fmt.Sprintf("Bearer %s", auth))
}
resp, err := http.DefaultClient.Do(getReq)
if err != nil {
return fmt.Errorf("error making GET request: %w", err)
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("response from %s (GET): %s", url, resp.Status)
}
defer func(Body io.ReadCloser) {
if err := Body.Close(); err != nil {
fmt.Printf("Error while closing HTTP stream: %v\n", err)
}
}(resp.Body)
out, err := os.Create(filepath)
if err != nil {
return fmt.Errorf("error creating file: %w", err)
}
defer func(out *os.File) {
if err := out.Close(); err != nil {
fmt.Printf("Error while closing output file: %v\n", err)
}
}(out)
buffer := make([]byte, 1024)
total := 0
lastTotal := 0
text := ""
if spinner != nil {
text = spinner.Text
}
for {
length, err := resp.Body.Read(buffer)
if err != nil && err != io.EOF {
return fmt.Errorf("error reading response body: %w", err)
}
total += length
if spinner != nil && total-lastTotal > 1024*1024 {
lastTotal = total
spinner.UpdateText(fmt.Sprintf("%s (%d %%)", text, 100*total/size))
}
if length == 0 {
break
}
if _, err = out.Write(buffer[:length]); err != nil {
return fmt.Errorf("error writing to file: %w", err)
}
}
// Check if the size matches, but only if the Content-Length header was present and valid
if size > 0 && total != size {
return fmt.Errorf("downloaded file size doesn't match expected size, got %d, expected %d", total, size)
}
if spinner != nil {
spinner.UpdateText(fmt.Sprintf("%s (100 %%)", text))
}
return nil
}