mirror of https://github.com/k3s-io/k3s
293 lines
5.7 KiB
Go
293 lines
5.7 KiB
Go
package main
|
|
|
|
import (
|
|
"go/parser"
|
|
"go/token"
|
|
"log"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
var cmdUpdate = &Command{
|
|
Name: "update",
|
|
Args: "[-goversion] [packages]",
|
|
Short: "update selected packages or the go version",
|
|
Long: `
|
|
Update changes the named dependency packages to use the
|
|
revision of each currently installed in GOPATH. New code will
|
|
be copied into the Godeps workspace or vendor folder and the
|
|
new revision will be written to the manifest.
|
|
|
|
If -goversion is specified, update the recorded go version.
|
|
|
|
For more about specifying packages, see 'go help packages'.
|
|
`,
|
|
Run: runUpdate,
|
|
OnlyInGOPATH: true,
|
|
}
|
|
|
|
var (
|
|
updateGoVer bool
|
|
)
|
|
|
|
func init() {
|
|
cmdUpdate.Flag.BoolVar(&saveT, "t", false, "save test files during update")
|
|
cmdUpdate.Flag.BoolVar(&updateGoVer, "goversion", false, "update the recorded go version")
|
|
}
|
|
|
|
func runUpdate(cmd *Command, args []string) {
|
|
if updateGoVer {
|
|
err := updateGoVersion()
|
|
if err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
}
|
|
if len(args) > 0 {
|
|
err := update(args)
|
|
if err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func updateGoVersion() error {
|
|
gold, err := loadDefaultGodepsFile()
|
|
if err != nil {
|
|
if !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
}
|
|
cv, err := goVersion()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
gv := gold.GoVersion
|
|
gold.GoVersion = cv
|
|
_, err = gold.save()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if gv != cv {
|
|
log.Println("Updated major go version to", cv)
|
|
}
|
|
return nil
|
|
|
|
}
|
|
|
|
func update(args []string) error {
|
|
if len(args) == 0 {
|
|
args = []string{"."}
|
|
}
|
|
g, err := loadDefaultGodepsFile()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, arg := range args {
|
|
arg := path.Clean(arg)
|
|
any := markMatches(arg, g.Deps)
|
|
if !any {
|
|
log.Println("not in manifest:", arg)
|
|
}
|
|
}
|
|
deps, rdeps, err := LoadVCSAndUpdate(g.Deps)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(deps) == 0 {
|
|
return errorNoPackagesUpdatable
|
|
}
|
|
g.addOrUpdateDeps(deps)
|
|
g.removeDeps(rdeps)
|
|
if _, err = g.save(); err != nil {
|
|
return err
|
|
}
|
|
|
|
srcdir := relativeVendorTarget(VendorExperiment)
|
|
if err := removeSrc(filepath.FromSlash(strings.Trim(sep, "/")), rdeps); err != nil {
|
|
return err
|
|
}
|
|
copySrc(srcdir, deps)
|
|
|
|
ok, err := needRewrite(g.Packages)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var rewritePaths []string
|
|
if ok {
|
|
for _, dep := range g.Deps {
|
|
rewritePaths = append(rewritePaths, dep.ImportPath)
|
|
}
|
|
}
|
|
return rewrite(nil, g.ImportPath, rewritePaths)
|
|
}
|
|
|
|
func needRewrite(importPaths []string) (bool, error) {
|
|
if len(importPaths) == 0 {
|
|
importPaths = []string{"."}
|
|
}
|
|
a, err := LoadPackages(importPaths...)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
for _, p := range a {
|
|
for _, name := range p.allGoFiles() {
|
|
path := filepath.Join(p.Dir, name)
|
|
hasSep, err := hasRewrittenImportStatement(path)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if hasSep {
|
|
return true, nil
|
|
}
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func hasRewrittenImportStatement(path string) (bool, error) {
|
|
fset := token.NewFileSet()
|
|
f, err := parser.ParseFile(fset, path, nil, 0)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
for _, s := range f.Imports {
|
|
name, _ := strconv.Unquote(s.Path.Value)
|
|
if strings.Contains(name, sep) {
|
|
return true, nil
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
// markMatches marks each entry in deps with an import path that
|
|
// matches pat. It returns whether any matches occurred.
|
|
func markMatches(pat string, deps []Dependency) (matched bool) {
|
|
f := matchPattern(pat)
|
|
for i, dep := range deps {
|
|
if f(dep.ImportPath) {
|
|
deps[i].matched = true
|
|
matched = true
|
|
}
|
|
}
|
|
return matched
|
|
}
|
|
|
|
func fillDeps(deps []Dependency) ([]Dependency, error) {
|
|
for i := range deps {
|
|
if deps[i].pkg != nil {
|
|
continue
|
|
}
|
|
ps, err := LoadPackages(deps[i].ImportPath)
|
|
if err != nil {
|
|
if _, ok := err.(errPackageNotFound); ok {
|
|
deps[i].missing = true
|
|
continue
|
|
}
|
|
return nil, err
|
|
}
|
|
if len(ps) > 1 {
|
|
panic("More than one package found for " + deps[i].ImportPath)
|
|
}
|
|
p := ps[0]
|
|
deps[i].pkg = p
|
|
deps[i].dir = p.Dir
|
|
deps[i].ws = p.Root
|
|
|
|
vcs, reporoot, err := VCSFromDir(p.Dir, filepath.Join(p.Root, "src"))
|
|
if err != nil {
|
|
return nil, errorLoadingDeps
|
|
}
|
|
deps[i].root = filepath.ToSlash(reporoot)
|
|
deps[i].vcs = vcs
|
|
}
|
|
|
|
return deps, nil
|
|
}
|
|
|
|
// LoadVCSAndUpdate loads and updates a set of dependencies.
|
|
func LoadVCSAndUpdate(deps []Dependency) ([]Dependency, []Dependency, error) {
|
|
var err1 error
|
|
|
|
deps, err := fillDeps(deps)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
repoMask := make(map[string]bool)
|
|
for i := range deps {
|
|
if !deps[i].matched {
|
|
repoMask[deps[i].root] = true
|
|
}
|
|
}
|
|
|
|
// Determine if we need any new packages because of new transitive imports
|
|
for _, dep := range deps {
|
|
if !dep.matched || dep.missing {
|
|
continue
|
|
}
|
|
for _, dp := range dep.pkg.Dependencies {
|
|
if dp.Goroot {
|
|
continue
|
|
}
|
|
var have bool
|
|
for _, d := range deps {
|
|
if d.ImportPath == dp.ImportPath {
|
|
have = true
|
|
break
|
|
}
|
|
}
|
|
if !have {
|
|
deps = append(deps, Dependency{ImportPath: dp.ImportPath, matched: true})
|
|
}
|
|
}
|
|
}
|
|
|
|
deps, err = fillDeps(deps)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var toUpdate, toRemove []Dependency
|
|
for _, d := range deps {
|
|
if !d.matched || repoMask[d.root] {
|
|
continue
|
|
}
|
|
if d.missing {
|
|
toRemove = append(toRemove, d)
|
|
continue
|
|
}
|
|
toUpdate = append(toUpdate, d)
|
|
}
|
|
|
|
debugln("toUpdate")
|
|
ppln(toUpdate)
|
|
|
|
var toCopy []Dependency
|
|
for _, d := range toUpdate {
|
|
id, err := d.vcs.identify(d.dir)
|
|
if err != nil {
|
|
log.Println(err)
|
|
err1 = errorLoadingDeps
|
|
continue
|
|
}
|
|
if d.vcs.isDirty(d.dir, id) {
|
|
log.Println("dirty working tree (please commit changes):", d.dir)
|
|
}
|
|
d.Rev = id
|
|
d.Comment = d.vcs.describe(d.dir, id)
|
|
toCopy = append(toCopy, d)
|
|
}
|
|
debugln("toCopy")
|
|
ppln(toCopy)
|
|
|
|
if err1 != nil {
|
|
return nil, nil, err1
|
|
}
|
|
return toCopy, toRemove, nil
|
|
}
|