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 }