internal/stdlib: refactor getGoRepo, add clone tests

Refactor getGoRepo to handle both test and cloned repos.  This will
enable adding a third option, getting the Go repo from a local copy.

Also add a test for checking the contents of a cloned repo, to make
sure the clone logic is correct. Flag-protect it because it's slow
and hits an external server.

Change-Id: I9de50bf12fccbd4fa35aa0566bdee3cddb25edf8
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/347403
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
diff --git a/internal/stdlib/stdlib.go b/internal/stdlib/stdlib.go
index d875773..2c57d76 100644
--- a/internal/stdlib/stdlib.go
+++ b/internal/stdlib/stdlib.go
@@ -200,10 +200,19 @@
 )
 
 // getGoRepo returns a repo object for the Go repo at version.
-func getGoRepo(v string) (_ *git.Repository, err error) {
-	defer derrors.Wrap(&err, "getGoRepo(%q)", v)
+func getGoRepo(version string) (_ *git.Repository, _ plumbing.ReferenceName, err error) {
+	defer derrors.Wrap(&err, "getGoRepo(%q)", version)
+	if UseTestData {
+		return getTestGoRepo(version)
+	}
+	return cloneGoRepo(version)
+}
 
-	var ref plumbing.ReferenceName
+// cloneGoRepo returns a repo object for the Go repo at version by cloning the
+// Go repo.
+func cloneGoRepo(v string) (_ *git.Repository, ref plumbing.ReferenceName, err error) {
+	defer derrors.Wrap(&err, "cloneGoRepo(%q)", v)
+
 	if v == version.Master {
 		ref = plumbing.HEAD
 	} else if SupportedBranches[v] {
@@ -211,21 +220,25 @@
 	} else {
 		tag, err := TagForVersion(v)
 		if err != nil {
-			return nil, err
+			return nil, "", err
 		}
 		ref = plumbing.NewTagReferenceName(tag)
 	}
-	return git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
+	repo, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
 		URL:           GoRepoURL,
 		ReferenceName: ref,
 		SingleBranch:  true,
 		Depth:         1,
 		Tags:          git.NoTags,
 	})
+	if err != nil {
+		return nil, "", err
+	}
+	return repo, ref, nil
 }
 
 // getTestGoRepo gets a Go repo for testing.
