github.com/polvi/nsproxy@v0.0.0-20140119202807-96ac732fa7f3/third_party.go (about) 1 // +build ignore 2 3 /* 4 Copyright 2013 Brandon Philips 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 // This program builds a project and is a copy of third_party.go. See 20 // github.com/philips/third_party.go 21 // 22 // $ go run third_party.go 23 // 24 // See the README file for more details. 25 package main 26 27 import ( 28 "fmt" 29 "io" 30 "io/ioutil" 31 "log" 32 "os" 33 "os/exec" 34 "path" 35 "path/filepath" 36 "strings" 37 ) 38 39 const ( 40 DefaultThirdParty = "third_party" 41 ) 42 43 // thirdPartyDir creates a string path to the third_party directory based on 44 // the current working directory. 45 func thirdPartyDir() string { 46 root, err := os.Getwd() 47 if err != nil { 48 log.Fatalf("Failed to get the current working directory: %v", err) 49 } 50 return path.Join(root, DefaultThirdParty) 51 } 52 53 func srcDir() string { 54 return path.Join(thirdPartyDir(), "src") 55 } 56 57 // binDir creates a string path to the GOBIN directory based on the current 58 // working directory. 59 func binDir() string { 60 root, err := os.Getwd() 61 if err != nil { 62 log.Fatalf("Failed to get the current working directory: %v", err) 63 } 64 return path.Join(root, "bin") 65 } 66 67 // run execs a command like a shell script piping everything to the parent's 68 // stderr/stdout and uses the given environment. 69 func run(name string, arg ...string) *os.ProcessState { 70 cmd := exec.Command(name, arg...) 71 72 stdout, err := cmd.StdoutPipe() 73 if err != nil { 74 fmt.Fprintf(os.Stderr, err.Error()) 75 os.Exit(1) 76 } 77 stderr, err := cmd.StderrPipe() 78 if err != nil { 79 fmt.Fprintf(os.Stderr, err.Error()) 80 os.Exit(1) 81 } 82 err = cmd.Start() 83 if err != nil { 84 fmt.Fprintf(os.Stderr, err.Error()) 85 os.Exit(1) 86 } 87 go io.Copy(os.Stdout, stdout) 88 go io.Copy(os.Stderr, stderr) 89 cmd.Wait() 90 91 return cmd.ProcessState 92 } 93 94 // setupProject does the initial setup of the third_party src directory 95 // including setting up the symlink to the cwd from the src directory. 96 func setupProject(pkg string) { 97 root, err := os.Getwd() 98 if err != nil { 99 log.Fatalf("Failed to get the current working directory: %v", err) 100 } 101 102 src := path.Join(thirdPartyDir(), "src", pkg) 103 srcdir := path.Dir(src) 104 105 os.MkdirAll(srcdir, 0755) 106 107 rel, err := filepath.Rel(srcdir, root) 108 if err != nil { 109 log.Fatalf("creating relative third party path: %v", err) 110 } 111 112 err = os.Symlink(rel, src) 113 if err != nil && os.IsExist(err) == false { 114 log.Fatalf("creating project third party symlink: %v", err) 115 } 116 } 117 118 func getVc(root string) versionControl { 119 for _, v := range []string{".git", ".hg"} { 120 r := path.Join(root, v) 121 info, err := os.Stat(r) 122 123 if err != nil || !info.IsDir() { 124 continue 125 } 126 127 base := path.Base(r) 128 switch base { 129 case ".git": 130 return vcGit(r) 131 case ".hg": 132 return vcHg(r) 133 } 134 } 135 return new(vcNoop) 136 } 137 138 type versionControl interface { 139 commit() string 140 update(string) error 141 } 142 143 // Performs noops on all VC operations. 144 type vcNoop struct{} 145 146 func (v *vcNoop) commit() string { 147 return "" 148 } 149 150 func (v *vcNoop) update(dir string) error { 151 return nil 152 } 153 154 type vcHg string 155 156 // vcHg.commit returns the current HEAD commit hash for a given hg dir. 157 func (v vcHg) commit() string { 158 out, err := exec.Command("hg", "id", "-i", "-R", string(v)).Output() 159 if err != nil { 160 return "" 161 } 162 return string(out) 163 } 164 165 // vcHg.udpate updates the given hg dir to ref. 166 func (v vcHg) update(ref string) error { 167 _, err := exec.Command("hg", 168 "update", 169 "-r", ref, 170 "-R", string(v), 171 "--cwd", path.Dir(string(v)), 172 ).Output() 173 if err != nil { 174 return err 175 } 176 return nil 177 } 178 179 type vcGit string 180 181 // vcGit.commit returns the current HEAD commit hash for a given git dir. 182 func (v vcGit) commit() string { 183 out, err := exec.Command("git", "--git-dir="+string(v), "rev-parse", "HEAD").Output() 184 if err != nil { 185 return "" 186 } 187 return string(out) 188 } 189 190 // vcHg.udpate updates the given git dir to ref. 191 func (v vcGit) update(ref string) error { 192 _, err := exec.Command("git", 193 "--work-tree="+path.Dir(string(v)), 194 "--git-dir="+string(v), 195 "reset", "--hard", ref, 196 ).Output() 197 if err != nil { 198 return err 199 } 200 return nil 201 } 202 203 // commit grabs the commit id from hg or git as a string. 204 func commit(dir string) string { 205 return getVc(dir).commit() 206 } 207 208 // removeVcs removes a .git or .hg directory from the given root if it exists. 209 func removeVcs(root string) (bool, string) { 210 for _, v := range []string{".git", ".hg"} { 211 r := path.Join(root, v) 212 info, err := os.Stat(r) 213 214 if err != nil { 215 continue 216 } 217 218 // We didn't find it, next! 219 if info.IsDir() == false { 220 continue 221 } 222 223 // We found it, grab the commit and remove the directory 224 c := commit(root) 225 err = os.RemoveAll(r) 226 if err != nil { 227 log.Fatalf("removeVcs: %v", err) 228 } 229 return true, c 230 } 231 232 return false, "" 233 } 234 235 // bump takes care of grabbing a package, getting the package git hash and 236 // removing all of the version control stuff. 237 func bump(pkg, version string) { 238 tpd := thirdPartyDir() 239 240 temp, err := ioutil.TempDir(tpd, "bump") 241 if err != nil { 242 log.Fatalf("bump: %v", err) 243 } 244 defer os.RemoveAll(temp) 245 246 os.Setenv("GOPATH", temp) 247 run("go", "get", "-u", "-d", pkg) 248 249 for { 250 root := path.Join(temp, "src", pkg) // the temp installation root 251 home := path.Join(tpd, "src", pkg) // where the package will end up 252 253 if version != "" { 254 err := getVc(root).update(version) 255 if err != nil { 256 log.Fatalf("bump: %v", err) 257 } 258 } 259 260 ok, c := removeVcs(root) 261 if ok { 262 // Create the path leading up to the package 263 err := os.MkdirAll(path.Dir(home), 0755) 264 if err != nil { 265 log.Fatalf("bump: %v", err) 266 } 267 268 // Remove anything that might have been there 269 err = os.RemoveAll(home) 270 if err != nil { 271 log.Fatalf("bump: %v", err) 272 } 273 274 // Finally move the package 275 err = os.Rename(root, home) 276 if err != nil { 277 log.Fatalf("bump: %v", err) 278 } 279 280 fmt.Printf("%s %s\n", pkg, strings.TrimSpace(c)) 281 break 282 } 283 284 // Pop off and try to find this directory! 285 pkg = path.Dir(pkg) 286 if pkg == "." { 287 return 288 } 289 } 290 } 291 292 // validPkg uses go list to decide if the given path is a valid go package. 293 // This is used by the bumpAll walk to bump all of the existing packages. 294 func validPkg(pkg string) bool { 295 env := append(os.Environ(), 296 ) 297 cmd := exec.Command("go", "list", pkg) 298 cmd.Env = env 299 300 out, err := cmd.Output() 301 if err != nil { 302 return false 303 } 304 305 if pkg == strings.TrimSpace(string(out)) { 306 return true 307 } 308 309 return false 310 } 311 312 // bumpWalk walks the third_party directory and bumps all of the packages that it finds. 313 func bumpWalk(path string, info os.FileInfo, err error) error { 314 if err != nil { 315 return nil 316 } 317 318 // go packages are always directories 319 if info.IsDir() == false { 320 return nil 321 } 322 323 parts := strings.Split(path, srcDir()+"/") 324 if len(parts) == 1 { 325 return nil 326 } 327 328 pkg := parts[1] 329 330 if validPkg(pkg) == false { 331 return nil 332 } 333 334 bump(pkg, "") 335 336 return nil 337 } 338 339 func bumpAll() { 340 err := filepath.Walk(srcDir(), bumpWalk) 341 if err != nil { 342 log.Fatalf(err.Error()) 343 } 344 } 345 346 func main() { 347 log.SetFlags(0) 348 349 // third_party manages GOPATH, no one else 350 os.Setenv("GOPATH", thirdPartyDir()) 351 os.Setenv("GOBIN", binDir()) 352 353 if len(os.Args) <= 1 { 354 log.Fatalf("No command") 355 } 356 357 cmd := os.Args[1] 358 359 if cmd == "setup" && len(os.Args) > 2 { 360 setupProject(os.Args[2]) 361 return 362 } 363 364 if cmd == "bump" && len(os.Args) > 2 { 365 ref := "" 366 if len(os.Args) > 3 { 367 ref = os.Args[3] 368 } 369 370 bump(os.Args[2], ref) 371 return 372 } 373 374 if cmd == "bump-all" && len(os.Args) > 1 { 375 bumpAll() 376 return 377 } 378 379 ps := run("go", os.Args[1:]...) 380 381 if ps.Success() == false { 382 os.Exit(1) 383 } 384 }