gopkg.in/tools/godep.v51@v51.0.0-20160121191931-64044a295f54/restore.go (about) 1 package main 2 3 import ( 4 "errors" 5 "go/build" 6 "log" 7 "os" 8 "path/filepath" 9 10 "github.com/tools/godep/Godeps/_workspace/src/golang.org/x/tools/go/vcs" 11 ) 12 13 var cmdRestore = &Command{ 14 Name: "restore", 15 Short: "check out listed dependency versions in GOPATH", 16 Long: ` 17 Restore checks out the Godeps-specified version of each package in GOPATH. 18 19 `, 20 Run: runRestore, 21 } 22 23 // Three phases: 24 // 1. Download all deps 25 // 2. Restore all deps (checkout the recorded rev) 26 // 3. Attempt to load all deps as a simple consistency check 27 func runRestore(cmd *Command, args []string) { 28 if len(build.Default.GOPATH) == 0 { 29 log.Println("Error restore requires GOPATH but it is empty.") 30 os.Exit(1) 31 } 32 33 var hadError bool 34 checkErr := func(s string) { 35 if hadError { 36 log.Println(s) 37 os.Exit(1) 38 } 39 } 40 41 g, err := loadDefaultGodepsFile() 42 if err != nil { 43 log.Fatalln(err) 44 } 45 for i, dep := range g.Deps { 46 verboseln("Downloading dependency (if needed):", dep.ImportPath) 47 err := download(&dep) 48 if err != nil { 49 log.Printf("error downloading dep (%s): %s\n", dep.ImportPath, err) 50 hadError = true 51 } 52 g.Deps[i] = dep 53 } 54 checkErr("Error downloading some deps. Aborting restore and check.") 55 for _, dep := range g.Deps { 56 verboseln("Restoring dependency (if needed):", dep.ImportPath) 57 err := restore(dep) 58 if err != nil { 59 log.Printf("error restoring dep (%s): %s\n", dep.ImportPath, err) 60 hadError = true 61 } 62 } 63 checkErr("Error restoring some deps. Aborting check.") 64 for _, dep := range g.Deps { 65 verboseln("Checking dependency:", dep.ImportPath) 66 _, err := LoadPackages(dep.ImportPath) 67 if err != nil { 68 log.Printf("Dep (%s) restored, but was unable to load it with error:\n\t%s\n", dep.ImportPath, err) 69 if me, ok := err.(errorMissingDep); ok { 70 log.Println("\tThis may be because the dependencies were saved with an older version of godep (< v33).") 71 log.Printf("\tTry `go get %s`. Then `godep save` to update deps.\n", me.i) 72 } 73 hadError = true 74 } 75 } 76 checkErr("Error checking some deps.") 77 } 78 79 var downloaded = make(map[string]bool) 80 81 // download downloads the given dependency. 82 // 2 Passes: 1) go get -d <pkg>, 2) git pull (if necessary) 83 func download(dep *Dependency) error { 84 85 rr, err := vcs.RepoRootForImportPath(dep.ImportPath, debug) 86 if err != nil { 87 debugln("Error determining repo root for", dep.ImportPath) 88 return err 89 } 90 ppln("rr", rr) 91 92 dep.vcs = cmd[rr.VCS] 93 94 // try to find an existing directory in the GOPATHs 95 for _, gp := range filepath.SplitList(build.Default.GOPATH) { 96 t := filepath.Join(gp, "src", rr.Root) 97 fi, err := os.Stat(t) 98 if err != nil { 99 continue 100 } 101 if fi.IsDir() { 102 dep.root = t 103 break 104 } 105 } 106 107 // If none found, just pick the first GOPATH entry (AFAICT that's what go get does) 108 if dep.root == "" { 109 dep.root = filepath.Join(filepath.SplitList(build.Default.GOPATH)[0], "src", rr.Root) 110 } 111 ppln("dep", dep) 112 113 if downloaded[rr.Repo] { 114 verboseln("Skipping already downloaded repo", rr.Repo) 115 return nil 116 } 117 118 fi, err := os.Stat(dep.root) 119 if err != nil { 120 if os.IsNotExist(err) { 121 if err := os.MkdirAll(filepath.Dir(dep.root), os.ModePerm); err != nil { 122 debugln("Error creating base dir of", dep.root) 123 return err 124 } 125 err := rr.VCS.CreateAtRev(dep.root, rr.Repo, dep.Rev) 126 debugln("CreatedAtRev", dep.root, rr.Repo, dep.Rev) 127 if err != nil { 128 debugln("CreateAtRev error", err) 129 return err 130 } 131 downloaded[rr.Repo] = true 132 return nil 133 } 134 debugln("Error checking repo root for", dep.ImportPath, "at", dep.root, ":", err) 135 return err 136 } 137 138 if !fi.IsDir() { 139 return errors.New("repo root src dir exists, but isn't a directory for " + dep.ImportPath + " at " + dep.root) 140 } 141 142 if !dep.vcs.exists(dep.root, dep.Rev) { 143 debugln("Updating existing", dep.root) 144 dep.vcs.vcs.Download(dep.root) 145 downloaded[rr.Repo] = true 146 } 147 148 debugln("Nothing to download") 149 return nil 150 } 151 152 var restored = make(map[string]string) // dep.root -> dep.Rev 153 154 // restore checks out the given revision. 155 func restore(dep Dependency) error { 156 rev, ok := restored[dep.root] 157 debugln(rev) 158 debugln(ok) 159 debugln(dep.root) 160 if ok { 161 if rev != dep.Rev { 162 return errors.New("Wanted to restore rev " + dep.Rev + ", already restored rev " + rev + " for another package in the repo") 163 } 164 verboseln("Skipping already restored repo") 165 return nil 166 } 167 168 debugln("Restoring:", dep.ImportPath, dep.Rev) 169 pkg, err := build.Import(dep.ImportPath, ".", build.FindOnly) 170 if err != nil { 171 // This should never happen 172 debugln("Error finding package "+dep.ImportPath+" on restore:", err) 173 return err 174 } 175 err = dep.vcs.RevSync(pkg.Dir, dep.Rev) 176 if err == nil { 177 restored[dep.root] = dep.Rev 178 } 179 return err 180 }