autorestic/internal/bins/bins.go

172 lines
4.0 KiB
Go
Raw Normal View History

2021-04-11 11:04:11 +00:00
package bins
import (
"compress/bzip2"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path"
"runtime"
"strings"
"github.com/blang/semver/v4"
"github.com/cupcakearmy/autorestic/internal"
2021-04-12 14:15:17 +00:00
"github.com/cupcakearmy/autorestic/internal/colors"
"github.com/cupcakearmy/autorestic/internal/flags"
2021-04-11 11:04:11 +00:00
)
const INSTALL_PATH = "/usr/local/bin"
type GithubReleaseAsset struct {
Name string `json:"name"`
Link string `json:"browser_download_url"`
}
type GithubRelease struct {
Tag string `json:"tag_name"`
Assets []GithubReleaseAsset `json:"assets"`
}
func dlJSON(url string) (GithubRelease, error) {
var parsed GithubRelease
resp, err := http.Get(url)
if err != nil {
return parsed, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return parsed, err
}
json.Unmarshal(body, &parsed)
return parsed, nil
}
2021-04-12 08:55:57 +00:00
func Uninstall(restic bool) error {
if err := os.Remove(path.Join(INSTALL_PATH, "autorestic")); err != nil {
return err
2021-04-12 08:55:57 +00:00
}
if restic {
if err := os.Remove(path.Join(INSTALL_PATH, "restic")); err != nil {
return err
2021-04-12 08:55:57 +00:00
}
}
return nil
}
2021-04-17 15:13:03 +00:00
func downloadAndInstallAsset(body GithubRelease, name string) error {
ending := fmt.Sprintf("_%s_%s.bz2", runtime.GOOS, runtime.GOARCH)
for _, asset := range body.Assets {
if strings.HasSuffix(asset.Name, ending) {
// Download archive
colors.Faint.Println("Downloading:", asset.Link)
resp, err := http.Get(asset.Link)
if err != nil {
return err
}
defer resp.Body.Close()
// Uncompress
bz := bzip2.NewReader(resp.Body)
2021-04-20 21:26:57 +00:00
// Save to tmp
// Linux does not support overwriting the file that is currently being overwritten, but it can be deleted and a new one moved in its place.
tmp, err := ioutil.TempFile(os.TempDir(), "autorestic-")
2021-04-17 15:13:03 +00:00
if err != nil {
return err
}
2021-04-20 21:26:57 +00:00
defer tmp.Close()
if err := tmp.Chmod(0755); err != nil {
return err
}
if _, err := io.Copy(tmp, bz); err != nil {
return err
}
2021-04-20 21:26:57 +00:00
to := path.Join(INSTALL_PATH, name)
defer os.Remove(tmp.Name()) // Cleanup temporary file after thread exits
2021-04-20 21:26:57 +00:00
if err := os.Rename(tmp.Name(), to); err != nil {
colors.Error.Printf("os.Rename() failed (%v), retrying with io.Copy()\n", err.Error())
var src *os.File
var dst *os.File
if src, err = os.Open(tmp.Name()); err != nil {
return err
}
if dst, err = os.Create(to); err != nil {
return err
}
if _, err := io.Copy(dst, src); err != nil {
return err
}
if err := os.Chmod(to, 0755); err != nil {
return err
}
2021-04-20 21:26:57 +00:00
}
2021-04-17 15:13:03 +00:00
colors.Success.Printf("Successfully installed '%s' under %s\n", name, INSTALL_PATH)
return nil
}
}
return errors.New("could not find right binary for your system, please install restic manually. https://bit.ly/2Y1Rzai")
}
2021-04-11 11:04:11 +00:00
func InstallRestic() error {
installed := internal.CheckIfCommandIsCallable("restic")
if installed {
2021-04-12 14:15:17 +00:00
colors.Body.Println("restic already installed")
2021-04-11 11:04:11 +00:00
return nil
} else {
2021-04-17 15:13:03 +00:00
if body, err := dlJSON("https://api.github.com/repos/restic/restic/releases/latest"); err != nil {
2021-04-11 11:04:11 +00:00
return err
2021-04-17 15:13:03 +00:00
} else {
return downloadAndInstallAsset(body, "restic")
2021-04-11 11:04:11 +00:00
}
}
}
func upgradeRestic() error {
_, _, err := internal.ExecuteCommand(internal.ExecuteOptions{
Command: flags.RESTIC_BIN,
2021-04-11 11:04:11 +00:00
}, "self-update")
return err
}
func Upgrade(restic bool) error {
// Upgrade restic
if restic {
2021-04-26 11:15:58 +00:00
if err := InstallRestic(); err != nil {
return err
}
if err := upgradeRestic(); err != nil {
return err
2021-04-26 11:15:58 +00:00
}
2021-04-11 11:04:11 +00:00
}
// Upgrade self
current, err := semver.ParseTolerant(internal.VERSION)
if err != nil {
return err
}
body, err := dlJSON("https://api.github.com/repos/cupcakearmy/autorestic/releases/latest")
if err != nil {
return err
}
latest, err := semver.ParseTolerant(body.Tag)
if err != nil {
return err
}
2021-04-17 15:41:53 +00:00
if current.LT(latest) {
if err := downloadAndInstallAsset(body, "autorestic"); err != nil {
return err
}
2021-04-12 14:15:17 +00:00
colors.Success.Println("Updated autorestic")
2021-04-11 11:04:11 +00:00
} else {
2021-04-12 14:15:17 +00:00
colors.Body.Println("Already up to date")
2021-04-11 11:04:11 +00:00
}
return nil
}