github.com/elubow/godep@v0.0.0-20140525002653-983ff9241cea/update.go (about)

     1  package main
     2  
     3  import (
     4  	"errors"
     5  	"log"
     6  	"os"
     7  	"path/filepath"
     8  	"regexp"
     9  	"strings"
    10  )
    11  
    12  var cmdUpdate = &Command{
    13  	Usage: "update [packages]",
    14  	Short: "use different revision of selected packages",
    15  	Long: `
    16  Update changes the named dependency packages to use the
    17  revision of each currently installed in GOPATH. New code will
    18  be copied into Godeps and the new revision will be written to
    19  the manifest.
    20  
    21  For more about specifying packages, see 'go help packages'.
    22  `,
    23  	Run: runUpdate,
    24  }
    25  
    26  func runUpdate(cmd *Command, args []string) {
    27  	err := update(args)
    28  	if err != nil {
    29  		log.Fatalln(err)
    30  	}
    31  }
    32  
    33  func update(args []string) error {
    34  	if len(args) == 0 {
    35  		args = []string{"."}
    36  	}
    37  	var g Godeps
    38  	manifest := filepath.Join("Godeps", "Godeps.json")
    39  	err := ReadGodeps(manifest, &g)
    40  	if os.IsNotExist(err) {
    41  		manifest = "Godeps"
    42  		err = ReadGodeps(manifest, &g)
    43  	}
    44  	if err != nil {
    45  		return err
    46  	}
    47  	for _, arg := range args {
    48  		any := markMatches(arg, g.Deps)
    49  		if !any {
    50  			log.Println("not in manifest:", arg)
    51  		}
    52  	}
    53  	deps, err := LoadVCSAndUpdate(g.Deps)
    54  	if err != nil {
    55  		return err
    56  	}
    57  	if len(deps) == 0 {
    58  		return errors.New("no packages can be updated")
    59  	}
    60  	f, err := os.Create(manifest)
    61  	if err != nil {
    62  		return err
    63  	}
    64  	_, err = g.WriteTo(f)
    65  	if err != nil {
    66  		return err
    67  	}
    68  	err = f.Close()
    69  	if err != nil {
    70  		return err
    71  	}
    72  	if manifest != "Godeps" {
    73  		srcdir := filepath.FromSlash("Godeps/_workspace/src")
    74  		copySrc(srcdir, deps)
    75  	}
    76  	return nil
    77  }
    78  
    79  // markMatches marks each entry in deps with an import path that
    80  // matches pat. It returns whether any matches occurred.
    81  func markMatches(pat string, deps []Dependency) (matched bool) {
    82  	f := matchPattern(pat)
    83  	for i, dep := range deps {
    84  		if f(dep.ImportPath) {
    85  			deps[i].matched = true
    86  			matched = true
    87  		}
    88  	}
    89  	return matched
    90  }
    91  
    92  // matchPattern(pattern)(name) reports whether
    93  // name matches pattern.  Pattern is a limited glob
    94  // pattern in which '...' means 'any string' and there
    95  // is no other special syntax.
    96  // Taken from $GOROOT/src/cmd/go/main.go.
    97  func matchPattern(pattern string) func(name string) bool {
    98  	re := regexp.QuoteMeta(pattern)
    99  	re = strings.Replace(re, `\.\.\.`, `.*`, -1)
   100  	// Special case: foo/... matches foo too.
   101  	if strings.HasSuffix(re, `/.*`) {
   102  		re = re[:len(re)-len(`/.*`)] + `(/.*)?`
   103  	}
   104  	reg := regexp.MustCompile(`^` + re + `$`)
   105  	return func(name string) bool {
   106  		return reg.MatchString(name)
   107  	}
   108  }
   109  
   110  func LoadVCSAndUpdate(deps []Dependency) ([]Dependency, error) {
   111  	var err1 error
   112  	var paths []string
   113  	for _, dep := range deps {
   114  		paths = append(paths, dep.ImportPath)
   115  	}
   116  	ps, err := LoadPackages(paths...)
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  	noupdate := make(map[string]bool) // repo roots
   121  	var candidates []*Dependency
   122  	var tocopy []Dependency
   123  	for i := range deps {
   124  		dep := &deps[i]
   125  		for _, pkg := range ps {
   126  			if dep.ImportPath == pkg.ImportPath {
   127  				dep.pkg = pkg
   128  				break
   129  			}
   130  		}
   131  		if dep.pkg == nil {
   132  			log.Println(dep.ImportPath + ": error listing package")
   133  			err1 = errors.New("error loading dependencies")
   134  			continue
   135  		}
   136  		if dep.pkg.Error.Err != "" {
   137  			log.Println(dep.pkg.Error.Err)
   138  			err1 = errors.New("error loading dependencies")
   139  			continue
   140  		}
   141  		vcs, reporoot, err := VCSFromDir(dep.pkg.Dir, filepath.Join(dep.pkg.Root, "src"))
   142  		if err != nil {
   143  			log.Println(err)
   144  			err1 = errors.New("error loading dependencies")
   145  			continue
   146  		}
   147  		dep.dir = dep.pkg.Dir
   148  		dep.ws = dep.pkg.Root
   149  		dep.root = filepath.ToSlash(reporoot)
   150  		dep.vcs = vcs
   151  		if dep.matched {
   152  			candidates = append(candidates, dep)
   153  		} else {
   154  			noupdate[dep.root] = true
   155  		}
   156  	}
   157  	if err1 != nil {
   158  		return nil, err1
   159  	}
   160  
   161  	for _, dep := range candidates {
   162  		dep.dir = dep.pkg.Dir
   163  		dep.ws = dep.pkg.Root
   164  		if noupdate[dep.root] {
   165  			continue
   166  		}
   167  		id, err := dep.vcs.identify(dep.pkg.Dir)
   168  		if err != nil {
   169  			log.Println(err)
   170  			err1 = errors.New("error loading dependencies")
   171  			continue
   172  		}
   173  		if dep.vcs.isDirty(dep.pkg.Dir, id) {
   174  			log.Println("dirty working tree:", dep.pkg.Dir)
   175  			err1 = errors.New("error loading dependencies")
   176  			break
   177  		}
   178  		dep.Rev = id
   179  		dep.Comment = dep.vcs.describe(dep.pkg.Dir, id)
   180  		tocopy = append(tocopy, *dep)
   181  	}
   182  	if err1 != nil {
   183  		return nil, err1
   184  	}
   185  	return tocopy, nil
   186  }