services/internal/actions/download.go

121 lines
2.6 KiB
Go
Raw Permalink Normal View History

package actions
import (
"flow/services/internal/bundle"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"github.com/magefile/mage/sh"
)
// Download downloads all the files in the download pack,
// verifies all the GPG signatures (if enabled) and
// verifies the checksums (if enabled).
func Download(b bundle.Bundle) error {
if err := os.MkdirAll(b.DestinationDir, 0o750); err != nil {
return fmt.Errorf("unable to make '%s'; %w", b.DestinationDir, err)
}
var objects []bundle.Object
for i := range b.Packages {
objects = append(objects, b.Packages[i].File)
if b.ValidateGPGSignature {
objects = append(objects, b.Packages[i].GPGSignature)
}
}
if b.Checksum.Validate {
objects = append(objects, b.Checksum.File)
}
for _, object := range objects {
if err := func() error {
_, err := os.Stat(object.Destination)
if err == nil {
fmt.Printf("%s is already downloaded.\n", object.Destination)
return nil
}
file, err := os.Create(object.Destination)
if err != nil {
return fmt.Errorf("unable to create %s; %w", object.Destination, err)
}
defer file.Close()
client := http.Client{
CheckRedirect: func(r *http.Request, _ []*http.Request) error {
r.URL.Opaque = r.URL.Path
return nil
},
}
resp, err := client.Get(object.Source)
if err != nil {
return err
}
defer resp.Body.Close()
size, err := io.Copy(file, resp.Body)
if err != nil {
return err
}
fmt.Printf("Downloaded %s with size %d.\n", object.Destination, size)
return nil
}(); err != nil {
return err
}
}
if b.ValidateGPGSignature {
for i := range b.Packages {
if err := sh.RunV("gpg", "--verify", b.Packages[i].GPGSignature.Destination, b.Packages[i].File.Destination); err != nil {
return fmt.Errorf("GPG verification failed for '%s'; %w", b.Packages[i].File.Destination, err)
}
}
}
if b.Checksum.Validate {
var err error
if b.Checksum.ValidateFunc != nil {
err = b.Checksum.ValidateFunc()
} else {
err = validateChecksum(b.DestinationDir, b.Checksum.File.Destination)
}
if err != nil {
return fmt.Errorf("checksum validation failed; %w", err)
}
}
return nil
}
func validateChecksum(destinationDir, checksumPath string) error {
startDir, err := os.Getwd()
if err != nil {
return err
}
if err := os.Chdir(destinationDir); err != nil {
return err
}
checksum := filepath.Base(checksumPath)
if err := sh.RunV("sha256sum", "--check", "--ignore-missing", checksum); err != nil {
return err
}
if err := os.Chdir(startDir); err != nil {
return err
}
return nil
}