gopkg.in/tools/godep.v38@v38.0.0-20151216225452-4154dbb67855/update.go (about)

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