116 lines
2.2 KiB
Go
116 lines
2.2 KiB
Go
|
package web
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"regexp"
|
||
|
"runtime"
|
||
|
|
||
|
"github.com/adrg/xdg"
|
||
|
"github.com/mholt/archiver/v3"
|
||
|
"go.jolheiser.com/eget/forge"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
amd64Re = regexp.MustCompile(`amd64|x86_64|64-bit`)
|
||
|
linuxRe = regexp.MustCompile(`linux`)
|
||
|
windowsRe = regexp.MustCompile(`windows`)
|
||
|
)
|
||
|
|
||
|
func Install(f forge.Forger) error {
|
||
|
var re *regexp.Regexp
|
||
|
switch runtime.GOOS {
|
||
|
case "linux":
|
||
|
re = linuxRe
|
||
|
case "windows":
|
||
|
re = windowsRe
|
||
|
default:
|
||
|
return fmt.Errorf("%q is not a supported OS", runtime.GOOS)
|
||
|
}
|
||
|
|
||
|
latest, err := f.Latest()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
var asset forge.Asset
|
||
|
for _, a := range latest.Assets {
|
||
|
if amd64Re.MatchString(a.DownloadURL) && re.MatchString(a.DownloadURL) {
|
||
|
asset = a
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if asset.Name == "" {
|
||
|
return errors.New("no release found for this OS")
|
||
|
}
|
||
|
|
||
|
tmp, err := os.MkdirTemp(os.TempDir(), "eget-*")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer os.RemoveAll(tmp)
|
||
|
|
||
|
resp, err := http.Get(asset.DownloadURL)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
|
||
|
tmpDest := filepath.Join(tmp, asset.Name)
|
||
|
fi, err := os.Create(tmpDest)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if _, err := io.Copy(fi, resp.Body); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if err := fi.Close(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if err := unpack(tmpDest, f.Name()); err != nil {
|
||
|
return fmt.Errorf("could not unpack download: %w", err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func detectRootDir(path string) bool {
|
||
|
infos, err := os.ReadDir(path)
|
||
|
if err != nil {
|
||
|
return false
|
||
|
}
|
||
|
return len(infos) != 1
|
||
|
}
|
||
|
|
||
|
func unpack(src, name string) error {
|
||
|
dest := filepath.Join(xdg.DataHome, name)
|
||
|
uaIface, err := archiver.ByExtension(src)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
u, ok := uaIface.(archiver.Unarchiver)
|
||
|
if !ok {
|
||
|
d, ok := uaIface.(archiver.Decompressor)
|
||
|
if !ok {
|
||
|
return fmt.Errorf("format specified by source filename is not an archive or compression format: %s (%T)", src, uaIface)
|
||
|
}
|
||
|
var binExt string
|
||
|
if runtime.GOOS == "windows" {
|
||
|
binExt = ".exe"
|
||
|
}
|
||
|
dest = filepath.Join(dest, name+binExt)
|
||
|
c := archiver.FileCompressor{Decompressor: d}
|
||
|
if err := c.DecompressFile(src, dest); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return os.Chmod(dest, 0o755)
|
||
|
}
|
||
|
return u.Unarchive(src, dest)
|
||
|
}
|