|
|
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !plan9
package main
import ( "archive/tar" "archive/zip" "compress/gzip" "crypto/sha256" "fmt" "io" "io/ioutil" "net/http" "os" "path/filepath" "strings" )
const ( currentVersionURL = "https://golang.org/VERSION?m=text" downloadURLPrefix = "https://storage.googleapis.com/golang" )
// downloadGoVersion downloads and upacks the specific go version to dest/go.
func downloadGoVersion(version, ops, arch, dest string) error { suffix := "tar.gz" if ops == "windows" { suffix = "zip" } uri := fmt.Sprintf("%s/%s.%s-%s.%s", downloadURLPrefix, version, ops, arch, suffix)
verbosef("Downloading %s", uri)
req, err := http.NewRequest("GET", uri, nil) if err != nil { return err } req.Header.Add("User-Agent", fmt.Sprintf("golang.org-getgo/%s", version))
resp, err := http.DefaultClient.Do(req) if err != nil { return fmt.Errorf("Downloading Go from %s failed: %v", uri, err) } if resp.StatusCode > 299 { return fmt.Errorf("Downloading Go from %s failed with HTTP status %s", uri, resp.Status) } defer resp.Body.Close()
tmpf, err := ioutil.TempFile("", "go") if err != nil { return err } defer os.Remove(tmpf.Name())
h := sha256.New()
w := io.MultiWriter(tmpf, h) if _, err := io.Copy(w, resp.Body); err != nil { return err }
verbosef("Downloading SHA %s.sha256", uri)
sresp, err := http.Get(uri + ".sha256") if err != nil { return fmt.Errorf("Downloading Go sha256 from %s.sha256 failed: %v", uri, err) } defer sresp.Body.Close() if sresp.StatusCode > 299 { return fmt.Errorf("Downloading Go sha256 from %s.sha256 failed with HTTP status %s", uri, sresp.Status) }
shasum, err := ioutil.ReadAll(sresp.Body) if err != nil { return err }
// Check the shasum.
sum := fmt.Sprintf("%x", h.Sum(nil)) if sum != string(shasum) { return fmt.Errorf("Shasum mismatch %s vs. %s", sum, string(shasum)) }
unpackFunc := unpackTar if ops == "windows" { unpackFunc = unpackZip } if err := unpackFunc(tmpf.Name(), dest); err != nil { return fmt.Errorf("Unpacking Go to %s failed: %v", dest, err) } return nil }
func unpack(dest, name string, fi os.FileInfo, r io.Reader) error { if strings.HasPrefix(name, "go/") { name = name[len("go/"):] }
path := filepath.Join(dest, name) if fi.IsDir() { return os.MkdirAll(path, fi.Mode()) }
f, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, fi.Mode()) if err != nil { return err } defer f.Close()
_, err = io.Copy(f, r) return err }
func unpackTar(src, dest string) error { r, err := os.Open(src) if err != nil { return err } defer r.Close()
archive, err := gzip.NewReader(r) if err != nil { return err } defer archive.Close()
tarReader := tar.NewReader(archive)
for { header, err := tarReader.Next() if err == io.EOF { break } else if err != nil { return err }
if err := unpack(dest, header.Name, header.FileInfo(), tarReader); err != nil { return err } }
return nil }
func unpackZip(src, dest string) error { zr, err := zip.OpenReader(src) if err != nil { return err }
for _, f := range zr.File { fr, err := f.Open() if err != nil { return err } if err := unpack(dest, f.Name, f.FileInfo(), fr); err != nil { return err } fr.Close() }
return nil }
func getLatestGoVersion() (string, error) { resp, err := http.Get(currentVersionURL) if err != nil { return "", fmt.Errorf("Getting current Go version failed: %v", err) } defer resp.Body.Close() if resp.StatusCode > 299 { b, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 1024)) return "", fmt.Errorf("Could not get current Go version: HTTP %d: %q", resp.StatusCode, b) } version, err := ioutil.ReadAll(resp.Body) if err != nil { return "", err } return strings.TrimSpace(string(version)), nil }
|