oopsie
This commit is contained in:
parent
b50133a06a
commit
a7cae14449
1 changed files with 128 additions and 128 deletions
256
spm/download.go
256
spm/download.go
|
@ -1,128 +1,128 @@
|
|||
package spm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DownloadPackageFromAppIndex selects and downloads the correct package from the APPINDEX.
|
||||
func DownloadPackageFromAppIndex(appIndexPath string, packageName string, release string, pkgType string, destDir string) error {
|
||||
// Parse the APPINDEX
|
||||
entries, err := ParseAppIndex(appIndexPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse APPINDEX: %w", err)
|
||||
}
|
||||
|
||||
// Find the right entry
|
||||
var selected *AppIndexEntry
|
||||
for _, e := range entries {
|
||||
if e.Name == packageName &&
|
||||
e.Release == release &&
|
||||
e.Type == pkgType &&
|
||||
e.OS == runtime.GOOS &&
|
||||
e.Arch == runtime.GOARCH {
|
||||
selected = &e
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Handle no matching entry
|
||||
if selected == nil {
|
||||
return fmt.Errorf("package not found in APPINDEX: %s (release: %s, type: %s, os: %s, arch: %s)", packageName, release, pkgType, runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
// Check if the package is already installed and up-to-date
|
||||
installDir, err := GetInstallDir()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get install directory: %w", err)
|
||||
}
|
||||
needsUpdate, err := IsUpdateNeeded(installDir, packageName, release, selected.Version, selected.Arch, selected.OS)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check update status: %w", err)
|
||||
}
|
||||
if !needsUpdate {
|
||||
UpdateProgress(0, "Already up-to-date, skipping download.")
|
||||
return nil // Skip download
|
||||
}
|
||||
|
||||
// Download the package
|
||||
UpdateProgress(0, fmt.Sprintf("Downloading %s %s (%s)...", packageName, selected.Version, selected.Type))
|
||||
resp, err := http.Get(selected.DownloadURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to download package: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Save the downloaded file
|
||||
downloadedFileName := filepath.Base(selected.DownloadURL)
|
||||
downloadedFilePath := filepath.Join(destDir, downloadedFileName)
|
||||
|
||||
out, err := os.OpenFile(downloadedFilePath, os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create output file: %w", err)
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
totalSize := resp.ContentLength
|
||||
var downloaded int64
|
||||
buf := make([]byte, 32*1024) // Use a larger buffer for efficiency
|
||||
|
||||
for {
|
||||
n, errRead := resp.Body.Read(buf)
|
||||
if n > 0 {
|
||||
downloaded += int64(n)
|
||||
percentage := int(float64(downloaded) / float64(totalSize) * 100)
|
||||
UpdateProgress(percentage, fmt.Sprintf("Downloading %s %s (%s)...", packageName, selected.Version, selected.Type))
|
||||
if _, errWrite := out.Write(buf[:n]); errWrite != nil {
|
||||
return fmt.Errorf("failed to write to output file: %w", errWrite)
|
||||
}
|
||||
}
|
||||
if errRead == io.EOF {
|
||||
break
|
||||
}
|
||||
if errRead != nil {
|
||||
return fmt.Errorf("error while reading response: %w", errRead)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the file handle is closed before renaming
|
||||
out.Close()
|
||||
|
||||
// Construct the expected filename
|
||||
expectedFileName := fmt.Sprintf("%s@%s@%s@%s@%s@%s.tar.gz",
|
||||
packageName, selected.Arch, selected.OS, selected.Type, selected.Release, selected.Version)
|
||||
|
||||
expectedFilePath := filepath.Join(destDir, expectedFileName)
|
||||
|
||||
// I dont know why is this happening, I dont want to know but sometimes some process is helding up the donwloaded files so thats why it retries here
|
||||
maxRetries := 5
|
||||
for i := 0; i < maxRetries; i++ {
|
||||
err = os.Rename(downloadedFilePath, expectedFilePath)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
// Check if file is in use
|
||||
f, checkErr := os.Open(downloadedFilePath)
|
||||
if checkErr != nil {
|
||||
return fmt.Errorf("file is locked by another process: %w", checkErr)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
if i < maxRetries-1 {
|
||||
time.Sleep(500 * time.Millisecond) // Wait before retrying
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to rename downloaded file after retries: %w", err)
|
||||
}
|
||||
|
||||
UpdateProgress(100, fmt.Sprintf("Downloaded %s %s (%s).", packageName, selected.Version, selected.Type))
|
||||
return nil
|
||||
}
|
||||
package spm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DownloadPackageFromAppIndex selects and downloads the correct package from the APPINDEX.
|
||||
func DownloadPackageFromAppIndex(appIndexPath string, packageName string, release string, pkgType string, destDir string) error {
|
||||
// Parse the APPINDEX
|
||||
entries, err := ParseAppIndex(appIndexPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse APPINDEX: %w", err)
|
||||
}
|
||||
|
||||
// Find the right entry
|
||||
var selected *AppIndexEntry
|
||||
for _, e := range entries {
|
||||
if e.Name == packageName &&
|
||||
e.Release == release &&
|
||||
e.Type == pkgType &&
|
||||
e.OS == runtime.GOOS &&
|
||||
e.Arch == runtime.GOARCH {
|
||||
selected = &e
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Handle no matching entry
|
||||
if selected == nil {
|
||||
return fmt.Errorf("package not found in APPINDEX: %s (release: %s, type: %s, os: %s, arch: %s)", packageName, release, pkgType, runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
// Check if the package is already installed and up-to-date
|
||||
installDir, err := GetInstallDir()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get install directory: %w", err)
|
||||
}
|
||||
needsUpdate, err := IsUpdateNeeded(installDir, packageName, release, selected.Version, selected.Arch, selected.OS)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check update status: %w", err)
|
||||
}
|
||||
if !needsUpdate {
|
||||
UpdateProgress(0, "Already up-to-date, skipping download.")
|
||||
return fmt.Errorf("Already up-to-date")
|
||||
}
|
||||
|
||||
// Download the package
|
||||
UpdateProgress(0, fmt.Sprintf("Downloading %s %s (%s)...", packageName, selected.Version, selected.Type))
|
||||
resp, err := http.Get(selected.DownloadURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to download package: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Save the downloaded file
|
||||
downloadedFileName := filepath.Base(selected.DownloadURL)
|
||||
downloadedFilePath := filepath.Join(destDir, downloadedFileName)
|
||||
|
||||
out, err := os.OpenFile(downloadedFilePath, os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create output file: %w", err)
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
totalSize := resp.ContentLength
|
||||
var downloaded int64
|
||||
buf := make([]byte, 32*1024) // Use a larger buffer for efficiency
|
||||
|
||||
for {
|
||||
n, errRead := resp.Body.Read(buf)
|
||||
if n > 0 {
|
||||
downloaded += int64(n)
|
||||
percentage := int(float64(downloaded) / float64(totalSize) * 100)
|
||||
UpdateProgress(percentage, fmt.Sprintf("Downloading %s %s (%s)...", packageName, selected.Version, selected.Type))
|
||||
if _, errWrite := out.Write(buf[:n]); errWrite != nil {
|
||||
return fmt.Errorf("failed to write to output file: %w", errWrite)
|
||||
}
|
||||
}
|
||||
if errRead == io.EOF {
|
||||
break
|
||||
}
|
||||
if errRead != nil {
|
||||
return fmt.Errorf("error while reading response: %w", errRead)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the file handle is closed before renaming
|
||||
out.Close()
|
||||
|
||||
// Construct the expected filename
|
||||
expectedFileName := fmt.Sprintf("%s@%s@%s@%s@%s@%s.tar.gz",
|
||||
packageName, selected.Arch, selected.OS, selected.Type, selected.Release, selected.Version)
|
||||
|
||||
expectedFilePath := filepath.Join(destDir, expectedFileName)
|
||||
|
||||
// I dont know why is this happening, I dont want to know but sometimes some process is helding up the donwloaded files so thats why it retries here
|
||||
maxRetries := 5
|
||||
for i := 0; i < maxRetries; i++ {
|
||||
err = os.Rename(downloadedFilePath, expectedFilePath)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
// Check if file is in use
|
||||
f, checkErr := os.Open(downloadedFilePath)
|
||||
if checkErr != nil {
|
||||
return fmt.Errorf("file is locked by another process: %w", checkErr)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
if i < maxRetries-1 {
|
||||
time.Sleep(500 * time.Millisecond) // Wait before retrying
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to rename downloaded file after retries: %w", err)
|
||||
}
|
||||
|
||||
UpdateProgress(100, fmt.Sprintf("Downloaded %s %s (%s).", packageName, selected.Version, selected.Type))
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue