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 }