gotip: add $GOROOT/bin to $PATH before starting go binary

This change applies the fix from CL 143545 to the gotip command,
which does not use the golang.org/dl/internal/version package at
this time.

Copy the necessary dependencies for now. In the future, the API
of ./internal/version can be reworked to make it possible for
gotip and all other commands to share more code.

Also remove a blank line in ./internal/version code, because it was
breaking up a single logical block of code and reducing readability.

Fixes golang/go#35507

Change-Id: Ic10e561cccee5259673c76ad679029c68641615f
Reviewed-on: https://go-review.googlesource.com/c/dl/+/206537
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/gotip/main.go b/gotip/main.go
index 0423482..bad0210 100644
--- a/gotip/main.go
+++ b/gotip/main.go
@@ -18,6 +18,7 @@
 	"errors"
 	"fmt"
 	"log"
+	"net/http"
 	"os"
 	"os/exec"
 	"os/user"
@@ -26,6 +27,10 @@
 	"strings"
 )
 
+func init() {
+	http.DefaultTransport = &userAgentTransport{http.DefaultTransport}
+}
+
 func main() {
 	log.SetFlags(0)
 
@@ -51,6 +56,11 @@
 	cmd.Stdin = os.Stdin
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
+	newPath := filepath.Join(root, "bin")
+	if p := os.Getenv("PATH"); p != "" {
+		newPath += string(filepath.ListSeparator) + p
+	}
+	cmd.Env = dedupEnv(caseInsensitiveEnv, append(os.Environ(), "GOROOT="+root, "PATH="+newPath))
 	if err := cmd.Run(); err != nil {
 		if _, ok := err.(*exec.ExitError); ok {
 			// TODO: return the same exit status maybe.
@@ -105,7 +115,7 @@
 		return fmt.Errorf("failed to cleanup git repository: %v", err)
 	}
 
-	cmd := exec.Command(filepath.Join(root, "src", make()))
+	cmd := exec.Command(filepath.Join(root, "src", makeScript()))
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
 	cmd.Dir = filepath.Join(root, "src")
@@ -124,7 +134,7 @@
 	return nil
 }
 
-func make() string {
+func makeScript() string {
 	switch runtime.GOOS {
 	case "plan9":
 		return "make.rc"
@@ -135,6 +145,8 @@
 	}
 }
 
+const caseInsensitiveEnv = runtime.GOOS == "windows"
+
 func exe() string {
 	if runtime.GOOS == "windows" {
 		return ".exe"
@@ -173,3 +185,46 @@
 		return "", errors.New("can't find user home directory; $HOME is empty")
 	}
 }
+
+type userAgentTransport struct {
+	rt http.RoundTripper
+}
+
+func (uat userAgentTransport) RoundTrip(r *http.Request) (*http.Response, error) {
+	r.Header.Set("User-Agent", "golang-x-build-version/devel")
+	return uat.rt.RoundTrip(r)
+}
+
+// dedupEnv returns a copy of env with any duplicates removed, in favor of
+// later values.
+// Items are expected to be on the normal environment "key=value" form.
+// If caseInsensitive is true, the case of keys is ignored.
+//
+// This function is unnecessary when the binary is
+// built with Go 1.9+, but keep it around for now until Go 1.8
+// is no longer seen in the wild in common distros.
+//
+// This is copied verbatim from golang.org/x/build/envutil.Dedup at CL 10301
+// (commit a91ae26).
+func dedupEnv(caseInsensitive bool, env []string) []string {
+	out := make([]string, 0, len(env))
+	saw := map[string]int{} // to index in the array
+	for _, kv := range env {
+		eq := strings.Index(kv, "=")
+		if eq < 1 {
+			out = append(out, kv)
+			continue
+		}
+		k := kv[:eq]
+		if caseInsensitive {
+			k = strings.ToLower(k)
+		}
+		if dupIdx, isDup := saw[k]; isDup {
+			out[dupIdx] = kv
+		} else {
+			saw[k] = len(out)
+			out = append(out, kv)
+		}
+	}
+	return out
+}
diff --git a/gotip/main_test.go b/gotip/main_test.go
new file mode 100644
index 0000000..d15f103
--- /dev/null
+++ b/gotip/main_test.go
@@ -0,0 +1,35 @@
+// 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 main
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestDedupEnv(t *testing.T) {
+	tests := []struct {
+		noCase bool
+		in     []string
+		want   []string
+	}{
+		{
+			noCase: true,
+			in:     []string{"k1=v1", "k2=v2", "K1=v3"},
+			want:   []string{"K1=v3", "k2=v2"},
+		},
+		{
+			noCase: false,
+			in:     []string{"k1=v1", "K1=V2", "k1=v3"},
+			want:   []string{"k1=v3", "K1=V2"},
+		},
+	}
+	for _, tt := range tests {
+		got := dedupEnv(tt.noCase, tt.in)
+		if !reflect.DeepEqual(got, tt.want) {
+			t.Errorf("Dedup(%v, %q) = %q; want %q", tt.noCase, tt.in, got, tt.want)
+		}
+	}
+}
diff --git a/internal/version/version.go b/internal/version/version.go
index 9509e1d..a63c649 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -55,7 +55,6 @@
 	cmd.Stdin = os.Stdin
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
-
 	newPath := filepath.Join(root, "bin")
 	if p := os.Getenv("PATH"); p != "" {
 		newPath += string(filepath.ListSeparator) + p