github.com/matthewbelisle-wf/godep@v0.0.0-20140716191328-dba190f14fc8/go.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "strings" 10 ) 11 12 var spool = filepath.Join(os.TempDir(), "godep") 13 14 var cmdGo = &Command{ 15 Usage: "go command [arguments]", 16 Short: "run the go tool in a sandbox", 17 Long: ` 18 Go runs the go tool in a temporary GOPATH sandbox 19 with the dependencies listed in file Godeps. 20 21 Any go tool command can run this way, but "godep go get" 22 is unnecessary and has been disabled. Instead, use 23 "godep go install". 24 `, 25 Run: runGo, 26 } 27 28 // Set up a sandbox and run the go tool. The sandbox is built 29 // out of specific checked-out revisions of repos. We keep repos 30 // and revs materialized on disk under the assumption that disk 31 // space is cheap and plentiful, and writing files is slow. 32 // Everything is kept in the spool directory. 33 func runGo(cmd *Command, args []string) { 34 gopath := prepareGopath() 35 if s := os.Getenv("GOPATH"); s != "" { 36 gopath += string(os.PathListSeparator) + os.Getenv("GOPATH") 37 } 38 if len(args) > 0 && args[0] == "get" { 39 log.Printf("invalid subcommand: %q", "go get") 40 fmt.Fprintln(os.Stderr, "Use 'godep go install' instead.") 41 fmt.Fprintln(os.Stderr, "Run 'godep help go' for usage.") 42 os.Exit(2) 43 } 44 c := exec.Command("go", args...) 45 c.Env = append(envNoGopath(), "GOPATH="+gopath) 46 c.Stdin = os.Stdin 47 c.Stdout = os.Stdout 48 c.Stderr = os.Stderr 49 err := c.Run() 50 if err != nil { 51 log.Fatalln("go", err) 52 } 53 } 54 55 // prepareGopath reads dependency information from the filesystem 56 // entry name, fetches any necessary code, and returns a gopath 57 // causing the specified dependencies to be used. 58 func prepareGopath() (gopath string) { 59 dir, isDir := findGodeps() 60 if dir == "" { 61 log.Fatalln("No Godeps found (or in any parent directory)") 62 } 63 if isDir { 64 return filepath.Join(dir, "Godeps", "_workspace") 65 } 66 g, err := ReadAndLoadGodeps(filepath.Join(dir, "Godeps")) 67 if err != nil { 68 log.Fatalln(err) 69 } 70 gopath, err = sandboxAll(g.Deps) 71 if err != nil { 72 log.Fatalln(err) 73 } 74 return gopath 75 } 76 77 // findGodeps looks for a directory entry "Godeps" in the 78 // current directory or any parent, and returns the containing 79 // directory and whether the entry itself is a directory. 80 // If Godeps can't be found, findGodeps returns "". 81 // For any other error, it exits the program. 82 func findGodeps() (dir string, isDir bool) { 83 wd, err := os.Getwd() 84 if err != nil { 85 log.Fatalln(err) 86 } 87 return findInParents(wd, "Godeps") 88 } 89 90 // findInParents returns the path to the directory containing name 91 // in dir or any ancestor, and whether name itself is a directory. 92 // If name cannot be found, findInParents returns the empty string. 93 func findInParents(dir, name string) (container string, isDir bool) { 94 for { 95 fi, err := os.Stat(filepath.Join(dir, name)) 96 if os.IsNotExist(err) && dir == "/" { 97 return "", false 98 } 99 if os.IsNotExist(err) { 100 dir = filepath.Dir(dir) 101 continue 102 } 103 if err != nil { 104 log.Fatalln(err) 105 } 106 return dir, fi.IsDir() 107 } 108 } 109 110 func envNoGopath() (a []string) { 111 for _, s := range os.Environ() { 112 if !strings.HasPrefix(s, "GOPATH=") { 113 a = append(a, s) 114 } 115 } 116 return a 117 } 118 119 // sandboxAll ensures that the commits in deps are available 120 // on disk, and returns a GOPATH string that will cause them 121 // to be used. 122 func sandboxAll(a []Dependency) (gopath string, err error) { 123 var path []string 124 for _, dep := range a { 125 dir, err := sandbox(dep) 126 if err != nil { 127 return "", err 128 } 129 path = append(path, dir) 130 } 131 return strings.Join(path, ":"), nil 132 } 133 134 // sandbox ensures that commit d is available on disk, 135 // and returns a GOPATH string that will cause it to be used. 136 func sandbox(d Dependency) (gopath string, err error) { 137 if !exists(d.RepoPath()) { 138 if err = d.CreateRepo("fast", "main"); err != nil { 139 return "", fmt.Errorf("create repo: %s", err) 140 } 141 } 142 err = d.checkout() 143 if err != nil && d.FastRemotePath() != "" { 144 err = d.fetchAndCheckout("fast") 145 } 146 if err != nil { 147 err = d.fetchAndCheckout("main") 148 } 149 if err != nil { 150 return "", err 151 } 152 return d.Gopath(), nil 153 }