package main import ( "context" "flag" "fmt" "io" "net/http" "os" "os/exec" "path/filepath" "runtime" "strings" "git.jojodev.com/golang/dl" "github.com/schollz/progressbar/v3" ) var f = false func main() { downloadFlag := flag.Bool("download", false, "Download latest Go") installFlag := &f if runtime.GOOS == "linux" { installFlag = flag.Bool("install", false, "Install/Update Go") } outFlag := flag.String("out", ".", "Where to put the downloaded file") flag.Parse() latest, err := latestVersion() if err != nil { fmt.Println(err) return } if !*downloadFlag && !*installFlag { ver, err := goVersion() if err != nil { fmt.Println(err) return } fmt.Printf("Current: %sLatest: %s\n", ver, latest.Version) return } outPath := filepath.Join(*outFlag, latest.Filename) if *downloadFlag { if err := download(latest.Filename, outPath); err != nil { fmt.Println(err) return } fmt.Println(outPath) } if *installFlag { if err := install(outPath); err != nil { fmt.Println(err) return } ver, err := goVersion() if err != nil { fmt.Println(err) return } fmt.Printf("Successfully installed: %s\n", ver) } } func goVersion() (string, error) { goVersion := exec.Command("/usr/local/go/bin/go", "version") out, err := goVersion.Output() if err != nil { return "", fmt.Errorf("could not check go version: %v", err) } return string(out), nil } func latestVersion() (*dl.File, error) { versions, err := dl.Versions(context.Background()) if err != nil { return nil, fmt.Errorf("could not get latest Go version(s): %v", err) } if len(versions) < 1 { return nil, fmt.Errorf("no latest Go version(s) found: %v", err) } var version dl.File for _, file := range versions[0].Files { if strings.EqualFold(file.OS, runtime.GOOS) && strings.EqualFold(file.Arch, runtime.GOARCH) { version = file break } } if version.Filename == "" { return nil, fmt.Errorf("could not find a download for OS = %s | Arch = %s", runtime.GOOS, runtime.GOARCH) } return &version, nil } func download(filename, outPath string) error { outFile, err := os.Create(outPath) if err != nil { return fmt.Errorf("could not create file for download: %v", err) } defer outFile.Close() req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://golang.org/dl/%s", filename), nil) if err != nil { return fmt.Errorf("could not create request: %v", err) } req.Header.Set("User-Agent", "git.jojodev.com/golang/dl/cmd/godl") res, err := http.DefaultClient.Do(req) if err != nil { return fmt.Errorf("could not download file: %v", err) } defer res.Body.Close() bar := progressbar.DefaultBytes( res.ContentLength, fmt.Sprintf("downloading %s", filename), ) if _, err := io.Copy(io.MultiWriter(outFile, bar), res.Body); err != nil { return err } return nil } func install(outPath string) error { if os.Geteuid() != 0 { return fmt.Errorf(`This command must be run as root to perform the install. Alternatively, you can run the following command manually, which is taken from https://golang.org/doc/install#install rm -rf /usr/local/go && tar -C /usr/local -xzf ` + outPath) } fmt.Println("removing local installation") rm := exec.Command("rm", "-rf", "/usr/local/go") if err := rm.Run(); err != nil { return fmt.Errorf("could not remove local go installation: %v", err) } fmt.Println("extracting new installation") tar := exec.Command("tar", "-C", "/usr/local", "-xzf", outPath) if err := tar.Run(); err != nil { return fmt.Errorf("could not extract new installation: %v", err) } rmDl := exec.Command("rm", outPath) if err := rmDl.Run(); err != nil { return fmt.Errorf("could not remove downloaded file: %v", err) } return nil }