gopkg.in/zumata/godep.v14@v14.0.0-20151008182512-99082d62f381/update.go (about)

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