gopkg.in/tools/godep.v61@v61.0.0-20160406162537-35ee059b4e6c/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  }