1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
package main
import (
"flag"
"fmt"
"github.com/rhysd/go-github-selfupdate/selfupdate"
"go/build"
"io"
"net/http"
"os"
"path/filepath"
"strings"
)
var version = "1.0.0"
func usage() {
fmt.Fprintln(os.Stderr, `Usage: go-get-release [flags] {package}
go-get-release is like "go get", but it downloads the latest release from
GitHub. {package} must start with "github.com/".
Flags:`)
flag.PrintDefaults()
}
func getCommand(pkg string) string {
_, cmd := filepath.Split(pkg)
if cmd == "" {
// When pkg path is ending with path separator, we need to split it out.
// i.e. github.com/rhysd/foo/cmd/bar/
_, cmd = filepath.Split(cmd)
}
return cmd
}
func parseSlug(pkg string) (string, bool) {
pkg = pkg[len("github.com/"):]
first := false
for i, r := range pkg {
if r == '/' {
if !first {
first = true
} else {
return pkg[:i], true
}
}
}
if first {
// When 'github.com/foo/bar' is specified, reaching here.
return pkg, true
}
return "", false
}
func installFrom(url, cmd, path string) error {
res, err := http.Get(url)
if err != nil {
return fmt.Errorf("Failed to download release binary from %s: %s", url, err)
}
defer res.Body.Close()
if res.StatusCode != 200 {
return fmt.Errorf("Failed to download release binary from %s: Invalid response ", url)
}
executable, err := selfupdate.UncompressCommand(res.Body, url, cmd)
if err != nil {
return fmt.Errorf("Failed to uncompress downloaded asset from %s: %s", url, err)
}
bin, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0755)
if err != nil {
return err
}
if _, err := io.Copy(bin, executable); err != nil {
return fmt.Errorf("Failed to write binary to %s: %s", path, err)
}
return nil
}
func main() {
help := flag.Bool("help", false, "Show help")
ver := flag.Bool("version", false, "Show version")
flag.Usage = usage
flag.Parse()
if *ver {
fmt.Println(version)
os.Exit(0)
}
if *help || flag.NArg() != 1 || !strings.HasPrefix(flag.Arg(0), "github.com/") {
usage()
os.Exit(1)
}
slug, ok := parseSlug(flag.Arg(0))
if !ok {
usage()
os.Exit(1)
}
latest, found, err := selfupdate.DetectLatest(slug)
if err != nil {
fmt.Fprintln(os.Stderr, "Error while detecting the latest version:", err)
os.Exit(1)
}
if !found {
fmt.Fprintln(os.Stderr, "No release was found in", slug)
os.Exit(1)
}
cmd := getCommand(flag.Arg(0))
cmdPath := filepath.Join(build.Default.GOPATH, "bin", cmd)
if _, err := os.Stat(cmdPath); err != nil {
// When executable is not existing yet
if err := installFrom(latest.AssetURL, cmd, cmdPath); err != nil {
fmt.Fprintf(os.Stderr, "Error while installing the release binary from %s: %s\n", latest.AssetURL, err)
os.Exit(1)
}
} else {
if err := selfupdate.UpdateTo(latest.AssetURL, cmdPath); err != nil {
fmt.Fprintf(os.Stderr, "Error while replacing the binary with %s: %s\n", latest.AssetURL, err)
os.Exit(1)
}
}
fmt.Printf(`Command was updated to the latest version %s: %s
Release Notes:
%s
`, latest.Version, cmdPath, latest.ReleaseNotes)
}
|