github.com/april1989/origin-go-tools@v0.0.32/cmd/getgo/download.go (about)

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build !plan9
     6  
     7  package main
     8  
     9  import (
    10  	"archive/tar"
    11  	"archive/zip"
    12  	"compress/gzip"
    13  	"crypto/sha256"
    14  	"fmt"
    15  	"io"
    16  	"io/ioutil"
    17  	"net/http"
    18  	"os"
    19  	"path/filepath"
    20  	"strings"
    21  )
    22  
    23  const (
    24  	currentVersionURL = "https://golang.org/VERSION?m=text"
    25  	downloadURLPrefix = "https://dl.google.com/go"
    26  )
    27  
    28  // downloadGoVersion downloads and upacks the specific go version to dest/go.
    29  func downloadGoVersion(version, ops, arch, dest string) error {
    30  	suffix := "tar.gz"
    31  	if ops == "windows" {
    32  		suffix = "zip"
    33  	}
    34  	uri := fmt.Sprintf("%s/%s.%s-%s.%s", downloadURLPrefix, version, ops, arch, suffix)
    35  
    36  	verbosef("Downloading %s", uri)
    37  
    38  	req, err := http.NewRequest("GET", uri, nil)
    39  	if err != nil {
    40  		return err
    41  	}
    42  	req.Header.Add("User-Agent", fmt.Sprintf("golang.org-getgo/%s", version))
    43  
    44  	resp, err := http.DefaultClient.Do(req)
    45  	if err != nil {
    46  		return fmt.Errorf("Downloading Go from %s failed: %v", uri, err)
    47  	}
    48  	if resp.StatusCode > 299 {
    49  		return fmt.Errorf("Downloading Go from %s failed with HTTP status %s", uri, resp.Status)
    50  	}
    51  	defer resp.Body.Close()
    52  
    53  	tmpf, err := ioutil.TempFile("", "go")
    54  	if err != nil {
    55  		return err
    56  	}
    57  	defer os.Remove(tmpf.Name())
    58  
    59  	h := sha256.New()
    60  
    61  	w := io.MultiWriter(tmpf, h)
    62  	if _, err := io.Copy(w, resp.Body); err != nil {
    63  		return err
    64  	}
    65  
    66  	verbosef("Downloading SHA %s.sha256", uri)
    67  
    68  	sresp, err := http.Get(uri + ".sha256")
    69  	if err != nil {
    70  		return fmt.Errorf("Downloading Go sha256 from %s.sha256 failed: %v", uri, err)
    71  	}
    72  	defer sresp.Body.Close()
    73  	if sresp.StatusCode > 299 {
    74  		return fmt.Errorf("Downloading Go sha256 from %s.sha256 failed with HTTP status %s", uri, sresp.Status)
    75  	}
    76  
    77  	shasum, err := ioutil.ReadAll(sresp.Body)
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	// Check the shasum.
    83  	sum := fmt.Sprintf("%x", h.Sum(nil))
    84  	if sum != string(shasum) {
    85  		return fmt.Errorf("Shasum mismatch %s vs. %s", sum, string(shasum))
    86  	}
    87  
    88  	unpackFunc := unpackTar
    89  	if ops == "windows" {
    90  		unpackFunc = unpackZip
    91  	}
    92  	if err := unpackFunc(tmpf.Name(), dest); err != nil {
    93  		return fmt.Errorf("Unpacking Go to %s failed: %v", dest, err)
    94  	}
    95  	return nil
    96  }
    97  
    98  func unpack(dest, name string, fi os.FileInfo, r io.Reader) error {
    99  	if strings.HasPrefix(name, "go/") {
   100  		name = name[len("go/"):]
   101  	}
   102  
   103  	path := filepath.Join(dest, name)
   104  	if fi.IsDir() {
   105  		return os.MkdirAll(path, fi.Mode())
   106  	}
   107  
   108  	f, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, fi.Mode())
   109  	if err != nil {
   110  		return err
   111  	}
   112  	defer f.Close()
   113  
   114  	_, err = io.Copy(f, r)
   115  	return err
   116  }
   117  
   118  func unpackTar(src, dest string) error {
   119  	r, err := os.Open(src)
   120  	if err != nil {
   121  		return err
   122  	}
   123  	defer r.Close()
   124  
   125  	archive, err := gzip.NewReader(r)
   126  	if err != nil {
   127  		return err
   128  	}
   129  	defer archive.Close()
   130  
   131  	tarReader := tar.NewReader(archive)
   132  
   133  	for {
   134  		header, err := tarReader.Next()
   135  		if err == io.EOF {
   136  			break
   137  		} else if err != nil {
   138  			return err
   139  		}
   140  
   141  		if err := unpack(dest, header.Name, header.FileInfo(), tarReader); err != nil {
   142  			return err
   143  		}
   144  	}
   145  
   146  	return nil
   147  }
   148  
   149  func unpackZip(src, dest string) error {
   150  	zr, err := zip.OpenReader(src)
   151  	if err != nil {
   152  		return err
   153  	}
   154  
   155  	for _, f := range zr.File {
   156  		fr, err := f.Open()
   157  		if err != nil {
   158  			return err
   159  		}
   160  		if err := unpack(dest, f.Name, f.FileInfo(), fr); err != nil {
   161  			return err
   162  		}
   163  		fr.Close()
   164  	}
   165  
   166  	return nil
   167  }
   168  
   169  func getLatestGoVersion() (string, error) {
   170  	resp, err := http.Get(currentVersionURL)
   171  	if err != nil {
   172  		return "", fmt.Errorf("Getting current Go version failed: %v", err)
   173  	}
   174  	defer resp.Body.Close()
   175  	if resp.StatusCode > 299 {
   176  		b, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 1024))
   177  		return "", fmt.Errorf("Could not get current Go version: HTTP %d: %q", resp.StatusCode, b)
   178  	}
   179  	version, err := ioutil.ReadAll(resp.Body)
   180  	if err != nil {
   181  		return "", err
   182  	}
   183  	return strings.TrimSpace(string(version)), nil
   184  }