gopkg.in/tools/godep.v76@v76.0.0-20170110172504-88cb03c7cb62/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, rdeps, err := LoadVCSAndUpdate(g.Deps)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	if len(deps) == 0 {
   102  		return errorNoPackagesUpdatable
   103  	}
   104  	g.addOrUpdateDeps(deps)
   105  	g.removeDeps(rdeps)
   106  	if _, err = g.save(); err != nil {
   107  		return err
   108  	}
   109  
   110  	srcdir := relativeVendorTarget(VendorExperiment)
   111  	if err := removeSrc(filepath.FromSlash(strings.Trim(sep, "/")), rdeps); err != nil {
   112  		return err
   113  	}
   114  	copySrc(srcdir, deps)
   115  
   116  	ok, err := needRewrite(g.Packages)
   117  	if err != nil {
   118  		return err
   119  	}
   120  	var rewritePaths []string
   121  	if ok {
   122  		for _, dep := range g.Deps {
   123  			rewritePaths = append(rewritePaths, dep.ImportPath)
   124  		}
   125  	}
   126  	return rewrite(nil, g.ImportPath, rewritePaths)
   127  }
   128  
   129  func needRewrite(importPaths []string) (bool, error) {
   130  	if len(importPaths) == 0 {
   131  		importPaths = []string{"."}
   132  	}
   133  	a, err := LoadPackages(importPaths...)
   134  	if err != nil {
   135  		return false, err
   136  	}
   137  	for _, p := range a {
   138  		for _, name := range p.allGoFiles() {
   139  			path := filepath.Join(p.Dir, name)
   140  			hasSep, err := hasRewrittenImportStatement(path)
   141  			if err != nil {
   142  				return false, err
   143  			}
   144  			if hasSep {
   145  				return true, nil
   146  			}
   147  		}
   148  	}
   149  	return false, nil
   150  }
   151  
   152  func hasRewrittenImportStatement(path string) (bool, error) {
   153  	fset := token.NewFileSet()
   154  	f, err := parser.ParseFile(fset, path, nil, 0)
   155  	if err != nil {
   156  		return false, err
   157  	}
   158  	for _, s := range f.Imports {
   159  		name, _ := strconv.Unquote(s.Path.Value)
   160  		if strings.Contains(name, sep) {
   161  			return true, nil
   162  		}
   163  	}
   164  	return false, nil
   165  }
   166  
   167  // markMatches marks each entry in deps with an import path that
   168  // matches pat. It returns whether any matches occurred.
   169  func markMatches(pat string, deps []Dependency) (matched bool) {
   170  	f := matchPattern(pat)
   171  	for i, dep := range deps {
   172  		if f(dep.ImportPath) {
   173  			deps[i].matched = true
   174  			matched = true
   175  		}
   176  	}
   177  	return matched
   178  }
   179  
   180  func fillDeps(deps []Dependency) ([]Dependency, error) {
   181  	for i := range deps {
   182  		if deps[i].pkg != nil {
   183  			continue
   184  		}
   185  		ps, err := LoadPackages(deps[i].ImportPath)
   186  		if err != nil {
   187  			if _, ok := err.(errPackageNotFound); ok {
   188  				deps[i].missing = true
   189  				continue
   190  			}
   191  			return nil, err
   192  		}
   193  		if len(ps) > 1 {
   194  			panic("More than one package found for " + deps[i].ImportPath)
   195  		}
   196  		p := ps[0]
   197  		deps[i].pkg = p
   198  		deps[i].dir = p.Dir
   199  		deps[i].ws = p.Root
   200  
   201  		vcs, reporoot, err := VCSFromDir(p.Dir, filepath.Join(p.Root, "src"))
   202  		if err != nil {
   203  			return nil, errorLoadingDeps
   204  		}
   205  		deps[i].root = filepath.ToSlash(reporoot)
   206  		deps[i].vcs = vcs
   207  	}
   208  
   209  	return deps, nil
   210  }
   211  
   212  // LoadVCSAndUpdate loads and updates a set of dependencies.
   213  func LoadVCSAndUpdate(deps []Dependency) ([]Dependency, []Dependency, error) {
   214  	var err1 error
   215  
   216  	deps, err := fillDeps(deps)
   217  	if err != nil {
   218  		return nil, nil, err
   219  	}
   220  
   221  	repoMask := make(map[string]bool)
   222  	for i := range deps {
   223  		if !deps[i].matched {
   224  			repoMask[deps[i].root] = true
   225  		}
   226  	}
   227  
   228  	// Determine if we need any new packages because of new transitive imports
   229  	for _, dep := range deps {
   230  		if !dep.matched || dep.missing {
   231  			continue
   232  		}
   233  		for _, dp := range dep.pkg.Dependencies {
   234  			if dp.Goroot {
   235  				continue
   236  			}
   237  			var have bool
   238  			for _, d := range deps {
   239  				if d.ImportPath == dp.ImportPath {
   240  					have = true
   241  					break
   242  				}
   243  			}
   244  			if !have {
   245  				deps = append(deps, Dependency{ImportPath: dp.ImportPath, matched: true})
   246  			}
   247  		}
   248  	}
   249  
   250  	deps, err = fillDeps(deps)
   251  	if err != nil {
   252  		return nil, nil, err
   253  	}
   254  
   255  	var toUpdate, toRemove []Dependency
   256  	for _, d := range deps {
   257  		if !d.matched || repoMask[d.root] {
   258  			continue
   259  		}
   260  		if d.missing {
   261  			toRemove = append(toRemove, d)
   262  			continue
   263  		}
   264  		toUpdate = append(toUpdate, d)
   265  	}
   266  
   267  	debugln("toUpdate")
   268  	ppln(toUpdate)
   269  
   270  	var toCopy []Dependency
   271  	for _, d := range toUpdate {
   272  		id, err := d.vcs.identify(d.dir)
   273  		if err != nil {
   274  			log.Println(err)
   275  			err1 = errorLoadingDeps
   276  			continue
   277  		}
   278  		if d.vcs.isDirty(d.dir, id) {
   279  			log.Println("dirty working tree (please commit changes):", d.dir)
   280  		}
   281  		d.Rev = id
   282  		d.Comment = d.vcs.describe(d.dir, id)
   283  		toCopy = append(toCopy, d)
   284  	}
   285  	debugln("toCopy")
   286  	ppln(toCopy)
   287  
   288  	if err1 != nil {
   289  		return nil, nil, err1
   290  	}
   291  	return toCopy, toRemove, nil
   292  }