You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
3.9 KiB

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