cmd/go/internal/modfetch/googlesource: fetch from *.googlesource.com
diff --git a/vendor/cmd/go/internal/modfetch/googlesource/fetch.go b/vendor/cmd/go/internal/modfetch/googlesource/fetch.go
new file mode 100644
index 0000000..a51763b
--- /dev/null
+++ b/vendor/cmd/go/internal/modfetch/googlesource/fetch.go
@@ -0,0 +1,283 @@
+// Copyright 2018 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.
+
+package googlesource
+
+import (
+	"archive/tar"
+	"archive/zip"
+	"bufio"
+	"compress/gzip"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/url"
+	"os"
+	"strconv"
+	"strings"
+	"time"
+
+	"cmd/go/internal/modfetch/codehost"
+	web "cmd/go/internal/web2"
+)
+
+func Lookup(path string) (codehost.Repo, error) {
+	i := strings.Index(path, "/")
+	if i+1 == len(path) || !strings.HasSuffix(path[:i+1], ".googlesource.com/") {
+		return nil, fmt.Errorf("not *.googlesource.com/*")
+	}
+	j := strings.Index(path[i+1:], "/")
+	if j >= 0 {
+		path = path[:i+1+j]
+	}
+	r := &repo{
+		root: path,
+		base: "https://" + path,
+	}
+	return r, nil
+}
+
+type repo struct {
+	base string
+	root string
+}
+
+func (r *repo) Root() string {
+	return r.root
+}
+
+func (r *repo) Tags(prefix string) ([]string, error) {
+	var data []byte
+	err := web.Get(r.base+"/+refs/tags/?format=TEXT", web.ReadAllBody(&data))
+	if err != nil {
+		return nil, err
+	}
+	prefix = "refs/tags/" + prefix
+	var tags []string
+	for _, line := range strings.Split(string(data), "\n") {
+		f := strings.Fields(line)
+		if len(f) == 2 && len(f[0]) == 40 && strings.HasPrefix(f[1], prefix) {
+			tags = append(tags, strings.TrimPrefix(f[1], "refs/tags/"))
+		}
+	}
+	return tags, nil
+}
+
+func (r *repo) LatestAt(limit time.Time, branch string) (*codehost.RevInfo, error) {
+	u := r.base + "/+log/" + url.PathEscape(branch) + "?format=JSON&n=2"
+	var n int
+	for u != "" {
+		var body io.ReadCloser
+		err := web.Get(u, web.Body(&body))
+		if err != nil {
+			return nil, err
+		}
+		b := make([]byte, 1)
+		for {
+			_, err := body.Read(b)
+			if err != nil {
+				body.Close()
+				return nil, err
+			}
+			if b[0] == '\n' {
+				break
+			}
+		}
+		var data struct {
+			Log []struct {
+				Commit    string
+				Committer struct {
+					Time string
+				}
+			}
+			Next string
+		}
+		err = json.NewDecoder(body).Decode(&data)
+		body.Close()
+		if err != nil {
+			return nil, err
+		}
+		for i := range data.Log {
+			t, err := time.Parse("Mon Jan 02 15:04:05 2006 -0700", data.Log[i].Committer.Time)
+			if err != nil {
+				return nil, err
+			}
+			if !t.After(limit) {
+				info := &codehost.RevInfo{
+					Time:  t.UTC(),
+					Name:  data.Log[i].Commit,
+					Short: codehost.ShortenSHA1(data.Log[i].Commit),
+				}
+				return info, nil
+			}
+		}
+		u = ""
+		if data.Next != "" {
+			if n == 0 {
+				n = 10
+			} else if n < 1000 {
+				n *= 2
+			}
+			u = r.base + "/+log/" + url.PathEscape(data.Next) + "?format=JSON&n=" + fmt.Sprint(n)
+		}
+	}
+	return nil, fmt.Errorf("no commits")
+}
+
+func (r *repo) Stat(rev string) (*codehost.RevInfo, error) {
+	if !codehost.AllHex(rev) || len(rev) != 40 {
+		return r.LatestAt(time.Date(9999, 1, 1, 0, 0, 0, 0, time.UTC), rev)
+	}
+
+	var body io.ReadCloser
+	u := r.base + "/+show/" + url.PathEscape(rev) + "?format=TEXT"
+	if err := web.Get(u, web.Body(&body)); err != nil {
+		return nil, err
+	}
+	defer body.Close()
+	b := bufio.NewReader(base64.NewDecoder(base64.StdEncoding, body))
+	for {
+		line, err := b.ReadSlice('\n')
+		if err != nil {
+			return nil, err
+		}
+		s := string(line)
+		if s == "\n" {
+			return nil, fmt.Errorf("malformed commit: no committer")
+		}
+		if strings.HasPrefix(s, "committer ") {
+			f := strings.Fields(s)
+			if len(f) >= 3 {
+				v, err := strconv.ParseUint(f[len(f)-2], 10, 64)
+				if err == nil {
+					info := &codehost.RevInfo{
+						Time:  time.Unix(int64(v), 0).UTC(),
+						Name:  rev,
+						Short: codehost.ShortenSHA1(rev),
+					}
+					return info, nil
+				}
+			}
+		}
+	}
+}
+
+func (r *repo) ReadFile(rev, file string, maxSize int64) ([]byte, error) {
+	u := r.base + "/+show/" + url.PathEscape(rev) + "/" + file + "?format=TEXT"
+	var body io.ReadCloser
+	if err := web.Get(u, web.Body(&body)); err != nil {
+		return nil, err
+	}
+	defer body.Close()
+	lr := &io.LimitedReader{R: base64.NewDecoder(base64.StdEncoding, body), N: maxSize + 1}
+	data, err := ioutil.ReadAll(lr)
+	if lr.N <= 0 {
+		return data, fmt.Errorf("too long")
+	}
+	return data, err
+}
+
+type closeRemover struct {
+	*os.File
+}
+
+func (c *closeRemover) Close() error {
+	c.File.Close()
+	os.Remove(c.File.Name())
+	return nil
+}
+
+func (r *repo) ReadZip(rev, subdir string, maxSize int64) (zipstream io.ReadCloser, actualSubdir string, err error) {
+	// Start download of tgz for subdir.
+	if subdir != "" {
+		subdir = "/" + strings.TrimSuffix(subdir, "/")
+	}
+	u := r.base + "/+archive/" + url.PathEscape(rev) + subdir + ".tar.gz"
+	var body io.ReadCloser
+	if err := web.Get(u, web.Body(&body)); err != nil {
+		return nil, "", err
+	}
+	defer body.Close()
+	gz, err := gzip.NewReader(body)
+	if err != nil {
+		return nil, "", err
+	}
+	defer gz.Close()
+	tr := tar.NewReader(gz)
+
+	// Start temporary zip file.
+	f, err := ioutil.TempFile("", "vgo-")
+	if err != nil {
+		return nil, "", err
+	}
+	defer func() {
+		f.Close()
+		if err != nil {
+			os.Remove(f.Name())
+		}
+	}()
+	z := zip.NewWriter(f)
+
+	// Copy files from tgz to zip file.
+	prefix := "googlesource/"
+	haveLICENSE := false
+	for {
+		hdr, err := tr.Next()
+		if err != nil {
+			if err == io.EOF {
+				break
+			}
+			return nil, "", fmt.Errorf("reading tgz from gitiles: %v", err)
+		}
+		maxSize -= 512
+		switch hdr.Typeflag {
+		case tar.TypeDir:
+			// ok
+		case tar.TypeReg:
+			if maxSize < hdr.Size {
+				return nil, "", fmt.Errorf("module source tree too big")
+			}
+			maxSize -= hdr.Size
+			if hdr.Name == "LICENSE" {
+				haveLICENSE = true
+			}
+			fw, err := z.Create(prefix + hdr.Name)
+			if err != nil {
+				return nil, "", err
+			}
+			if _, err := io.Copy(fw, tr); err != nil {
+				return nil, "", err
+			}
+		}
+	}
+
+	// Add LICENSE from parent directory if needed.
+	if !haveLICENSE && subdir != "" {
+		if data, err := r.ReadFile(rev, "LICENSE", codehost.MaxLICENSE); err == nil {
+			fw, err := z.Create(prefix + "LICENSE")
+			if err != nil {
+				return nil, "", err
+			}
+			if _, err := fw.Write(data); err != nil {
+				return nil, "", err
+			}
+		}
+	}
+
+	// Finish.
+	if err := z.Close(); err != nil {
+		return nil, "", err
+	}
+	if err := f.Close(); err != nil {
+		return nil, "", err
+	}
+
+	fr, err := os.Open(f.Name())
+	if err != nil {
+		return nil, "", err
+	}
+	return &closeRemover{fr}, subdir, nil
+}