Copyright 2019 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 stdlib supports special handling of the Go standard library. Regardless of the how the standard library has been split into modules for development and testing, the discovery site treats it as a single module named "std".
package stdlib

import (
	
	
	
	
	
	
	
	
	
	

	
	
	
	

	
	
	
	
	
	
	
)
ModulePath is the name of the module for the standard library.
const ModulePath = "std"

Regexp for matching go tags. The groups are: 1 the major.minor version 2 the patch version, or empty if none 3 the entire prerelease, if present 4 the prerelease type ("beta" or "rc") 5 the prerelease number
	tagRegexp = regexp.MustCompile(`^go(\d+\.\d+)(\.\d+|)((beta|rc)(\d+))?$`)
)
VersionForTag returns the semantic version for the Go tag, or "" if tag doesn't correspond to a Go release or beta tag. In special cases, when the tag specified is either `latest` or `master` it will return the tag. Examples: "go1" => "v1.0.0" "go1.2" => "v1.2.0" "go1.13beta1" => "v1.13.0-beta.1" "go1.9rc2" => "v1.9.0-rc.2" "latest" => "latest" "master" => "master"
Special cases for go1.
	if  == "go1" {
		return "v1.0.0"
	}
	if  == "go1.0" {
		return ""
Special case for latest and master.
	if  == "latest" ||  == "master" {
		return 
	}
	 := tagRegexp.FindStringSubmatch()
	if  == nil {
		return ""
	}
	 := "v" + [1]
	if [2] != "" {
		 += [2]
	} else {
		 += ".0"
	}
	if [3] != "" {
		 += "-" + [4] + "." + [5]
	}
	return 
}
TagForVersion returns the Go standard library repository tag corresponding to semver. The Go tags differ from standard semantic versions in a few ways, such as beginning with "go" instead of "v".
func ( string) ( string,  error) {
	defer derrors.Wrap(&, "TagForVersion(%q)", )
Special case: master => master
	if  == "master" || strings.HasPrefix(, "v0.0.0") {
		return "master", nil
Special case: v1.0.0 => go1.
	if  == "v1.0.0" {
		return "go1", nil
	}
	if !semver.IsValid() {
		return "", fmt.Errorf("%w: requested version is not a valid semantic version: %q ", derrors.InvalidArgument, )
	}
	 := semver.Canonical()
	 := semver.Prerelease()
	 := strings.TrimSuffix(, )
	 := strings.TrimPrefix(, semver.MajorMinor()+".")
	if  == "0" {
		 = strings.TrimSuffix(, ".0")
	}
	 = fmt.Sprintf("go%s", strings.TrimPrefix(, "v"))
Go prereleases look like "beta1" instead of "beta.1". "beta1" is bad for sorting (since beta10 comes before beta9), so require the dot form.
		 := finalDigitsIndex()
		if  >= 1 {
			if [-1] != '.' {
				return "", fmt.Errorf("%w: final digits in a prerelease must follow a period", derrors.InvalidArgument)
Remove the dot.
			 = [:-1] + [:]
		}
		 += strings.TrimPrefix(, "-")
	}
	return , nil
}
MajorVersionForVersion returns the Go major version for version. E.g. "v1.13.3" => "go1".
func ( string) ( string,  error) {
	defer derrors.Wrap(&, "MajorVersionForVersion(%q)", )

	,  := TagForVersion()
	if  != nil {
		return "", 
	}
	if  == "go1" {
		return , nil
	}
	 := strings.IndexRune(, '.')
	if  < 0 {
		return "", fmt.Errorf("no '.' in go tag %q", )
	}
	return [:], nil
}
finalDigitsIndex returns the index of the first digit in the sequence of digits ending s. If s doesn't end in digits, it returns -1.
Assume ASCII (since the semver package does anyway).
	var  int
	for  = len() - 1;  >= 0; -- {
		if [] < '0' || [] > '9' {
			break
		}
	}
	if  == len()-1 {
		return -1
	}
	return  + 1
}

