github.com/golang-haiku/go-1.4.3@v0.0.0-20190609233734-1f5ae41cc308/src/cmd/api/run.go (about)

     1  // Copyright 2013 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build ignore
     6  
     7  // The run program is invoked via "go run" from src/run.bash or
     8  // src/run.bat conditionally builds and runs the cmd/api tool.
     9  //
    10  // TODO(bradfitz): the "conditional" condition is always true.
    11  // We should only do this if the user has the hg codereview extension
    12  // enabled and verifies that the go.tools subrepo is checked out with
    13  // a suitably recently version. In prep for the cmd/api rewrite.
    14  package main
    15  
    16  import (
    17  	"fmt"
    18  	"log"
    19  	"net/http"
    20  	"os"
    21  	"os/exec"
    22  	"os/user"
    23  	"path/filepath"
    24  	"runtime"
    25  	"strings"
    26  )
    27  
    28  // goToolsVersion is the hg revision of the go.tools subrepo we need
    29  // to build cmd/api.  This only needs to be updated whenever a go/types
    30  // bug fix is needed by the cmd/api tool.
    31  const goToolsVersion = "6698ca2900e2"
    32  
    33  var goroot string
    34  
    35  func main() {
    36  	// Go 1.4 will never have new API, and the code below has bit-rotted.
    37  	fmt.Println("Skipping cmd/api checks")
    38  	return
    39  
    40  	log.SetFlags(0)
    41  	goroot = os.Getenv("GOROOT") // should be set by run.{bash,bat}
    42  	if goroot == "" {
    43  		log.Fatal("No $GOROOT set.")
    44  	}
    45  	_, err := exec.LookPath("hg")
    46  	if err != nil {
    47  		fmt.Println("Skipping cmd/api checks; hg not available")
    48  		return
    49  	}
    50  
    51  	gopath := prepGoPath()
    52  
    53  	cmd := exec.Command("go", "install", "--tags=api_tool", "cmd/api")
    54  	cmd.Env = append(filterOut(os.Environ(), "GOARCH", "GOPATH"), "GOPATH="+gopath)
    55  	out, err := cmd.CombinedOutput()
    56  	if err != nil {
    57  		log.Fatalf("Error installing cmd/api: %v\n%s", err, out)
    58  	}
    59  
    60  	out, err = exec.Command("go", "tool", "api",
    61  		"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4"),
    62  		"-next", file("next"),
    63  		"-except", file("except")).CombinedOutput()
    64  	if err != nil {
    65  		log.Fatalf("Error running API checker: %v\n%s", err, out)
    66  	}
    67  	fmt.Print(string(out))
    68  }
    69  
    70  // filterOut returns a copy of the src environment without environment
    71  // variables from remove.
    72  // TODO: delete when issue 6201 is fixed.
    73  func filterOut(src []string, remove ...string) (out []string) {
    74  S:
    75  	for _, s := range src {
    76  		for _, r := range remove {
    77  			if strings.HasPrefix(s, r) && strings.HasPrefix(s, r+"=") {
    78  				continue S
    79  			}
    80  		}
    81  		out = append(out, s)
    82  	}
    83  	return
    84  }
    85  
    86  // file expands s to $GOROOT/api/s.txt.
    87  // If there are more than 1, they're comma-separated.
    88  func file(s ...string) string {
    89  	if len(s) > 1 {
    90  		return file(s[0]) + "," + file(s[1:]...)
    91  	}
    92  	return filepath.Join(goroot, "api", s[0]+".txt")
    93  }
    94  
    95  // prepGoPath returns a GOPATH for the "go" tool to compile the API tool with.
    96  // It tries to re-use a go.tools checkout from a previous run if possible,
    97  // else it hg clones it.
    98  func prepGoPath() string {
    99  	const tempBase = "go.tools.TMP"
   100  
   101  	username := ""
   102  	u, err := user.Current()
   103  	if err == nil {
   104  		username = u.Username
   105  	} else {
   106  		username = os.Getenv("USER")
   107  		if username == "" {
   108  			username = "nobody"
   109  		}
   110  	}
   111  
   112  	// The GOPATH we'll return
   113  	gopath := filepath.Join(os.TempDir(), "gopath-api-"+cleanUsername(username)+"-"+cleanUsername(strings.Fields(runtime.Version())[0]), goToolsVersion)
   114  
   115  	// cloneDir is where we run "hg clone".
   116  	cloneDir := filepath.Join(gopath, "src", "code.google.com", "p")
   117  
   118  	// The dir we clone into. We only atomically rename it to finalDir on
   119  	// clone success.
   120  	tmpDir := filepath.Join(cloneDir, tempBase)
   121  
   122  	// finalDir is where the checkout will live once it's complete.
   123  	finalDir := filepath.Join(cloneDir, "go.tools")
   124  
   125  	if goToolsCheckoutGood(finalDir) {
   126  		return gopath
   127  	}
   128  	os.RemoveAll(finalDir) // in case it's there but corrupt
   129  	os.RemoveAll(tmpDir)   // in case of aborted hg clone before
   130  
   131  	if err := os.MkdirAll(cloneDir, 0700); err != nil {
   132  		log.Fatal(err)
   133  	}
   134  	cmd := exec.Command("hg",
   135  		"clone", "--rev="+goToolsVersion,
   136  		"https://code.google.com/p/go.tools",
   137  		tempBase)
   138  	cmd.Dir = cloneDir
   139  	out, err := cmd.CombinedOutput()
   140  	if err != nil {
   141  		if _, err := http.Head("http://ip.appspot.com/"); err != nil {
   142  			log.Printf("# Skipping API check; network appears to be unavailable")
   143  			os.Exit(0)
   144  		}
   145  		log.Fatalf("Error running hg clone on go.tools: %v\n%s", err, out)
   146  	}
   147  	if err := os.Rename(tmpDir, finalDir); err != nil {
   148  		log.Fatal(err)
   149  	}
   150  	return gopath
   151  }
   152  
   153  func cleanUsername(n string) string {
   154  	b := make([]rune, len(n))
   155  	for i, r := range n {
   156  		if r == '\\' || r == '/' || r == ':' {
   157  			b[i] = '_'
   158  		} else {
   159  			b[i] = r
   160  		}
   161  	}
   162  	return string(b)
   163  }
   164  
   165  func goToolsCheckoutGood(dir string) bool {
   166  	if _, err := os.Stat(dir); err != nil {
   167  		return false
   168  	}
   169  
   170  	cmd := exec.Command("hg", "id", "--id")
   171  	cmd.Dir = dir
   172  	out, err := cmd.Output()
   173  	if err != nil {
   174  		return false
   175  	}
   176  	id := strings.TrimSpace(string(out))
   177  	if id != goToolsVersion {
   178  		return false
   179  	}
   180  
   181  	cmd = exec.Command("hg", "status")
   182  	cmd.Dir = dir
   183  	out, err = cmd.Output()
   184  	if err != nil || len(out) > 0 {
   185  		return false
   186  	}
   187  
   188  	return true
   189  }