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