-func getTestGoRepo(v string) (_ *git.Repository, err error) {
+func getTestGoRepo(v string) (_ *git.Repository, _ plumbing.ReferenceName, err error) {
 	defer derrors.Wrap(&err, "getTestGoRepo(%q)", v)
 	if v == TestMasterVersion {
 		v = version.Master
@@ -236,15 +249,15 @@
 	fs := osfs.New(filepath.Join(testhelper.TestDataPath("testdata"), v))
 	repo, err := git.Init(memory.NewStorage(), fs)
 	if err != nil {
-		return nil, fmt.Errorf("git.Initi: %v", err)
+		return nil, "", fmt.Errorf("git.Initi: %v", err)
 	}
 	wt, err := repo.Worktree()
 	if err != nil {
-		return nil, fmt.Errorf("repo.Worktree: %v", err)
+		return nil, "", fmt.Errorf("repo.Worktree: %v", err)
 	}
 	// Add all files in the directory.
 	if _, err := wt.Add(""); err != nil {
-		return nil, fmt.Errorf("wt.Add(): %v", err)
+		return nil, "", fmt.Errorf("wt.Add(): %v", err)
 	}
 	_, err = wt.Commit("", &git.CommitOptions{All: true, Author: &object.Signature{
 		Name:  "Joe Random",
@@ -252,9 +265,9 @@
 		When:  TestCommitTime,
 	}})
 	if err != nil {
-		return nil, fmt.Errorf("wt.Commit: %v", err)
+		return nil, "", fmt.Errorf("wt.Commit: %v", err)
 	}
-	return repo, nil
+	return repo, plumbing.HEAD, nil
 }
 
 // Versions returns all the versions of Go that are relevant to the discovery
@@ -316,28 +329,24 @@
 }
 
 func zipInternal(requestedVersion string) (_ *zip.Reader, resolvedVersion string, commitTime time.Time, prefix string, err error) {
-	var repo *git.Repository
-	if UseTestData {
-		repo, err = getTestGoRepo(requestedVersion)
-	} else {
-		if requestedVersion == version.Latest {
-			requestedVersion, err = semanticVersion(requestedVersion)
-			if err != nil {
-				return nil, "", time.Time{}, "", err
-			}
+	if !UseTestData && requestedVersion == version.Latest {
+		requestedVersion, err = semanticVersion(requestedVersion)
+		if err != nil {
+			return nil, "", time.Time{}, "", err
 		}
-		repo, err = getGoRepo(requestedVersion)
 	}
+	repo, refName, err := getGoRepo(requestedVersion)
 	if err != nil {
 		return nil, "", time.Time{}, "", err
 	}
 	var buf bytes.Buffer
 	z := zip.NewWriter(&buf)
-	head, err := repo.Head()
+
+	ref, err := repo.Reference(refName, true)
 	if err != nil {
 		return nil, "", time.Time{}, "", err
 	}
-	commit, err := repo.CommitObject(head.Hash())
+	commit, err := repo.CommitObject(ref.Hash())
 	if err != nil {
 		return nil, "", time.Time{}, "", err
 	}
diff --git a/internal/stdlib/stdlib_test.go b/internal/stdlib/stdlib_test.go
index 3555b2f..0e20402 100644
--- a/internal/stdlib/stdlib_test.go
+++ b/internal/stdlib/stdlib_test.go
@@ -6,6 +6,7 @@
 
 import (
 	"errors"
+	"flag"
 	"io/fs"
 	"reflect"
 	"testing"
@@ -14,6 +15,8 @@
 	"golang.org/x/pkgsite/internal/version"
 )
 
+var clone = flag.Bool("clone", false, "test actual clones of the Go repo")
+
 func TestTagForVersion(t *testing.T) {
 	for _, test := range []struct {
 		name    string
@@ -142,39 +145,65 @@
 			if !gotTime.Equal(TestCommitTime) {
 				t.Errorf("commit time: got %s, want %s", gotTime, TestCommitTime)
 			}
-			wantFiles := map[string]bool{
-				"LICENSE":               true,
-				"errors/errors.go":      true,
-				"errors/errors_test.go": true,
-			}
-			if semver.Compare(resolvedVersion, "v1.13.0") > 0 || resolvedVersion == TestMasterVersion {
-				wantFiles["cmd/README.vendor"] = true
-			}
+			checkContentDirFiles(t, cdir, resolvedVersion)
+		})
+	}
+}
 
-			const readmeVendorFile = "README.vendor"
-			if _, err := fs.Stat(cdir, readmeVendorFile); !errors.Is(err, fs.ErrNotExist) {
-				t.Fatalf("fs.Stat returned %v; want %q to be removed", err, readmeVendorFile)
-			}
-			err = fs.WalkDir(cdir, ".", func(path string, d fs.DirEntry, err error) error {
-				if err != nil {
-					return err
-				}
-				if d.IsDir() {
-					return nil
-				}
-				delete(wantFiles, path)
-				return nil
-			})
+func TestContentDirClone(t *testing.T) {
+	if !*clone {
+		t.Skip("-clone not supplied")
+	}
+	for _, resolvedVersion := range []string{
+		"v1.3.2",
+		"v1.14.6",
+		version.Master,
+		version.Latest,
+	} {
+		t.Run(resolvedVersion, func(t *testing.T) {
+			cdir, _, _, err := ContentDir(resolvedVersion)
 			if err != nil {
 				t.Fatal(err)
 			}
-			if len(wantFiles) > 0 {
-				t.Errorf("zip missing files: %v", reflect.ValueOf(wantFiles).MapKeys())
-			}
+			checkContentDirFiles(t, cdir, resolvedVersion)
 		})
 	}
 }
 
+func checkContentDirFiles(t *testing.T, cdir fs.FS, resolvedVersion string) {
+	wantFiles := map[string]bool{
+		"LICENSE":               true,
+		"errors/errors.go":      true,
+		"errors/errors_test.go": true,
+	}
+	if semver.Compare(resolvedVersion, "v1.13.0") > 0 || resolvedVersion == TestMasterVersion {
+		wantFiles["cmd/README.vendor"] = true
+	}
+	if semver.Compare(resolvedVersion, "v1.14.0") > 0 {
+		wantFiles["context/context.go"] = true
+	}
+	const readmeVendorFile = "README.vendor"
+	if _, err := fs.Stat(cdir, readmeVendorFile); !errors.Is(err, fs.ErrNotExist) {
+		t.Fatalf("fs.Stat returned %v; want %q to be removed", err, readmeVendorFile)
+	}
+	err := fs.WalkDir(cdir, ".", func(path string, d fs.DirEntry, err error) error {
+		if err != nil {
+			return err
+		}
+		if d.IsDir() {
+			return nil
+		}
+		delete(wantFiles, path)
+		return nil
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(wantFiles) > 0 {
+		t.Errorf("zip missing files: %v", reflect.ValueOf(wantFiles).MapKeys())
+	}
+}
+
 func TestZipInfo(t *testing.T) {
 	UseTestData = true
 	defer func() { UseTestData = false }()
diff --git a/internal/stdlib/testdata/v1.14.6/src/context/context.go b/internal/stdlib/testdata/v1.14.6/src/context/context.go
new file mode 100644
index 0000000..b561968
--- /dev/null
+++ b/internal/stdlib/testdata/v1.14.6/src/context/context.go
@@ -0,0 +1,554 @@
+// Copyright 2014 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 context defines the Context type, which carries deadlines,
+// cancellation signals, and other request-scoped values across API boundaries
+// and between processes.
+//
+// Incoming requests to a server should create a Context, and outgoing
+// calls to servers should accept a Context. The chain of function
+// calls between them must propagate the Context, optionally replacing
+// it with a derived Context created using WithCancel, WithDeadline,
+// WithTimeout, or WithValue. When a Context is canceled, all
+// Contexts derived from it are also canceled.
+//
+// The WithCancel, WithDeadline, and WithTimeout functions take a
+// Context (the parent) and return a derived Context (the child) and a
+// CancelFunc. Calling the CancelFunc cancels the child and its
+// children, removes the parent's reference to the child, and stops
+// any associated timers. Failing to call the CancelFunc leaks the
+// child and its children until the parent is canceled or the timer
+// fires. The go vet tool checks that CancelFuncs are used on all
+// control-flow paths.
+//
+// Programs that use Contexts should follow these rules to keep interfaces
+// consistent across packages and enable static analysis tools to check context
+// propagation:
+//
+// Do not store Contexts inside a struct type; instead, pass a Context
+// explicitly to each function that needs it. The Context should be the first
+// parameter, typically named ctx:
+//
+// 	func DoSomething(ctx context.Context, arg Arg) error {
+// 		// ... use ctx ...
+// 	}
+//
+// Do not pass a nil Context, even if a function permits it. Pass context.TODO
+// if you are unsure about which Context to use.
+//
+// Use context Values only for request-scoped data that transits processes and
+// APIs, not for passing optional parameters to functions.
+//
+// The same Context may be passed to functions running in different goroutines;
+// Contexts are safe for simultaneous use by multiple goroutines.
+//
+// See https://blog.golang.org/context for example code for a server that uses
+// Contexts.
+package context
+
+import (
+	"errors"
+	"internal/reflectlite"
+	"sync"
+	"sync/atomic"
+	"time"
+)
+
+// A Context carries a deadline, a cancellation signal, and other values across
+// API boundaries.
+//
+// Context's methods may be called by multiple goroutines simultaneously.
+type Context interface {
+	// Deadline returns the time when work done on behalf of this context
+	// should be canceled. Deadline returns ok==false when no deadline is
+	// set. Successive calls to Deadline return the same results.
+	Deadline() (deadline time.Time, ok bool)
+
+	// Done returns a channel that's closed when work done on behalf of this
+	// context should be canceled. Done may return nil if this context can
+	// never be canceled. Successive calls to Done return the same value.
+	// The close of the Done channel may happen asynchronously,
+	// after the cancel function returns.
+	//
+	// WithCancel arranges for Done to be closed when cancel is called;
+	// WithDeadline arranges for Done to be closed when the deadline
+	// expires; WithTimeout arranges for Done to be closed when the timeout
+	// elapses.
+	//
+	// Done is provided for use in select statements:
+	//
+	//  // Stream generates values with DoSomething and sends them to out
+	//  // until DoSomething returns an error or ctx.Done is closed.
+	//  func Stream(ctx context.Context, out chan<- Value) error {
+	//  	for {
+	//  		v, err := DoSomething(ctx)
+	//  		if err != nil {
+	//  			return err
+	//  		}
+	//  		select {
+	//  		case <-ctx.Done():
+	//  			return ctx.Err()
+	//  		case out <- v:
+	//  		}
+	//  	}
+	//  }
+	//
+	// See https://blog.golang.org/pipelines for more examples of how to use
+	// a Done channel for cancellation.
+	Done() <-chan struct{}
+
+	// If Done is not yet closed, Err returns nil.
+	// If Done is closed, Err returns a non-nil error explaining why:
+	// Canceled if the context was canceled
+	// or DeadlineExceeded if the context's deadline passed.
+	// After Err returns a non-nil error, successive calls to Err return the same error.
+	Err() error
+
+	// Value returns the value associated with this context for key, or nil
+	// if no value is associated with key. Successive calls to Value with
+	// the same key returns the same result.
+	//
+	// Use context values only for request-scoped data that transits
+	// processes and API boundaries, not for passing optional parameters to
+	// functions.
+	//
+	// A key identifies a specific value in a Context. Functions that wish
+	// to store values in Context typically allocate a key in a global
+	// variable then use that key as the argument to context.WithValue and
+	// Context.Value. A key can be any type that supports equality;
+	// packages should define keys as an unexported type to avoid
+	// collisions.
+	//
+	// Packages that define a Context key should provide type-safe accessors
+	// for the values stored using that key:
+	//
+	// 	// Package user defines a User type that's stored in Contexts.
+	// 	package user
+	//
+	// 	import "context"
+	//
+	// 	// User is the type of value stored in the Contexts.
+	// 	type User struct {...}
+	//
+	// 	// key is an unexported type for keys defined in this package.
+	// 	// This prevents collisions with keys defined in other packages.
+	// 	type key int
+	//
+	// 	// userKey is the key for user.User values in Contexts. It is
+	// 	// unexported; clients use user.NewContext and user.FromContext
+	// 	// instead of using this key directly.
+	// 	var userKey key
+	//
+	// 	// NewContext returns a new Context that carries value u.
+	// 	func NewContext(ctx context.Context, u *User) context.Context {
+	// 		return context.WithValue(ctx, userKey, u)
+	// 	}
+	//
+	// 	// FromContext returns the User value stored in ctx, if any.
+	// 	func FromContext(ctx context.Context) (*User, bool) {
+	// 		u, ok := ctx.Value(userKey).(*User)
+	// 		return u, ok
+	// 	}
+	Value(key interface{}) interface{}
+}
+
+// Canceled is the error returned by Context.Err when the context is canceled.
+var Canceled = errors.New("context canceled")
+
+// DeadlineExceeded is the error returned by Context.Err when the context's
+// deadline passes.
+var DeadlineExceeded error = deadlineExceededError{}
+
+type deadlineExceededError struct{}
+
+func (deadlineExceededError) Error() string   { return "context deadline exceeded" }
+func (deadlineExceededError) Timeout() bool   { return true }
+func (deadlineExceededError) Temporary() bool { return true }
+
+// An emptyCtx is never canceled, has no values, and has no deadline. It is not
+// struct{}, since vars of this type must have distinct addresses.
+type emptyCtx int
+
+func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
+	return
+}
+
+func (*emptyCtx) Done() <-chan struct{} {
+	return nil
+}
+
+func (*emptyCtx) Err() error {
+	return nil
+}
+
+func (*emptyCtx) Value(key interface{}) interface{} {
+	return nil
+}
+
+func (e *emptyCtx) String() string {
+	switch e {
+	case background:
+		return "context.Background"
+	case todo:
+		return "context.TODO"
+	}
+	return "unknown empty Context"
+}
+
+var (
+	background = new(emptyCtx)
+	todo       = new(emptyCtx)
+)
+
+// Background returns a non-nil, empty Context. It is never canceled, has no
+// values, and has no deadline. It is typically used by the main function,
+// initialization, and tests, and as the top-level Context for incoming
+// requests.
+func Background() Context {
+	return background
+}
+
+// TODO returns a non-nil, empty Context. Code should use context.TODO when
+// it's unclear which Context to use or it is not yet available (because the
+// surrounding function has not yet been extended to accept a Context
+// parameter).
+func TODO() Context {
+	return todo
+}
+
+// A CancelFunc tells an operation to abandon its work.
+// A CancelFunc does not wait for the work to stop.
+// A CancelFunc may be called by multiple goroutines simultaneously.
+// After the first call, subsequent calls to a CancelFunc do nothing.
+type CancelFunc func()
+
+// WithCancel returns a copy of parent with a new Done channel. The returned
+// context's Done channel is closed when the returned cancel function is called
+// or when the parent context's Done channel is closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
+	c := newCancelCtx(parent)
+	propagateCancel(parent, &c)
+	return &c, func() { c.cancel(true, Canceled) }
+}
+
+// newCancelCtx returns an initialized cancelCtx.
+func newCancelCtx(parent Context) cancelCtx {
+	return cancelCtx{Context: parent}
+}
+
+// goroutines counts the number of goroutines ever created; for testing.
+var goroutines int32
+
+// propagateCancel arranges for child to be canceled when parent is.
+func propagateCancel(parent Context, child canceler) {
+	done := parent.Done()
+	if done == nil {
+		return // parent is never canceled
+	}
+
+	select {
+	case <-done:
+		// parent is already canceled
+		child.cancel(false, parent.Err())
+		return
+	default:
+	}
+
+	if p, ok := parentCancelCtx(parent); ok {
+		p.mu.Lock()
+		if p.err != nil {
+			// parent has already been canceled
+			child.cancel(false, p.err)
+		} else {
+			if p.children == nil {
+				p.children = make(map[canceler]struct{})
+			}
+			p.children[child] = struct{}{}
+		}
+		p.mu.Unlock()
+	} else {
+		atomic.AddInt32(&goroutines, +1)
+		go func() {
+			select {
+			case <-parent.Done():
+				child.cancel(false, parent.Err())
+			case <-child.Done():
+			}
+		}()
+	}
+}
+
+// &cancelCtxKey is the key that a cancelCtx returns itself for.
+var cancelCtxKey int
+
+// parentCancelCtx returns the underlying *cancelCtx for parent.
+// It does this by looking up parent.Value(&cancelCtxKey) to find
+// the innermost enclosing *cancelCtx and then checking whether
+// parent.Done() matches that *cancelCtx. (If not, the *cancelCtx
+// has been wrapped in a custom implementation providing a
+// different done channel, in which case we should not bypass it.)
+func parentCancelCtx(parent Context) (*cancelCtx, bool) {
+	done := parent.Done()
+	if done == closedchan || done == nil {
+		return nil, false
+	}
+	p, ok := parent.Value(&cancelCtxKey).(*cancelCtx)
+	if !ok {
+		return nil, false
+	}
+	p.mu.Lock()
+	ok = p.done == done
+	p.mu.Unlock()
+	if !ok {
+		return nil, false
+	}
+	return p, true
+}
+
+// removeChild removes a context from its parent.
+func removeChild(parent Context, child canceler) {
+	p, ok := parentCancelCtx(parent)
+	if !ok {
+		return
+	}
+	p.mu.Lock()
+	if p.children != nil {
+		delete(p.children, child)
+	}
+	p.mu.Unlock()
+}
+
+// A canceler is a context type that can be canceled directly. The
+// implementations are *cancelCtx and *timerCtx.
+type canceler interface {
+	cancel(removeFromParent bool, err error)
+	Done() <-chan struct{}
+}
+
+// closedchan is a reusable closed channel.
+var closedchan = make(chan struct{})
+
+func init() {
+	close(closedchan)
+}
+
+// A cancelCtx can be canceled. When canceled, it also cancels any children
+// that implement canceler.
+type cancelCtx struct {
+	Context
+
+	mu       sync.Mutex            // protects following fields
+	done     chan struct{}         // created lazily, closed by first cancel call
+	children map[canceler]struct{} // set to nil by the first cancel call
+	err      error                 // set to non-nil by the first cancel call
+}
+
+func (c *cancelCtx) Value(key interface{}) interface{} {
+	if key == &cancelCtxKey {
+		return c
+	}
+	return c.Context.Value(key)
+}
+
+func (c *cancelCtx) Done() <-chan struct{} {
+	c.mu.Lock()
+	if c.done == nil {
+		c.done = make(chan struct{})
+	}
+	d := c.done
+	c.mu.Unlock()
+	return d
+}
+
+func (c *cancelCtx) Err() error {
+	c.mu.Lock()
+	err := c.err
+	c.mu.Unlock()
+	return err
+}
+
+type stringer interface {
+	String() string
+}
+
+func contextName(c Context) string {
+	if s, ok := c.(stringer); ok {
+		return s.String()
+	}
+	return reflectlite.TypeOf(c).String()
+}
+
+func (c *cancelCtx) String() string {
+	return contextName(c.Context) + ".WithCancel"
+}
+
+// cancel closes c.done, cancels each of c's children, and, if
+// removeFromParent is true, removes c from its parent's children.
+func (c *cancelCtx) cancel(removeFromParent bool, err error) {
+	if err == nil {
+		panic("context: internal error: missing cancel error")
+	}
+	c.mu.Lock()
+	if c.err != nil {
+		c.mu.Unlock()
+		return // already canceled
+	}
+	c.err = err
+	if c.done == nil {
+		c.done = closedchan
+	} else {
+		close(c.done)
+	}
+	for child := range c.children {
+		// NOTE: acquiring the child's lock while holding parent's lock.
+		child.cancel(false, err)
+	}
+	c.children = nil
+	c.mu.Unlock()
+
+	if removeFromParent {
+		removeChild(c.Context, c)
+	}
+}
+
+// WithDeadline returns a copy of the parent context with the deadline adjusted
+// to be no later than d. If the parent's deadline is already earlier than d,
+// WithDeadline(parent, d) is semantically equivalent to parent. The returned
+// context's Done channel is closed when the deadline expires, when the returned
+// cancel function is called, or when the parent context's Done channel is
+// closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {
+	if cur, ok := parent.Deadline(); ok && cur.Before(d) {
+		// The current deadline is already sooner than the new one.
+		return WithCancel(parent)
+	}
+	c := &timerCtx{
+		cancelCtx: newCancelCtx(parent),
+		deadline:  d,
+	}
+	propagateCancel(parent, c)
+	dur := time.Until(d)
+	if dur <= 0 {
+		c.cancel(true, DeadlineExceeded) // deadline has already passed
+		return c, func() { c.cancel(false, Canceled) }
+	}
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	if c.err == nil {
+		c.timer = time.AfterFunc(dur, func() {
+			c.cancel(true, DeadlineExceeded)
+		})
+	}
+	return c, func() { c.cancel(true, Canceled) }
+}
+
+// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
+// implement Done and Err. It implements cancel by stopping its timer then
+// delegating to cancelCtx.cancel.
+type timerCtx struct {
+	cancelCtx
+	timer *time.Timer // Under cancelCtx.mu.
+
+	deadline time.Time
+}
+
+func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
+	return c.deadline, true
+}
+
+func (c *timerCtx) String() string {
+	return contextName(c.cancelCtx.Context) + ".WithDeadline(" +
+		c.deadline.String() + " [" +
+		time.Until(c.deadline).String() + "])"
+}
+
+func (c *timerCtx) cancel(removeFromParent bool, err error) {
+	c.cancelCtx.cancel(false, err)
+	if removeFromParent {
+		// Remove this timerCtx from its parent cancelCtx's children.
+		removeChild(c.cancelCtx.Context, c)
+	}
+	c.mu.Lock()
+	if c.timer != nil {
+		c.timer.Stop()
+		c.timer = nil
+	}
+	c.mu.Unlock()
+}
+
+// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete:
+//
+// 	func slowOperationWithTimeout(ctx context.Context) (Result, error) {
+// 		ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
+// 		defer cancel()  // releases resources if slowOperation completes before timeout elapses
+// 		return slowOperation(ctx)
+// 	}
+func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
+	return WithDeadline(parent, time.Now().Add(timeout))
+}
+
+// WithValue returns a copy of parent in which the value associated with key is
+// val.
+//
+// Use context Values only for request-scoped data that transits processes and
+// APIs, not for passing optional parameters to functions.
+//
+// The provided key must be comparable and should not be of type
+// string or any other built-in type to avoid collisions between
+// packages using context. Users of WithValue should define their own
+// types for keys. To avoid allocating when assigning to an
+// interface{}, context keys often have concrete type
+// struct{}. Alternatively, exported context key variables' static
+// type should be a pointer or interface.
+func WithValue(parent Context, key, val interface{}) Context {
+	if key == nil {
+		panic("nil key")
+	}
+	if !reflectlite.TypeOf(key).Comparable() {
+		panic("key is not comparable")
+	}
+	return &valueCtx{parent, key, val}
+}
+
+// A valueCtx carries a key-value pair. It implements Value for that key and
+// delegates all other calls to the embedded Context.
+type valueCtx struct {
+	Context
+	key, val interface{}
+}
+
+// stringify tries a bit to stringify v, without using fmt, since we don't
+// want context depending on the unicode tables. This is only used by
+// *valueCtx.String().
+func stringify(v interface{}) string {
+	switch s := v.(type) {
+	case stringer:
+		return s.String()
+	case string:
+		return s
+	}
+	return "<not Stringer>"
+}
+
+func (c *valueCtx) String() string {
+	return contextName(c.Context) + ".WithValue(type " +
+		reflectlite.TypeOf(c.key).String() +
+		", val " + stringify(c.val) + ")"
+}
+
+func (c *valueCtx) Value(key interface{}) interface{} {
+	if c.key == key {
+		return c.val
+	}
+	return c.Context.Value(key)
+}