const (
	GoRepoURL       = "https://go.googlesource.com/go"
	GoSourceRepoURL = "https://cs.opensource.google/go/go"
)
UseTestData determines whether to really clone the Go repo, or use stripped-down versions of the repo from the testdata directory.
TestCommitTime is the time used for all commits when UseTestData is true.
var (
	TestCommitTime = time.Date(2019, 9, 4, 1, 2, 3, 0, time.UTC)
	TestVersion    = "v0.0.0-20190904010203-89fb59e2e920"
)
getGoRepo returns a repo object for the Go repo at version.
func ( string) ( *git.Repository,  error) {
	defer derrors.Wrap(&, "getGoRepo(%q)", )

	var  plumbing.ReferenceName
	if  == "master" {
		 = plumbing.HEAD
	} else {
		,  := TagForVersion()
		if  != nil {
			return nil, 
		}
		 = plumbing.NewTagReferenceName()
	}
	return git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
		URL:           GoRepoURL,
		ReferenceName: ,
		SingleBranch:  true,
		Depth:         1,
		Tags:          git.NoTags,
	})
}
getTestGoRepo gets a Go repo for testing.
func ( string) ( *git.Repository,  error) {
	defer derrors.Wrap(&, "getTestGoRepo(%q)", )
	if strings.HasPrefix(, "v0.0.0") {
		 = "master"
	}

	 := osfs.New(filepath.Join(testhelper.TestDataPath("testdata"), ))
	,  := git.Init(memory.NewStorage(), )
	if  != nil {
		return nil, 
	}
	,  := .Worktree()
	if  != nil {
		return nil, 
Add all files in the directory.
	if ,  := .Add("");  != nil {
		return nil, 
	}
	_,  = .Commit("", &git.CommitOptions{All: true, Author: &object.Signature{
		Name:  "Joe Random",
		Email: "joe@example.com",
		When:  TestCommitTime,
	}})
	if  != nil {
		return nil, 
	}
	return , nil
}
Versions returns all the versions of Go that are relevant to the discovery site. These are all release versions (tags of the forms "goN.N" and "goN.N.N", where N is a number) and beta or rc versions (tags of the forms "goN.NbetaN" and "goN.N.NbetaN", and similarly for "rc" replacing "beta").
func () ( []string,  error) {
	defer derrors.Wrap(&, "Versions()")

	var  []plumbing.ReferenceName
	if UseTestData {
		 = testRefs
	} else {
		 := git.NewRemote(memory.NewStorage(), &config.RemoteConfig{
			URLs: []string{GoRepoURL},
		})
		,  := .List(&git.ListOptions{})
		if  != nil {
			return nil, fmt.Errorf("re.List: %v", )
		}
		for ,  := range  {
			 = append(, .Name())
		}
	}

	var  []string
	for ,  := range  {
		 := VersionForTag(.Short())
		if  != "" {
			 = append(, )
		}
	}
	return , nil
}
Directory returns the directory of the standard library relative to the repo root.
func ( string) string {
	if semver.Compare(, "v1.4.0-beta.1") >= 0 ||
		 == "master" || strings.HasPrefix(, "v0.0.0") {
		return "src"
For versions older than v1.4.0-beta.1, the stdlib is in src/pkg.
	return "src/pkg"
}
EstimatedZipSize is the approximate size of Zip("v1.15.2").
const EstimatedZipSize = 16 * 1024 * 1024
ZipInfo returns the proxy .info information for the module std.
func ( string) ( string,  error) {
	defer derrors.Wrap(&, "stdlib.ZipInfo(%q)", )

	,  = semanticVersion()
	if  != nil {
		return "", 
	}
	return , nil
}
Zip creates a module zip representing the entire Go standard library at the given version (which must have been resolved with ZipInfo) and returns a reader to it. It also returns the time of the commit for that version. The zip file is in module form, with each path prefixed by ModuleName + "@" + version. Normally, Zip returns the resolved version it was passed. If the resolved version is "master", Zip returns a semantic version for the branch. Zip reads the standard library at the Go repository tag corresponding to to the given semantic version. Zip ignores go.mod files in the standard library, treating it as if it were a single module named "std" at the given version.
This code taken, with modifications, from https://github.com/shurcooL/play/blob/master/256/moduleproxy/std/std.go.
	defer derrors.Wrap(&, "stdlib.Zip(%q)", )

	var  *git.Repository
	if UseTestData {
		,  = getTestGoRepo()
	} else {
		,  = getGoRepo()
	}
	if  != nil {
		return nil, "", time.Time{}, 
	}
	var  bytes.Buffer
	 := zip.NewWriter(&)
	,  := .Head()
	if  != nil {
		return nil, "", time.Time{}, 
	}
	,  := .CommitObject(.Hash())
	if  != nil {
		return nil, "", time.Time{}, 
	}
	if  == "master" {
		 = newPseudoVersion("v0.0.0", .Committer.When, .Hash)
	}
	,  := .TreeObject(.TreeHash)
	if  != nil {
		return nil, "", time.Time{}, 
	}
Add top-level files.
	if  := addFiles(, , , , false);  != nil {
		return nil, "", time.Time{}, 
Add files from the stdlib directory.
	 := 
	for ,  := range strings.Split(Directory(), "/") {
		,  = subTree(, , )
		if  != nil {
			return nil, "", time.Time{}, 
		}
	}
	if  := addFiles(, , , , true);  != nil {
		return nil, "", time.Time{}, 
	}
	if  := .Close();  != nil {
		return nil, "", time.Time{}, 
	}
	 := bytes.NewReader(.Bytes())
	,  := zip.NewReader(, int64(.Len()))
	if  != nil {
		return nil, "", time.Time{}, 
	}
	return , , .Committer.When, nil
}

func ( string,  time.Time,  plumbing.Hash) string {
	return fmt.Sprintf("%s-%s-%s", , .Format("20060102150405"), .String()[:12])
}
semanticVersion returns the semantic version corresponding to the requestedVersion. If the requested version is "master", then semanticVersion returns it as is. The branch name is resolved to a proper pseudo-version in Zip.
func ( string) ( string,  error) {
	defer derrors.Wrap(&, "semanticVersion(%q)", )

	if  == "master" {
		return "master", nil
	}

	,  := Versions()
	if  != nil {
		return "", 
	}

	switch  {
	case "latest":
		var  string
		for ,  := range  {
			if !strings.HasPrefix(, "v") {
				continue
			}
			,  := version.ParseType()
			if  != nil {
				return "", 
			}
We expect there to always be at least 1 release version.
				continue
			}
			if semver.Compare(, ) > 0 {
				 = 
			}
		}
		return , nil
	default:
		for ,  := range  {
			if  ==  {
				return , nil
			}
		}
	}

	return "", fmt.Errorf("%w: requested version unknown: %q", derrors.InvalidArgument, )
}
addFiles adds the files in t to z, using dirpath as the path prefix. If recursive is true, it also adds the files in all subdirectories.
func ( *zip.Writer,  *git.Repository,  *object.Tree,  string,  bool) ( error) {
	defer derrors.Wrap(&, "addFiles(zip, repository, tree, %q, %t)", , )

	for ,  := range .Entries {
		if strings.HasPrefix(.Name, ".") || strings.HasPrefix(.Name, "_") {
			continue
		}
ignore; we'll synthesize our own
			continue
		}
For versions newer than v1.4.0-beta.1, the stdlib is in src/pkg. This means that our construction of the zip files will return two READMEs at the root: https://golang.org/README.md and https://golang.org/src/README.vendor We do not want to display the README.md or any README.vendor. However, we do want to store the README in other directories.
			continue
		}
		switch .Mode {
		case filemode.Regular, filemode.Executable:
			,  := .BlobObject(.Hash)
			if  != nil {
				return 
			}
			,  := .Reader()
			if  != nil {
				return 
			}
			if  := writeZipFile(, path.Join(, .Name), );  != nil {
				_ = .Close()
				return 
			}
			if  := .Close();  != nil {
				return 
			}
		case filemode.Dir:
			if ! || .Name == "testdata" {
				continue
			}
			,  := .TreeObject(.Hash)
			if  != nil {
				return 
			}
			if  := (, , , path.Join(, .Name), );  != nil {
				return 
			}
		}
	}
	return nil
}

