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