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