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