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