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