github.com/jd-ly/cmd@v1.0.10/revel/version.go (about) 1 // Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved. 2 // Revel Framework source code and usage is governed by a MIT style 3 // license that can be found in the LICENSE file. 4 5 // Copyright (c) 2012-2016 The Revel Framework Authors, All rights reserved. 6 // Revel Framework source code and usage is governed by a MIT style 7 // license that can be found in the LICENSE file. 8 9 package main 10 11 import ( 12 "fmt" 13 14 "github.com/jd-ly/cmd" 15 "github.com/jd-ly/cmd/model" 16 "github.com/jd-ly/cmd/utils" 17 "go/ast" 18 "go/parser" 19 "go/token" 20 "io/ioutil" 21 "net/http" 22 "os" 23 "os/exec" 24 "path/filepath" 25 "strings" 26 "bytes" 27 ) 28 29 type ( 30 // The version container 31 VersionCommand struct { 32 Command *model.CommandConfig // The command 33 revelVersion *model.Version // The Revel framework version 34 modulesVersion *model.Version // The Revel modules version 35 cmdVersion *model.Version // The tool version 36 } 37 ) 38 39 var cmdVersion = &Command{ 40 UsageLine: "revel version", 41 Short: "displays the Revel Framework and Go version", 42 Long: ` 43 Displays the Revel Framework and Go version. 44 45 For example: 46 47 revel version [<application path>] 48 `, 49 } 50 51 func init() { 52 v := &VersionCommand{} 53 cmdVersion.UpdateConfig = v.UpdateConfig 54 cmdVersion.RunWith = v.RunWith 55 } 56 57 // Update the version 58 func (v *VersionCommand) UpdateConfig(c *model.CommandConfig, args []string) bool { 59 if len(args) > 0 { 60 c.Version.ImportPath = args[0] 61 } 62 return true 63 } 64 65 // Displays the version of go and Revel 66 func (v *VersionCommand) RunWith(c *model.CommandConfig) (err error) { 67 utils.Logger.Info("Requesting version information", "config", c) 68 v.Command = c 69 70 // Update the versions with the local values 71 v.updateLocalVersions() 72 73 needsUpdates := true 74 versionInfo := "" 75 for x := 0; x < 2 && needsUpdates; x++ { 76 needsUpdates = false 77 versionInfo, needsUpdates = v.doRepoCheck(x == 0) 78 } 79 80 fmt.Printf("%s\n\nGo Location:%s\n\n", versionInfo, c.GoCmd) 81 cmd := exec.Command(c.GoCmd, "version") 82 cmd.Stdout = os.Stdout 83 if e := cmd.Start(); e != nil { 84 fmt.Println("Go command error ", e) 85 } else { 86 cmd.Wait() 87 } 88 89 return 90 } 91 92 // Checks the Revel repos for the latest version 93 func (v *VersionCommand) doRepoCheck(updateLibs bool) (versionInfo string, needsUpdate bool) { 94 var ( 95 title string 96 localVersion *model.Version 97 ) 98 for _, repo := range []string{"revel", "cmd", "modules"} { 99 versonFromRepo, err := v.versionFromRepo(repo, "", "version.go") 100 if err != nil { 101 utils.Logger.Info("Failed to get version from repo", "repo", repo, "error", err) 102 } 103 switch repo { 104 case "revel": 105 title, repo, localVersion = "Revel Framework", "github.com/revel/revel", v.revelVersion 106 case "cmd": 107 title, repo, localVersion = "Revel Cmd", "github.com/jd-ly/cmd/revel", v.cmdVersion 108 case "modules": 109 title, repo, localVersion = "Revel Modules", "github.com/revel/modules", v.modulesVersion 110 } 111 112 // Only do an update on the first loop, and if specified to update 113 versionInfo = versionInfo + v.outputVersion(title, repo, localVersion, versonFromRepo) 114 } 115 return 116 } 117 118 // Checks for updates if needed 119 func (v *VersionCommand) doUpdate(title, repo string, local, remote *model.Version) { 120 utils.Logger.Info("Updating package", "package", title, "repo", repo) 121 fmt.Println("Attempting to update package", title) 122 if err := v.Command.PackageResolver(repo); err != nil { 123 utils.Logger.Error("Unable to update repo", "repo", repo, "error", err) 124 } else if repo == "github.com/jd-ly/cmd/revel" { 125 // One extra step required here to run the install for the command 126 utils.Logger.Fatal("Revel command tool was updated, you must manually run the following command before continuing\ngo install github.com/jd-ly/cmd/revel") 127 } 128 return 129 } 130 131 // Prints out the local and remote versions, calls update if needed 132 func (v *VersionCommand) outputVersion(title, repo string, local, remote *model.Version) (output string) { 133 buffer := &bytes.Buffer{} 134 remoteVersion := "Unknown" 135 if remote != nil { 136 remoteVersion = remote.VersionString() 137 } 138 localVersion := "Unknown" 139 if local != nil { 140 localVersion = local.VersionString() 141 } 142 143 fmt.Fprintf(buffer, "%s\t:\t%s\t(%s remote master branch)\n", title, localVersion, remoteVersion) 144 return buffer.String() 145 } 146 147 // Returns the version from the repository 148 func (v *VersionCommand) versionFromRepo(repoName, branchName, fileName string) (version *model.Version, err error) { 149 if branchName == "" { 150 branchName = "master" 151 } 152 // Try to download the version of file from the repo, just use an http connection to retrieve the source 153 // Assuming that the repo is github 154 fullurl := "https://raw.githubusercontent.com/revel/" + repoName + "/" + branchName + "/" + fileName 155 resp, err := http.Get(fullurl) 156 if err != nil { 157 return 158 } 159 defer resp.Body.Close() 160 body, err := ioutil.ReadAll(resp.Body) 161 if err != nil { 162 return 163 } 164 utils.Logger.Info("Got version file", "from", fullurl, "content", string(body)) 165 166 return v.versionFromBytes(body) 167 } 168 169 // Returns version information from a file called version on the gopath 170 func (v *VersionCommand) compareAndUpdateVersion(remoteVersion *model.Version, localVersion *model.Version) (err error) { 171 return 172 } 173 func (v *VersionCommand) versionFromFilepath(sourcePath string) (version *model.Version, err error) { 174 utils.Logger.Info("Fullpath to revel", "dir", sourcePath) 175 176 sourceStream, err := ioutil.ReadFile(filepath.Join(sourcePath, "version.go")) 177 if err != nil { 178 return 179 } 180 return v.versionFromBytes(sourceStream) 181 } 182 183 // Returns version information from a file called version on the gopath 184 func (v *VersionCommand) versionFromBytes(sourceStream []byte) (version *model.Version, err error) { 185 fset := token.NewFileSet() // positions are relative to fset 186 187 // Parse src but stop after processing the imports. 188 f, err := parser.ParseFile(fset, "", sourceStream, parser.ParseComments) 189 if err != nil { 190 err = utils.NewBuildError("Failed to parse Revel version error:", "error", err) 191 return 192 } 193 version = &model.Version{} 194 195 // Print the imports from the file's AST. 196 for _, s := range f.Decls { 197 genDecl, ok := s.(*ast.GenDecl) 198 if !ok { 199 continue 200 } 201 if genDecl.Tok != token.CONST { 202 continue 203 } 204 for _, a := range genDecl.Specs { 205 spec := a.(*ast.ValueSpec) 206 r := spec.Values[0].(*ast.BasicLit) 207 switch spec.Names[0].Name { 208 case "Version": 209 version.ParseVersion(strings.Replace(r.Value, `"`, "", -1)) 210 case "BuildDate": 211 version.BuildDate = r.Value 212 case "MinimumGoVersion": 213 version.MinGoVersion = r.Value 214 } 215 } 216 } 217 return 218 } 219 220 // Fetch the local version of revel from the file system 221 func (v *VersionCommand) updateLocalVersions() { 222 v.cmdVersion = &model.Version{} 223 v.cmdVersion.ParseVersion(cmd.Version) 224 v.cmdVersion.BuildDate = cmd.BuildDate 225 v.cmdVersion.MinGoVersion = cmd.MinimumGoVersion 226 227 if v.Command.Version.ImportPath=="" { 228 return 229 } 230 231 pathMap, err := utils.FindSrcPaths(v.Command.AppPath, []string{model.RevelImportPath, model.RevelModulesImportPath}, v.Command.PackageResolver) 232 if err != nil { 233 utils.Logger.Warn("Unable to extract version information from Revel library", "path", pathMap[model.RevelImportPath], "error", err) 234 return 235 } 236 utils.Logger.Info("Fullpath to revel modules", "dir", pathMap[model.RevelImportPath]) 237 v.revelVersion, err = v.versionFromFilepath(pathMap[model.RevelImportPath]) 238 if err != nil { 239 utils.Logger.Warn("Unable to extract version information from Revel", "error,err") 240 } 241 242 v.modulesVersion, err = v.versionFromFilepath(pathMap[model.RevelModulesImportPath]) 243 if err != nil { 244 utils.Logger.Warn("Unable to extract version information from Revel Modules", "path", pathMap[model.RevelModulesImportPath], "error", err) 245 } 246 247 return 248 }