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