Add generated file
This PR adds generated files under pkg/client and vendor folder.
This commit is contained in:
559
vendor/golang.org/x/tools/godoc/dl/dl.go
generated
vendored
Normal file
559
vendor/golang.org/x/tools/godoc/dl/dl.go
generated
vendored
Normal file
@@ -0,0 +1,559 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
// Package dl implements a simple downloads frontend server.
|
||||
//
|
||||
// It accepts HTTP POST requests to create a new download metadata entity, and
|
||||
// lists entities with sorting and filtering.
|
||||
// It is designed to run only on the instance of godoc that serves golang.org.
|
||||
package dl
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/appengine"
|
||||
"google.golang.org/appengine/datastore"
|
||||
"google.golang.org/appengine/log"
|
||||
"google.golang.org/appengine/memcache"
|
||||
)
|
||||
|
||||
const (
|
||||
downloadBaseURL = "https://dl.google.com/go/"
|
||||
cacheKey = "download_list_3" // increment if listTemplateData changes
|
||||
cacheDuration = time.Hour
|
||||
)
|
||||
|
||||
func RegisterHandlers(mux *http.ServeMux) {
|
||||
mux.Handle("/dl", http.RedirectHandler("/dl/", http.StatusFound))
|
||||
mux.HandleFunc("/dl/", getHandler) // also serves listHandler
|
||||
mux.HandleFunc("/dl/upload", uploadHandler)
|
||||
mux.HandleFunc("/dl/init", initHandler)
|
||||
}
|
||||
|
||||
// File represents a file on the golang.org downloads page.
|
||||
// It should be kept in sync with the upload code in x/build/cmd/release.
|
||||
type File struct {
|
||||
Filename string `json:"filename"`
|
||||
OS string `json:"os"`
|
||||
Arch string `json:"arch"`
|
||||
Version string `json:"version"`
|
||||
Checksum string `json:"-" datastore:",noindex"` // SHA1; deprecated
|
||||
ChecksumSHA256 string `json:"sha256" datastore:",noindex"`
|
||||
Size int64 `json:"size" datastore:",noindex"`
|
||||
Kind string `json:"kind"` // "archive", "installer", "source"
|
||||
Uploaded time.Time `json:"-"`
|
||||
}
|
||||
|
||||
func (f File) ChecksumType() string {
|
||||
if f.ChecksumSHA256 != "" {
|
||||
return "SHA256"
|
||||
}
|
||||
return "SHA1"
|
||||
}
|
||||
|
||||
func (f File) PrettyChecksum() string {
|
||||
if f.ChecksumSHA256 != "" {
|
||||
return f.ChecksumSHA256
|
||||
}
|
||||
return f.Checksum
|
||||
}
|
||||
|
||||
func (f File) PrettyOS() string {
|
||||
if f.OS == "darwin" {
|
||||
switch {
|
||||
case strings.Contains(f.Filename, "osx10.8"):
|
||||
return "OS X 10.8+"
|
||||
case strings.Contains(f.Filename, "osx10.6"):
|
||||
return "OS X 10.6+"
|
||||
}
|
||||
}
|
||||
return pretty(f.OS)
|
||||
}
|
||||
|
||||
func (f File) PrettySize() string {
|
||||
const mb = 1 << 20
|
||||
if f.Size == 0 {
|
||||
return ""
|
||||
}
|
||||
if f.Size < mb {
|
||||
// All Go releases are >1mb, but handle this case anyway.
|
||||
return fmt.Sprintf("%v bytes", f.Size)
|
||||
}
|
||||
return fmt.Sprintf("%.0fMB", float64(f.Size)/mb)
|
||||
}
|
||||
|
||||
var primaryPorts = map[string]bool{
|
||||
"darwin/amd64": true,
|
||||
"linux/386": true,
|
||||
"linux/amd64": true,
|
||||
"linux/armv6l": true,
|
||||
"windows/386": true,
|
||||
"windows/amd64": true,
|
||||
}
|
||||
|
||||
func (f File) PrimaryPort() bool {
|
||||
if f.Kind == "source" {
|
||||
return true
|
||||
}
|
||||
return primaryPorts[f.OS+"/"+f.Arch]
|
||||
}
|
||||
|
||||
func (f File) Highlight() bool {
|
||||
switch {
|
||||
case f.Kind == "source":
|
||||
return true
|
||||
case f.Arch == "amd64" && f.OS == "linux":
|
||||
return true
|
||||
case f.Arch == "amd64" && f.Kind == "installer":
|
||||
switch f.OS {
|
||||
case "windows":
|
||||
return true
|
||||
case "darwin":
|
||||
if !strings.Contains(f.Filename, "osx10.6") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f File) URL() string {
|
||||
return downloadBaseURL + f.Filename
|
||||
}
|
||||
|
||||
type Release struct {
|
||||
Version string `json:"version"`
|
||||
Stable bool `json:"stable"`
|
||||
Files []File `json:"files"`
|
||||
Visible bool `json:"-"` // show files on page load
|
||||
SplitPortTable bool `json:"-"` // whether files should be split by primary/other ports.
|
||||
}
|
||||
|
||||
type Feature struct {
|
||||
// The File field will be filled in by the first stable File
|
||||
// whose name matches the given fileRE.
|
||||
File
|
||||
fileRE *regexp.Regexp
|
||||
|
||||
Platform string // "Microsoft Windows", "Apple macOS", "Linux"
|
||||
Requirements string // "Windows XP and above, 64-bit Intel Processor"
|
||||
}
|
||||
|
||||
// featuredFiles lists the platforms and files to be featured
|
||||
// at the top of the downloads page.
|
||||
var featuredFiles = []Feature{
|
||||
{
|
||||
Platform: "Microsoft Windows",
|
||||
Requirements: "Windows XP SP3 or later, Intel 64-bit processor",
|
||||
fileRE: regexp.MustCompile(`\.windows-amd64\.msi$`),
|
||||
},
|
||||
{
|
||||
Platform: "Apple macOS",
|
||||
Requirements: "macOS 10.8 or later, Intel 64-bit processor",
|
||||
fileRE: regexp.MustCompile(`\.darwin-amd64(-osx10\.8)?\.pkg$`),
|
||||
},
|
||||
{
|
||||
Platform: "Linux",
|
||||
Requirements: "Linux 2.6.23 or later, Intel 64-bit processor",
|
||||
fileRE: regexp.MustCompile(`\.linux-amd64\.tar\.gz$`),
|
||||
},
|
||||
{
|
||||
Platform: "Source",
|
||||
fileRE: regexp.MustCompile(`\.src\.tar\.gz$`),
|
||||
},
|
||||
}
|
||||
|
||||
// data to send to the template; increment cacheKey if you change this.
|
||||
type listTemplateData struct {
|
||||
Featured []Feature
|
||||
Stable, Unstable, Archive []Release
|
||||
}
|
||||
|
||||
var (
|
||||
listTemplate = template.Must(template.New("").Funcs(templateFuncs).Parse(templateHTML))
|
||||
templateFuncs = template.FuncMap{"pretty": pretty}
|
||||
)
|
||||
|
||||
func listHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
var (
|
||||
c = appengine.NewContext(r)
|
||||
d listTemplateData
|
||||
)
|
||||
if _, err := memcache.Gob.Get(c, cacheKey, &d); err != nil {
|
||||
if err == memcache.ErrCacheMiss {
|
||||
log.Debugf(c, "cache miss")
|
||||
} else {
|
||||
log.Errorf(c, "cache get error: %v", err)
|
||||
}
|
||||
|
||||
var fs []File
|
||||
_, err := datastore.NewQuery("File").Ancestor(rootKey(c)).GetAll(c, &fs)
|
||||
if err != nil {
|
||||
log.Errorf(c, "error listing: %v", err)
|
||||
return
|
||||
}
|
||||
d.Stable, d.Unstable, d.Archive = filesToReleases(fs)
|
||||
if len(d.Stable) > 0 {
|
||||
d.Featured = filesToFeatured(d.Stable[0].Files)
|
||||
}
|
||||
|
||||
item := &memcache.Item{Key: cacheKey, Object: &d, Expiration: cacheDuration}
|
||||
if err := memcache.Gob.Set(c, item); err != nil {
|
||||
log.Errorf(c, "cache set error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if r.URL.Query().Get("mode") == "json" {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetIndent("", " ")
|
||||
if err := enc.Encode(d.Stable); err != nil {
|
||||
log.Errorf(c, "failed rendering JSON for releases: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := listTemplate.ExecuteTemplate(w, "root", d); err != nil {
|
||||
log.Errorf(c, "error executing template: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func filesToFeatured(fs []File) (featured []Feature) {
|
||||
for _, feature := range featuredFiles {
|
||||
for _, file := range fs {
|
||||
if feature.fileRE.MatchString(file.Filename) {
|
||||
feature.File = file
|
||||
featured = append(featured, feature)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func filesToReleases(fs []File) (stable, unstable, archive []Release) {
|
||||
sort.Sort(fileOrder(fs))
|
||||
|
||||
var r *Release
|
||||
var stableMaj, stableMin int
|
||||
add := func() {
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
if !r.Stable {
|
||||
if len(unstable) != 0 {
|
||||
// Only show one (latest) unstable version.
|
||||
return
|
||||
}
|
||||
maj, min, _ := parseVersion(r.Version)
|
||||
if maj < stableMaj || maj == stableMaj && min <= stableMin {
|
||||
// Display unstable version only if newer than the
|
||||
// latest stable release.
|
||||
return
|
||||
}
|
||||
unstable = append(unstable, *r)
|
||||
}
|
||||
|
||||
// Reports whether the release is the most recent minor version of the
|
||||
// two most recent major versions.
|
||||
shouldAddStable := func() bool {
|
||||
if len(stable) >= 2 {
|
||||
// Show up to two stable versions.
|
||||
return false
|
||||
}
|
||||
if len(stable) == 0 {
|
||||
// Most recent stable version.
|
||||
stableMaj, stableMin, _ = parseVersion(r.Version)
|
||||
return true
|
||||
}
|
||||
if maj, _, _ := parseVersion(r.Version); maj == stableMaj {
|
||||
// Older minor version of most recent major version.
|
||||
return false
|
||||
}
|
||||
// Second most recent stable version.
|
||||
return true
|
||||
}
|
||||
if !shouldAddStable() {
|
||||
archive = append(archive, *r)
|
||||
return
|
||||
}
|
||||
|
||||
// Split the file list into primary/other ports for the stable releases.
|
||||
// NOTE(cbro): This is only done for stable releases because maintaining the historical
|
||||
// nature of primary/other ports for older versions is infeasible.
|
||||
// If freebsd is considered primary some time in the future, we'd not want to
|
||||
// mark all of the older freebsd binaries as "primary".
|
||||
// It might be better if we set that as a flag when uploading.
|
||||
r.SplitPortTable = true
|
||||
r.Visible = true // Toggle open all stable releases.
|
||||
stable = append(stable, *r)
|
||||
}
|
||||
for _, f := range fs {
|
||||
if r == nil || f.Version != r.Version {
|
||||
add()
|
||||
r = &Release{
|
||||
Version: f.Version,
|
||||
Stable: isStable(f.Version),
|
||||
}
|
||||
}
|
||||
r.Files = append(r.Files, f)
|
||||
}
|
||||
add()
|
||||
return
|
||||
}
|
||||
|
||||
// isStable reports whether the version string v is a stable version.
|
||||
func isStable(v string) bool {
|
||||
return !strings.Contains(v, "beta") && !strings.Contains(v, "rc")
|
||||
}
|
||||
|
||||
type fileOrder []File
|
||||
|
||||
func (s fileOrder) Len() int { return len(s) }
|
||||
func (s fileOrder) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s fileOrder) Less(i, j int) bool {
|
||||
a, b := s[i], s[j]
|
||||
if av, bv := a.Version, b.Version; av != bv {
|
||||
return versionLess(av, bv)
|
||||
}
|
||||
if a.OS != b.OS {
|
||||
return a.OS < b.OS
|
||||
}
|
||||
if a.Arch != b.Arch {
|
||||
return a.Arch < b.Arch
|
||||
}
|
||||
if a.Kind != b.Kind {
|
||||
return a.Kind < b.Kind
|
||||
}
|
||||
return a.Filename < b.Filename
|
||||
}
|
||||
|
||||
func versionLess(a, b string) bool {
|
||||
// Put stable releases first.
|
||||
if isStable(a) != isStable(b) {
|
||||
return isStable(a)
|
||||
}
|
||||
maja, mina, ta := parseVersion(a)
|
||||
majb, minb, tb := parseVersion(b)
|
||||
if maja == majb {
|
||||
if mina == minb {
|
||||
return ta >= tb
|
||||
}
|
||||
return mina >= minb
|
||||
}
|
||||
return maja >= majb
|
||||
}
|
||||
|
||||
func parseVersion(v string) (maj, min int, tail string) {
|
||||
if i := strings.Index(v, "beta"); i > 0 {
|
||||
tail = v[i:]
|
||||
v = v[:i]
|
||||
}
|
||||
if i := strings.Index(v, "rc"); i > 0 {
|
||||
tail = v[i:]
|
||||
v = v[:i]
|
||||
}
|
||||
p := strings.Split(strings.TrimPrefix(v, "go1."), ".")
|
||||
maj, _ = strconv.Atoi(p[0])
|
||||
if len(p) < 2 {
|
||||
return
|
||||
}
|
||||
min, _ = strconv.Atoi(p[1])
|
||||
return
|
||||
}
|
||||
|
||||
func uploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
c := appengine.NewContext(r)
|
||||
|
||||
// Authenticate using a user token (same as gomote).
|
||||
user := r.FormValue("user")
|
||||
if !validUser(user) {
|
||||
http.Error(w, "bad user", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
if r.FormValue("key") != userKey(c, user) {
|
||||
http.Error(w, "bad key", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
var f File
|
||||
defer r.Body.Close()
|
||||
if err := json.NewDecoder(r.Body).Decode(&f); err != nil {
|
||||
log.Errorf(c, "error decoding upload JSON: %v", err)
|
||||
http.Error(w, "Something broke", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if f.Filename == "" {
|
||||
http.Error(w, "Must provide Filename", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if f.Uploaded.IsZero() {
|
||||
f.Uploaded = time.Now()
|
||||
}
|
||||
k := datastore.NewKey(c, "File", f.Filename, 0, rootKey(c))
|
||||
if _, err := datastore.Put(c, k, &f); err != nil {
|
||||
log.Errorf(c, "putting File entity: %v", err)
|
||||
http.Error(w, "could not put File entity", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err := memcache.Delete(c, cacheKey); err != nil {
|
||||
log.Errorf(c, "cache delete error: %v", err)
|
||||
}
|
||||
io.WriteString(w, "OK")
|
||||
}
|
||||
|
||||
func getHandler(w http.ResponseWriter, r *http.Request) {
|
||||
name := strings.TrimPrefix(r.URL.Path, "/dl/")
|
||||
if name == "" {
|
||||
listHandler(w, r)
|
||||
return
|
||||
}
|
||||
if !fileRe.MatchString(name) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, downloadBaseURL+name, http.StatusFound)
|
||||
}
|
||||
|
||||
func validUser(user string) bool {
|
||||
switch user {
|
||||
case "adg", "bradfitz", "cbro", "andybons", "valsorda":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func userKey(c context.Context, user string) string {
|
||||
h := hmac.New(md5.New, []byte(secret(c)))
|
||||
h.Write([]byte("user-" + user))
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
||||
|
||||
var fileRe = regexp.MustCompile(`^go[0-9a-z.]+\.[0-9a-z.-]+\.(tar\.gz|pkg|msi|zip)$`)
|
||||
|
||||
func initHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var fileRoot struct {
|
||||
Root string
|
||||
}
|
||||
c := appengine.NewContext(r)
|
||||
k := rootKey(c)
|
||||
err := datastore.RunInTransaction(c, func(c context.Context) error {
|
||||
err := datastore.Get(c, k, &fileRoot)
|
||||
if err != nil && err != datastore.ErrNoSuchEntity {
|
||||
return err
|
||||
}
|
||||
_, err = datastore.Put(c, k, &fileRoot)
|
||||
return err
|
||||
}, nil)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
io.WriteString(w, "OK")
|
||||
}
|
||||
|
||||
// rootKey is the ancestor of all File entities.
|
||||
func rootKey(c context.Context) *datastore.Key {
|
||||
return datastore.NewKey(c, "FileRoot", "root", 0, nil)
|
||||
}
|
||||
|
||||
// pretty returns a human-readable version of the given OS, Arch, or Kind.
|
||||
func pretty(s string) string {
|
||||
t, ok := prettyStrings[s]
|
||||
if !ok {
|
||||
return s
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
var prettyStrings = map[string]string{
|
||||
"darwin": "macOS",
|
||||
"freebsd": "FreeBSD",
|
||||
"linux": "Linux",
|
||||
"windows": "Windows",
|
||||
|
||||
"386": "x86",
|
||||
"amd64": "x86-64",
|
||||
"armv6l": "ARMv6",
|
||||
"arm64": "ARMv8",
|
||||
|
||||
"archive": "Archive",
|
||||
"installer": "Installer",
|
||||
"source": "Source",
|
||||
}
|
||||
|
||||
// Code below copied from x/build/app/key
|
||||
|
||||
var theKey struct {
|
||||
sync.RWMutex
|
||||
builderKey
|
||||
}
|
||||
|
||||
type builderKey struct {
|
||||
Secret string
|
||||
}
|
||||
|
||||
func (k *builderKey) Key(c context.Context) *datastore.Key {
|
||||
return datastore.NewKey(c, "BuilderKey", "root", 0, nil)
|
||||
}
|
||||
|
||||
func secret(c context.Context) string {
|
||||
// check with rlock
|
||||
theKey.RLock()
|
||||
k := theKey.Secret
|
||||
theKey.RUnlock()
|
||||
if k != "" {
|
||||
return k
|
||||
}
|
||||
|
||||
// prepare to fill; check with lock and keep lock
|
||||
theKey.Lock()
|
||||
defer theKey.Unlock()
|
||||
if theKey.Secret != "" {
|
||||
return theKey.Secret
|
||||
}
|
||||
|
||||
// fill
|
||||
if err := datastore.Get(c, theKey.Key(c), &theKey.builderKey); err != nil {
|
||||
if err == datastore.ErrNoSuchEntity {
|
||||
// If the key is not stored in datastore, write it.
|
||||
// This only happens at the beginning of a new deployment.
|
||||
// The code is left here for SDK use and in case a fresh
|
||||
// deployment is ever needed. "gophers rule" is not the
|
||||
// real key.
|
||||
if !appengine.IsDevAppServer() {
|
||||
panic("lost key from datastore")
|
||||
}
|
||||
theKey.Secret = "gophers rule"
|
||||
datastore.Put(c, theKey.Key(c), &theKey.builderKey)
|
||||
return theKey.Secret
|
||||
}
|
||||
panic("cannot load builder key: " + err.Error())
|
||||
}
|
||||
|
||||
return theKey.Secret
|
||||
}
|
137
vendor/golang.org/x/tools/godoc/dl/dl_test.go
generated
vendored
Normal file
137
vendor/golang.org/x/tools/godoc/dl/dl_test.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
package dl
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseVersion(t *testing.T) {
|
||||
for _, c := range []struct {
|
||||
in string
|
||||
maj, min int
|
||||
tail string
|
||||
}{
|
||||
{"go1.5", 5, 0, ""},
|
||||
{"go1.5beta1", 5, 0, "beta1"},
|
||||
{"go1.5.1", 5, 1, ""},
|
||||
{"go1.5.1rc1", 5, 1, "rc1"},
|
||||
} {
|
||||
maj, min, tail := parseVersion(c.in)
|
||||
if maj != c.maj || min != c.min || tail != c.tail {
|
||||
t.Errorf("parseVersion(%q) = %v, %v, %q; want %v, %v, %q",
|
||||
c.in, maj, min, tail, c.maj, c.min, c.tail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileOrder(t *testing.T) {
|
||||
fs := []File{
|
||||
{Filename: "go1.3.src.tar.gz", Version: "go1.3", OS: "", Arch: "", Kind: "source"},
|
||||
{Filename: "go1.3.1.src.tar.gz", Version: "go1.3.1", OS: "", Arch: "", Kind: "source"},
|
||||
{Filename: "go1.3.linux-amd64.tar.gz", Version: "go1.3", OS: "linux", Arch: "amd64", Kind: "archive"},
|
||||
{Filename: "go1.3.1.linux-amd64.tar.gz", Version: "go1.3.1", OS: "linux", Arch: "amd64", Kind: "archive"},
|
||||
{Filename: "go1.3.darwin-amd64.tar.gz", Version: "go1.3", OS: "darwin", Arch: "amd64", Kind: "archive"},
|
||||
{Filename: "go1.3.darwin-amd64.pkg", Version: "go1.3", OS: "darwin", Arch: "amd64", Kind: "installer"},
|
||||
{Filename: "go1.3.darwin-386.tar.gz", Version: "go1.3", OS: "darwin", Arch: "386", Kind: "archive"},
|
||||
{Filename: "go1.3beta1.linux-amd64.tar.gz", Version: "go1.3beta1", OS: "linux", Arch: "amd64", Kind: "archive"},
|
||||
{Filename: "go1.3beta2.linux-amd64.tar.gz", Version: "go1.3beta2", OS: "linux", Arch: "amd64", Kind: "archive"},
|
||||
{Filename: "go1.3rc1.linux-amd64.tar.gz", Version: "go1.3rc1", OS: "linux", Arch: "amd64", Kind: "archive"},
|
||||
{Filename: "go1.2.linux-amd64.tar.gz", Version: "go1.2", OS: "linux", Arch: "amd64", Kind: "archive"},
|
||||
{Filename: "go1.2.2.linux-amd64.tar.gz", Version: "go1.2.2", OS: "linux", Arch: "amd64", Kind: "archive"},
|
||||
}
|
||||
sort.Sort(fileOrder(fs))
|
||||
var s []string
|
||||
for _, f := range fs {
|
||||
s = append(s, f.Filename)
|
||||
}
|
||||
got := strings.Join(s, "\n")
|
||||
want := strings.Join([]string{
|
||||
"go1.3.1.src.tar.gz",
|
||||
"go1.3.1.linux-amd64.tar.gz",
|
||||
"go1.3.src.tar.gz",
|
||||
"go1.3.darwin-386.tar.gz",
|
||||
"go1.3.darwin-amd64.tar.gz",
|
||||
"go1.3.darwin-amd64.pkg",
|
||||
"go1.3.linux-amd64.tar.gz",
|
||||
"go1.2.2.linux-amd64.tar.gz",
|
||||
"go1.2.linux-amd64.tar.gz",
|
||||
"go1.3rc1.linux-amd64.tar.gz",
|
||||
"go1.3beta2.linux-amd64.tar.gz",
|
||||
"go1.3beta1.linux-amd64.tar.gz",
|
||||
}, "\n")
|
||||
if got != want {
|
||||
t.Errorf("sort order is\n%s\nwant:\n%s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilesToReleases(t *testing.T) {
|
||||
fs := []File{
|
||||
{Version: "go1.7.4", OS: "darwin"},
|
||||
{Version: "go1.7.4", OS: "windows"},
|
||||
{Version: "go1.7", OS: "darwin"},
|
||||
{Version: "go1.7", OS: "windows"},
|
||||
{Version: "go1.6.2", OS: "darwin"},
|
||||
{Version: "go1.6.2", OS: "windows"},
|
||||
{Version: "go1.6", OS: "darwin"},
|
||||
{Version: "go1.6", OS: "windows"},
|
||||
{Version: "go1.5.2", OS: "darwin"},
|
||||
{Version: "go1.5.2", OS: "windows"},
|
||||
{Version: "go1.5", OS: "darwin"},
|
||||
{Version: "go1.5", OS: "windows"},
|
||||
{Version: "go1.5beta1", OS: "windows"},
|
||||
}
|
||||
stable, unstable, archive := filesToReleases(fs)
|
||||
if got, want := len(stable), 2; want != got {
|
||||
t.Errorf("len(stable): got %v, want %v", got, want)
|
||||
} else {
|
||||
if got, want := stable[0].Version, "go1.7.4"; want != got {
|
||||
t.Errorf("stable[0].Version: got %v, want %v", got, want)
|
||||
}
|
||||
if got, want := stable[1].Version, "go1.6.2"; want != got {
|
||||
t.Errorf("stable[1].Version: got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
if got, want := len(unstable), 0; want != got {
|
||||
t.Errorf("len(unstable): got %v, want %v", got, want)
|
||||
}
|
||||
if got, want := len(archive), 4; want != got {
|
||||
t.Errorf("len(archive): got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOldUnstableNotShown(t *testing.T) {
|
||||
fs := []File{
|
||||
{Version: "go1.7.4"},
|
||||
{Version: "go1.7"},
|
||||
{Version: "go1.7beta1"},
|
||||
}
|
||||
_, unstable, _ := filesToReleases(fs)
|
||||
if len(unstable) != 0 {
|
||||
t.Errorf("got unstable, want none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnstableShown(t *testing.T) {
|
||||
fs := []File{
|
||||
{Version: "go1.8beta2"},
|
||||
{Version: "go1.8rc1"},
|
||||
{Version: "go1.7.4"},
|
||||
{Version: "go1.7"},
|
||||
{Version: "go1.7beta1"},
|
||||
}
|
||||
_, unstable, _ := filesToReleases(fs)
|
||||
if got, want := len(unstable), 1; got != want {
|
||||
t.Fatalf("len(unstable): got %v, want %v", got, want)
|
||||
}
|
||||
// show rcs ahead of betas.
|
||||
if got, want := unstable[0].Version, "go1.8rc1"; got != want {
|
||||
t.Fatalf("unstable[0].Version: got %v, want %v", got, want)
|
||||
}
|
||||
}
|
279
vendor/golang.org/x/tools/godoc/dl/tmpl.go
generated
vendored
Normal file
279
vendor/golang.org/x/tools/godoc/dl/tmpl.go
generated
vendored
Normal file
@@ -0,0 +1,279 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
package dl
|
||||
|
||||
// TODO(adg): refactor this to use the tools/godoc/static template.
|
||||
|
||||
const templateHTML = `
|
||||
{{define "root"}}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Downloads - The Go Programming Language</title>
|
||||
<link type="text/css" rel="stylesheet" href="/lib/godoc/style.css">
|
||||
<script type="text/javascript">window.initFuncs = [];</script>
|
||||
<style>
|
||||
table.codetable {
|
||||
margin-left: 20px; margin-right: 20px;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.codetable tr {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
table.codetable tr:nth-child(2n), table.codetable tr.first {
|
||||
background-color: white;
|
||||
}
|
||||
table.codetable td, table.codetable th {
|
||||
white-space: nowrap;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
table.codetable tt {
|
||||
font-size: xx-small;
|
||||
}
|
||||
table.codetable tr.highlight td {
|
||||
font-weight: bold;
|
||||
}
|
||||
a.downloadBox {
|
||||
display: block;
|
||||
color: #222;
|
||||
border: 1px solid #375EAB;
|
||||
border-radius: 5px;
|
||||
background: #E0EBF5;
|
||||
width: 280px;
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
a.downloadBox:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.downloadBox .platform {
|
||||
font-size: large;
|
||||
}
|
||||
.downloadBox .filename {
|
||||
color: #375EAB;
|
||||
font-weight: bold;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
a.downloadBox:hover .filename {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.downloadBox .size {
|
||||
font-size: small;
|
||||
font-weight: normal;
|
||||
}
|
||||
.downloadBox .reqs {
|
||||
font-size: small;
|
||||
font-style: italic;
|
||||
}
|
||||
.downloadBox .checksum {
|
||||
font-size: 5pt;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="topbar"><div class="container">
|
||||
|
||||
<div class="top-heading"><a href="/">The Go Programming Language</a></div>
|
||||
<form method="GET" action="/search">
|
||||
<div id="menu">
|
||||
<a href="/doc/">Documents</a>
|
||||
<a href="/pkg/">Packages</a>
|
||||
<a href="/project/">The Project</a>
|
||||
<a href="/help/">Help</a>
|
||||
<a href="/blog/">Blog</a>
|
||||
<span class="search-box"><input type="search" id="search" name="q" placeholder="Search" aria-label="Search" required><button type="submit"><span><!-- magnifying glass: --><svg width="24" height="24" viewBox="0 0 24 24"><title>submit search</title><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/><path d="M0 0h24v24H0z" fill="none"/></svg></span></button></span>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div></div>
|
||||
|
||||
<div id="page">
|
||||
<div class="container">
|
||||
|
||||
<h1>Downloads</h1>
|
||||
|
||||
<p>
|
||||
After downloading a binary release suitable for your system,
|
||||
please follow the <a href="/doc/install">installation instructions</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you are building from source,
|
||||
follow the <a href="/doc/install/source">source installation instructions</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
See the <a href="/doc/devel/release.html">release history</a> for more
|
||||
information about Go releases.
|
||||
</p>
|
||||
|
||||
{{with .Featured}}
|
||||
<h3 id="featured">Featured downloads</h3>
|
||||
{{range .}}
|
||||
{{template "download" .}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
<div style="clear: both;"></div>
|
||||
|
||||
{{with .Stable}}
|
||||
<h3 id="stable">Stable versions</h3>
|
||||
{{template "releases" .}}
|
||||
{{end}}
|
||||
|
||||
{{with .Unstable}}
|
||||
<h3 id="unstable">Unstable version</h3>
|
||||
{{template "releases" .}}
|
||||
{{end}}
|
||||
|
||||
{{with .Archive}}
|
||||
<div class="toggle" id="archive">
|
||||
<div class="collapsed">
|
||||
<h3 class="toggleButton" title="Click to show versions">Archived versions▹</h3>
|
||||
</div>
|
||||
<div class="expanded">
|
||||
<h3 class="toggleButton" title="Click to hide versions">Archived versions▾</h3>
|
||||
{{template "releases" .}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div id="footer">
|
||||
<p>
|
||||
Except as
|
||||
<a href="https://developers.google.com/site-policies#restrictions">noted</a>,
|
||||
the content of this page is licensed under the Creative Commons
|
||||
Attribution 3.0 License,<br>
|
||||
and code is licensed under a <a href="http://golang.org/LICENSE">BSD license</a>.<br>
|
||||
<a href="http://golang.org/doc/tos.html">Terms of Service</a> |
|
||||
<a href="http://www.google.com/intl/en/policies/privacy/">Privacy Policy</a>
|
||||
</p>
|
||||
</div><!-- #footer -->
|
||||
|
||||
</div><!-- .container -->
|
||||
</div><!-- #page -->
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-11222381-2', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
<script src="/lib/godoc/jquery.js"></script>
|
||||
<script src="/lib/godoc/godocs.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('a.download').click(function(e) {
|
||||
// Try using the link text as the file name,
|
||||
// unless there's a child element of class 'filename'.
|
||||
var filename = $(this).text();
|
||||
var child = $(this).find('.filename');
|
||||
if (child.length > 0) {
|
||||
filename = child.text();
|
||||
}
|
||||
|
||||
// This must be kept in sync with the filenameRE in godocs.js.
|
||||
var filenameRE = /^go1\.\d+(\.\d+)?([a-z0-9]+)?\.([a-z0-9]+)(-[a-z0-9]+)?(-osx10\.[68])?\.([a-z.]+)$/;
|
||||
var m = filenameRE.exec(filename);
|
||||
if (!m) {
|
||||
// Don't redirect to the download page if it won't recognize this file.
|
||||
// (Should not happen.)
|
||||
return;
|
||||
}
|
||||
|
||||
var dest = "/doc/install";
|
||||
if (filename.indexOf(".src.") != -1) {
|
||||
dest += "/source";
|
||||
}
|
||||
dest += "?download=" + filename;
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
window.location = dest;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</html>
|
||||
{{end}}
|
||||
|
||||
{{define "releases"}}
|
||||
{{range .}}
|
||||
<div class="toggle{{if .Visible}}Visible{{end}}" id="{{.Version}}">
|
||||
<div class="collapsed">
|
||||
<h2 class="toggleButton" title="Click to show downloads for this version">{{.Version}} ▹</h2>
|
||||
</div>
|
||||
<div class="expanded">
|
||||
<h2 class="toggleButton" title="Click to hide downloads for this version">{{.Version}} ▾</h2>
|
||||
{{if .Stable}}{{else}}
|
||||
<p>This is an <b>unstable</b> version of Go. Use with caution.</p>
|
||||
<p>If you already have Go installed, you can install this version by running:</p>
|
||||
<pre>
|
||||
go get golang.org/x/build/version/{{.Version}}
|
||||
</pre>
|
||||
<p>Then, use the <code>{{.Version}}</code> command instead of the <code>go</code> command to use {{.Version}}.</p>
|
||||
{{end}}
|
||||
{{template "files" .}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{define "files"}}
|
||||
<table class="codetable">
|
||||
<thead>
|
||||
<tr class="first">
|
||||
<th>File name</th>
|
||||
<th>Kind</th>
|
||||
<th>OS</th>
|
||||
<th>Arch</th>
|
||||
<th>Size</th>
|
||||
{{/* Use the checksum type of the first file for the column heading. */}}
|
||||
<th>{{(index .Files 0).ChecksumType}} Checksum</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{{if .SplitPortTable}}
|
||||
{{range .Files}}{{if .PrimaryPort}}{{template "file" .}}{{end}}{{end}}
|
||||
|
||||
{{/* TODO(cbro): add a link to an explanatory doc page */}}
|
||||
<tr class="first"><th colspan="6" class="first">Other Ports</th></tr>
|
||||
{{range .Files}}{{if not .PrimaryPort}}{{template "file" .}}{{end}}{{end}}
|
||||
{{else}}
|
||||
{{range .Files}}{{template "file" .}}{{end}}
|
||||
{{end}}
|
||||
</table>
|
||||
{{end}}
|
||||
|
||||
{{define "file"}}
|
||||
<tr{{if .Highlight}} class="highlight"{{end}}>
|
||||
<td class="filename"><a class="download" href="{{.URL}}">{{.Filename}}</a></td>
|
||||
<td>{{pretty .Kind}}</td>
|
||||
<td>{{.PrettyOS}}</td>
|
||||
<td>{{pretty .Arch}}</td>
|
||||
<td>{{.PrettySize}}</td>
|
||||
<td><tt>{{.PrettyChecksum}}</tt></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
||||
{{define "download"}}
|
||||
<a class="download downloadBox" href="{{.URL}}">
|
||||
<div class="platform">{{.Platform}}</div>
|
||||
{{with .Requirements}}<div class="reqs">{{.}}</div>{{end}}
|
||||
<div>
|
||||
<span class="filename">{{.Filename}}</span>
|
||||
{{if .Size}}<span class="size">({{.PrettySize}})</span>{{end}}
|
||||
</div>
|
||||
</a>
|
||||
{{end}}
|
||||
`
|
Reference in New Issue
Block a user