gopkg.in/tools/godep.v41@v41.0.0-20151217180337-fe5ce707f879/update.go (about)

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