This repository has been archived on 2023-11-08. You can view files and clone it, but cannot push or open issues/pull-requests.
eget/disk/disk.go

130 lines
2.8 KiB
Go

package disk
import (
"fmt"
"io"
"io/fs"
"net/http"
"os"
"path/filepath"
"runtime"
"strings"
"go.jolheiser.com/eget/forge"
"github.com/mholt/archiver/v3"
"github.com/schollz/progressbar/v3"
)
func Install(name string, asset forge.Asset) error {
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
}
bar := progressbar.DefaultBytes(resp.ContentLength, "downloading")
if _, err := io.Copy(io.MultiWriter(fi, bar), resp.Body); err != nil {
return err
}
if err := fi.Close(); err != nil {
return err
}
if err := unpack(tmpDest, name); err != nil {
return fmt.Errorf("could not unpack download: %w", err)
}
return nil
}
func unpack(src, name string) error {
dest := Path(name)
if err := os.MkdirAll(dest, os.ModePerm); err != nil {
return fmt.Errorf("could not make all dest dirs: %w", err)
}
var binExt string
if runtime.GOOS == "windows" {
binExt = ".exe"
}
uaIface, err := archiver.ByExtension(src)
if err != nil {
ext := filepath.Ext(src)
if ext == binExt || len(ext) > 3 {
dest = filepath.Join(dest, name+binExt)
if err := os.Rename(src, dest); err != nil {
return err
}
return os.Chmod(dest, 0o755)
}
return err
}
u, ok := uaIface.(archiver.Unarchiver)
if !ok {
dest = filepath.Join(dest, name+binExt)
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)
}
c := archiver.FileCompressor{Decompressor: d}
if err := c.DecompressFile(src, dest); err != nil {
return err
}
return os.Chmod(dest, 0o755)
}
tmpDest := filepath.Join(filepath.Dir(src), name)
if err := u.Unarchive(src, tmpDest); err != nil {
return fmt.Errorf("could not unarchive source: %w", err)
}
tmpSrc := tmpDest
infos, err := os.ReadDir(tmpSrc)
if err != nil {
return fmt.Errorf("could not read unarchived dir: %w", err)
}
if len(infos) == 1 && infos[0].IsDir() {
tmpSrc = filepath.Join(tmpDest, infos[0].Name())
}
return moveDir(tmpSrc, dest)
}
func moveDir(src, dest string) error {
return filepath.WalkDir(src, func(walkPath string, walkEntry fs.DirEntry, walkErr error) error {
if walkErr != nil {
return walkErr
}
if walkEntry.IsDir() {
return nil
}
rel := strings.TrimPrefix(walkPath, src)
destPath := filepath.Join(dest, rel)
if err := os.MkdirAll(filepath.Dir(destPath), os.ModePerm); err != nil {
return err
}
return os.Rename(walkPath, destPath)
})
}
func Path(name string) string {
home, err := os.UserHomeDir()
if err != nil {
home = "."
}
return filepath.Join(home, ".eget", name)
}