package spm import ( "errors" "fmt" "io" "net/http" "os" "path/filepath" "runtime" ) type Package struct { Name string Arch string OS string DownloadURL string } func DownloadPackage(pkg Package, destDir string) error { UpdateProgress(0, fmt.Sprintf("Downloading %s", pkg.Name)) resp, err := http.Get(pkg.DownloadURL) if err != nil { return err } defer resp.Body.Close() filePath := filepath.Join(destDir, filepath.Base(pkg.DownloadURL)) out, err := os.Create(filePath) if err != nil { return err } defer out.Close() totalSize := resp.ContentLength var downloaded int64 // Track progress as bytes are downloaded buf := make([]byte, 1024) for { n, err := resp.Body.Read(buf) if n > 0 { downloaded += int64(n) percentage := int(float64(downloaded) / float64(totalSize) * 100) UpdateProgress(percentage, fmt.Sprintf("Downloading %s", pkg.Name)) if _, err := out.Write(buf[:n]); err != nil { return err } } if err == io.EOF { break } if err != nil { return err } } UpdateProgress(100, fmt.Sprintf("%s downloaded", pkg.Name)) return nil } func FindPackage(entries []AppIndexEntry, name, release, arch, os string) (*AppIndexEntry, error) { for _, entry := range entries { if entry.Name == name && entry.Release == release && entry.Arch == arch && entry.OS == os { return &entry, nil } } return nil, errors.New("package not found") } func DownloadPackageFromAppIndex(appIndexPath, packageName, release, destDir string) error { arch := runtime.GOARCH osName := runtime.GOOS entries, err := ParseAppIndex(appIndexPath) if err != nil { return err } entry, err := FindPackage(entries, packageName, release, arch, osName) if err != nil { return err } return DownloadPackage(Package{ Name: entry.Name, Arch: entry.Arch, OS: entry.OS, DownloadURL: entry.DownloadURL, }, destDir) }