func ( *zip.Writer,  string,  io.Reader) ( error) {
	defer derrors.Wrap(&, "writeZipFile(zip, %q, src)", )

	,  := .Create()
	if  != nil {
		return 
	}
	_,  = io.Copy(, )
	return 
}
subTree looks non-recursively for a directory with the given name in t, and returns the corresponding tree. If a directory with such name doesn't exist in t, it returns os.ErrNotExist.
func ( *git.Repository,  *object.Tree,  string) ( *object.Tree,  error) {
	defer derrors.Wrap(&, "subTree(repository, tree, %q)", )

	for ,  := range .Entries {
		if .Name ==  {
			return .TreeObject(.Hash)
		}
	}
	return nil, os.ErrNotExist
}
Contains reports whether the given import path could be part of the Go standard library, by reporting whether the first component lacks a '.'.
func ( string) bool {
	if  := strings.IndexByte(, '/');  != -1 {
		 = [:]
	}
	return !strings.Contains(, ".")
}
References used for Versions during testing.
stdlib versions
	"refs/tags/go1.2.1",
	"refs/tags/go1.3.2",
	"refs/tags/go1.4.2",
	"refs/tags/go1.4.3",
	"refs/tags/go1.6",
	"refs/tags/go1.6.3",
	"refs/tags/go1.6beta1",
	"refs/tags/go1.8",
	"refs/tags/go1.8rc2",
	"refs/tags/go1.9rc1",
	"refs/tags/go1.11",
	"refs/tags/go1.12",
	"refs/tags/go1.12.1",
	"refs/tags/go1.12.5",
	"refs/tags/go1.12.9",
	"refs/tags/go1.13",
	"refs/tags/go1.13beta1",
	"refs/tags/go1.14.6",
other tags
	"refs/changes/56/93156/13",
	"refs/tags/release.r59",
	"refs/tags/weekly.2011-04-13",