refactor(mage): refactor download code
- Refactor the code for the Download target to reduce repeated code and (hopefully) improve readability. - The code now checks to see if each of the downloaded files already exists. - The verification will always run if enabled regardless of whether the files are already downloaded or not.
This commit is contained in:
parent
b961753dd2
commit
428a59faaa
3 changed files with 239 additions and 222 deletions
11
magefiles/const.go
Normal file
11
magefiles/const.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
//go:build mage
|
||||
|
||||
package main
|
||||
|
||||
const (
|
||||
configFile string = "./config/services.json"
|
||||
rootBuildDir string = "./build"
|
||||
templateExtension string = ".gotmpl"
|
||||
rootTemplatesDir string = "./templates"
|
||||
rootAssetsDir string = "./assets"
|
||||
)
|
|
@ -13,14 +13,6 @@ import (
|
|||
"github.com/magefile/mage/sh"
|
||||
)
|
||||
|
||||
const (
|
||||
configFile string = "./config/services.json"
|
||||
rootBuildDir string = "./build"
|
||||
templateExtension string = ".gotmpl"
|
||||
rootTemplatesDir string = "./templates"
|
||||
rootAssetsDir string = "./assets"
|
||||
)
|
||||
|
||||
// Download downloads the binaries for a given service.
|
||||
func Download(name string) error {
|
||||
cfg, err := newConfig(configFile)
|
||||
|
@ -44,9 +36,228 @@ func Download(name string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Download Forgejo
|
||||
// downloadForgejo downloads and validates the Forgejo files.
|
||||
func downloadForgejo(version string) error {
|
||||
var (
|
||||
forgejoBinaryFileFormat = "forgejo-%s-linux-amd64"
|
||||
forgejoDigestExtension = ".sha256"
|
||||
forgejoSignatureExtension = ".asc"
|
||||
forgejoJson = "./magefiles/forgejo.json"
|
||||
)
|
||||
|
||||
type forgejoDownload struct {
|
||||
destinationDir := filepath.Join(rootBuildDir, "forgejo")
|
||||
|
||||
binaryPath := filepath.Join(
|
||||
destinationDir,
|
||||
fmt.Sprintf(forgejoBinaryFileFormat, version),
|
||||
)
|
||||
|
||||
signaturePath := binaryPath + forgejoSignatureExtension
|
||||
|
||||
checksumPath := binaryPath + forgejoDigestExtension
|
||||
|
||||
data, err := newForgejoInfo(forgejoJson)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pack := downloadPack{
|
||||
destinationDir: destinationDir,
|
||||
packages: []pack{
|
||||
{
|
||||
file: object{
|
||||
source: data.Downloads[version].Binary,
|
||||
destination: binaryPath,
|
||||
},
|
||||
gpgSignature: object{
|
||||
source: data.Downloads[version].Signature,
|
||||
destination: signaturePath,
|
||||
},
|
||||
},
|
||||
},
|
||||
validateGPGSignature: true,
|
||||
checksum: object{
|
||||
source: data.Downloads[version].Digest,
|
||||
destination: checksumPath,
|
||||
},
|
||||
validateChecksum: true,
|
||||
}
|
||||
|
||||
if err := download(pack); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// downloadGoToSocial downloads and validates the files for GoToSocial.
|
||||
func downloadGoToSocial(version string) error {
|
||||
destinationDir := filepath.Join(rootBuildDir, "gotosocial")
|
||||
|
||||
binaryTarUrl := fmt.Sprintf(
|
||||
"https://github.com/superseriousbusiness/gotosocial/releases/download/v%s/gotosocial_%s_linux_amd64.tar.gz",
|
||||
version,
|
||||
version,
|
||||
)
|
||||
binaryTarFilepath := filepath.Join(destinationDir, fmt.Sprintf("gotosocial_%s_linux_amd64.tar.gz", version))
|
||||
|
||||
webAssetsTarUrl := fmt.Sprintf(
|
||||
"https://github.com/superseriousbusiness/gotosocial/releases/download/v%s/gotosocial_%s_web-assets.tar.gz",
|
||||
version,
|
||||
version,
|
||||
)
|
||||
webAssetsFilepath := filepath.Join(destinationDir, fmt.Sprintf("gotosocial_%s_web-assets.tar.gz", version))
|
||||
|
||||
checksumUrl := fmt.Sprintf(
|
||||
"https://github.com/superseriousbusiness/gotosocial/releases/download/v%s/checksums.txt",
|
||||
version,
|
||||
)
|
||||
checksumFilePath := filepath.Join(destinationDir, fmt.Sprintf("gotosocial_%s_checksums.txt", version))
|
||||
|
||||
pack := downloadPack{
|
||||
destinationDir: destinationDir,
|
||||
packages: []pack{
|
||||
{
|
||||
file: object{
|
||||
source: binaryTarUrl,
|
||||
destination: binaryTarFilepath,
|
||||
},
|
||||
},
|
||||
{
|
||||
file: object{
|
||||
source: webAssetsTarUrl,
|
||||
destination: webAssetsFilepath,
|
||||
},
|
||||
},
|
||||
},
|
||||
validateGPGSignature: false,
|
||||
checksum: object{
|
||||
source: checksumUrl,
|
||||
destination: checksumFilePath,
|
||||
},
|
||||
validateChecksum: true,
|
||||
}
|
||||
|
||||
if err := download(pack); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type downloadPack struct {
|
||||
destinationDir string
|
||||
packages []pack
|
||||
checksum object
|
||||
validateGPGSignature bool
|
||||
validateChecksum bool
|
||||
}
|
||||
|
||||
type pack struct {
|
||||
file object
|
||||
gpgSignature object
|
||||
}
|
||||
|
||||
type object struct {
|
||||
source string
|
||||
destination string
|
||||
}
|
||||
|
||||
// download downloads all the files in the download pack,
|
||||
// verifies all the GPG signatures (if enabled) and
|
||||
// verifies the checksums (if enabled).
|
||||
func download(pack downloadPack) error {
|
||||
if err := os.MkdirAll(pack.destinationDir, 0o750); err != nil {
|
||||
return fmt.Errorf("unable to make '%s'; %w", pack.destinationDir, err)
|
||||
}
|
||||
|
||||
var objects []object
|
||||
|
||||
for i := range pack.packages {
|
||||
objects = append(objects, pack.packages[i].file)
|
||||
if pack.validateGPGSignature {
|
||||
objects = append(objects, pack.packages[i].gpgSignature)
|
||||
}
|
||||
}
|
||||
|
||||
if pack.validateChecksum {
|
||||
objects = append(objects, pack.checksum)
|
||||
}
|
||||
|
||||
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 pack.validateGPGSignature {
|
||||
for i := range pack.packages {
|
||||
if err := sh.Run("gpg", "--verify", pack.packages[i].gpgSignature.destination, pack.packages[i].file.destination); err != nil {
|
||||
return fmt.Errorf("GPG verification failed for '%s'; %w", pack.packages[i].file.destination, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if pack.validateChecksum {
|
||||
startDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Chdir(pack.destinationDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
checksum := filepath.Base(pack.checksum.destination)
|
||||
|
||||
if err := sh.Run("sha256sum", "--check", "--ignore-missing", checksum); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Chdir(startDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type forgejoInfo struct {
|
||||
Downloads map[string]forgejoFiles `json:"downloads"`
|
||||
}
|
||||
|
||||
|
@ -56,225 +267,20 @@ type forgejoFiles struct {
|
|||
Digest string `json:"digest"`
|
||||
}
|
||||
|
||||
const (
|
||||
forgejoBinaryFileFormat string = "forgejo-%s-linux-amd64"
|
||||
forgejoDigestExtension string = ".sha256"
|
||||
forgejoSignatureExtension string = ".asc"
|
||||
forgejoDownloadJson string = "./magefiles/forgejo/download.json"
|
||||
)
|
||||
func newForgejoInfo(path string) (forgejoInfo, error) {
|
||||
var info forgejoInfo
|
||||
|
||||
func downloadForgejo(version string) error {
|
||||
downloadFolder := filepath.Join(rootBuildDir, "forgejo")
|
||||
|
||||
if err := os.MkdirAll(downloadFolder, 0o750); err != nil {
|
||||
return fmt.Errorf("unable to make %s; %w", downloadFolder, err)
|
||||
}
|
||||
|
||||
binaryPath := filepath.Join(
|
||||
downloadFolder,
|
||||
fmt.Sprintf(forgejoBinaryFileFormat, version),
|
||||
)
|
||||
signaturePath := binaryPath + forgejoSignatureExtension
|
||||
digestPath := binaryPath + forgejoDigestExtension
|
||||
|
||||
_, err := os.Stat(binaryPath)
|
||||
if err == nil {
|
||||
fmt.Printf("Forgejo %s is already downloaded.\n", version)
|
||||
return nil
|
||||
}
|
||||
|
||||
data, err := newForgejoDownloadData()
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
downloads := []struct {
|
||||
url string
|
||||
path string
|
||||
}{
|
||||
{
|
||||
url: data.Downloads[version].Binary,
|
||||
path: binaryPath,
|
||||
},
|
||||
{
|
||||
url: data.Downloads[version].Signature,
|
||||
path: signaturePath,
|
||||
},
|
||||
{
|
||||
url: data.Downloads[version].Digest,
|
||||
path: digestPath,
|
||||
},
|
||||
}
|
||||
|
||||
for _, v := range downloads {
|
||||
if err := func() error {
|
||||
download, err := os.Create(v.path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create %s; %w", v.path, err)
|
||||
}
|
||||
defer download.Close()
|
||||
|
||||
client := http.Client{
|
||||
CheckRedirect: func(r *http.Request, _ []*http.Request) error {
|
||||
r.URL.Opaque = r.URL.Path
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := client.Get(v.url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
size, err := io.Copy(download, resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Downloaded %s with size %d.\n", v.path, size)
|
||||
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = sh.Run("gpg", "--verify", signaturePath, binaryPath); err != nil {
|
||||
return fmt.Errorf("GPG verification failed; %w", err)
|
||||
}
|
||||
|
||||
if err := os.Chdir(downloadFolder); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sh.Run("sha256sum", "--check", fmt.Sprintf(forgejoBinaryFileFormat+forgejoDigestExtension, version)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Chdir("../.."); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newForgejoDownloadData() (forgejoDownload, error) {
|
||||
var data forgejoDownload
|
||||
|
||||
f, err := os.Open(forgejoDownloadJson)
|
||||
if err != nil {
|
||||
return data, err
|
||||
return info, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
decoder := json.NewDecoder(f)
|
||||
|
||||
if err = decoder.Decode(&data); err != nil {
|
||||
return data, err
|
||||
if err = decoder.Decode(&info); err != nil {
|
||||
return info, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Download GTS
|
||||
|
||||
func downloadGoToSocial(version string) error {
|
||||
downloadFolder := filepath.Join(rootBuildDir, "gotosocial")
|
||||
|
||||
if err := os.MkdirAll(downloadFolder, 0o750); err != nil {
|
||||
return fmt.Errorf("unable to make %s; %w", downloadFolder, err)
|
||||
}
|
||||
|
||||
binaryTarUrl := fmt.Sprintf(
|
||||
"https://github.com/superseriousbusiness/gotosocial/releases/download/v%s/gotosocial_%s_linux_amd64.tar.gz",
|
||||
version,
|
||||
version,
|
||||
)
|
||||
binaryTarFilepath := filepath.Join(downloadFolder, fmt.Sprintf("gotosocial_%s_linux_amd64.tar.gz", version))
|
||||
|
||||
webAssetsTarUrl := fmt.Sprintf(
|
||||
"https://github.com/superseriousbusiness/gotosocial/releases/download/v%s/gotosocial_%s_web-assets.tar.gz",
|
||||
version,
|
||||
version,
|
||||
)
|
||||
webAssetsFilepath := filepath.Join(downloadFolder, fmt.Sprintf("gotosocial_%s_web-assets.tar.gz", version))
|
||||
|
||||
checksumUrl := fmt.Sprintf(
|
||||
"https://github.com/superseriousbusiness/gotosocial/releases/download/v%s/checksums.txt",
|
||||
version,
|
||||
)
|
||||
checksumFilePath := filepath.Join(downloadFolder, fmt.Sprintf("gotosocial_%s_checksums.txt", version))
|
||||
|
||||
_, err := os.Stat(binaryTarFilepath)
|
||||
if err == nil {
|
||||
fmt.Printf("GoToSocial %s is already downloaded.\n", version)
|
||||
return nil
|
||||
}
|
||||
|
||||
downloads := []struct {
|
||||
url string
|
||||
path string
|
||||
}{
|
||||
{
|
||||
url: binaryTarUrl,
|
||||
path: binaryTarFilepath,
|
||||
},
|
||||
{
|
||||
url: webAssetsTarUrl,
|
||||
path: webAssetsFilepath,
|
||||
},
|
||||
{
|
||||
url: checksumUrl,
|
||||
path: checksumFilePath,
|
||||
},
|
||||
}
|
||||
|
||||
for _, v := range downloads {
|
||||
if err := func() error {
|
||||
download, err := os.Create(v.path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create %s; %w", v.path, err)
|
||||
}
|
||||
defer download.Close()
|
||||
|
||||
client := http.Client{
|
||||
CheckRedirect: func(r *http.Request, _ []*http.Request) error {
|
||||
r.URL.Opaque = r.URL.Path
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := client.Get(v.url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
size, err := io.Copy(download, resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Downloaded %s with size %d.\n", v.path, size)
|
||||
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.Chdir(downloadFolder); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sh.Run("sha256sum", "--check", "--ignore-missing", fmt.Sprintf("gotosocial_%s_checksums.txt", version)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Chdir("../.."); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return info, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue