Patchset for 21

Added Version -u to update the checked out libaraies
Enhanced new skeleton toto support http https and git schemas when cloning the skeleton repo.
Enhanced version command to fetch server version from master branch
Enhanced version command to update local repository if a new version exists on the server
This commit is contained in:
NotZippy
2018-10-29 12:04:19 -07:00
parent 1e7b5322f5
commit ee53d2f399
7 changed files with 256 additions and 94 deletions

View File

@@ -1,6 +1,7 @@
{ {
"GOLANG": { "GOLANG": {
"ABC":[25, 35, 50, 70], "ABC":[25, 35, 50, 70],
"ARITY":[5,6,7,8],
"BLOCK_NESTING":[7, 9, 11, 13], "BLOCK_NESTING":[7, 9, 11, 13],
"CYCLO":[20, 30, 45, 60], "CYCLO":[20, 30, 45, 60],
"TOO_MANY_IVARS": [20, 25, 40, 45], "TOO_MANY_IVARS": [20, 25, 40, 45],

View File

@@ -44,6 +44,7 @@ type (
SrcRoot string // The source root SrcRoot string // The source root
AppPath string // The application path (absolute) AppPath string // The application path (absolute)
AppName string // The application name AppName string // The application name
Vendored bool // True if the application is vendored
PackageResolver func(pkgName string) error // a packge resolver for the config PackageResolver func(pkgName string) error // a packge resolver for the config
BuildFlags []string `short:"X" long:"build-flags" description:"These flags will be used when building the application. May be specified multiple times, only applicable for Build, Run, Package, Test commands"` BuildFlags []string `short:"X" long:"build-flags" description:"These flags will be used when building the application. May be specified multiple times, only applicable for Build, Run, Package, Test commands"`
// The new command // The new command
@@ -87,6 +88,7 @@ type (
// The version command // The version command
Version struct { Version struct {
ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"` ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"`
Update bool `short:"u" long:"Update the framework and modules" required:"false"`
} `command:"version"` } `command:"version"`
} }
) )
@@ -124,7 +126,6 @@ func (c *CommandConfig) UpdateImportPath() error {
} }
// For an absolute path // For an absolute path
currentPath, _ = filepath.Abs(importPath) currentPath, _ = filepath.Abs(importPath)
} }
if err == nil { if err == nil {
@@ -136,8 +137,11 @@ func (c *CommandConfig) UpdateImportPath() error {
if len(importPath) > 4 && strings.ToLower(importPath[0:4]) == "src/" { if len(importPath) > 4 && strings.ToLower(importPath[0:4]) == "src/" {
importPath = importPath[4:] importPath = importPath[4:]
} else if importPath == "src" { } else if importPath == "src" {
if c.Index != VERSION {
return fmt.Errorf("Invlaid import path, working dir is in GOPATH root") return fmt.Errorf("Invlaid import path, working dir is in GOPATH root")
} }
importPath = ""
}
utils.Logger.Info("Updated import path", "path", importPath) utils.Logger.Info("Updated import path", "path", importPath)
} }
} }
@@ -167,18 +171,19 @@ func (c *CommandConfig) UpdateImportPath() error {
// Used to initialize the package resolver // Used to initialize the package resolver
func (c *CommandConfig) InitPackageResolver() { func (c *CommandConfig) InitPackageResolver() {
useVendor := utils.DirExists(filepath.Join(c.AppPath, "vendor")) c.Vendored = utils.DirExists(filepath.Join(c.AppPath, "vendor"))
if c.Index == NEW && c.New.Vendored { if c.Index == NEW && c.New.Vendored {
useVendor = true c.Vendored = true
} }
utils.Logger.Info("InitPackageResolver", "useVendor", useVendor, "path", c.AppPath)
utils.Logger.Info("InitPackageResolver", "useVendor", c.Vendored, "path", c.AppPath)
var ( var (
depPath string depPath string
err error err error
) )
if useVendor { if c.Vendored {
utils.Logger.Info("Vendor folder detected, scanning for deps in path") utils.Logger.Info("Vendor folder detected, scanning for deps in path")
depPath, err = exec.LookPath("dep") depPath, err = exec.LookPath("dep")
if err != nil { if err != nil {
@@ -194,8 +199,8 @@ func (c *CommandConfig) InitPackageResolver() {
//useVendor := utils.DirExists(filepath.Join(c.AppPath, "vendor")) //useVendor := utils.DirExists(filepath.Join(c.AppPath, "vendor"))
var getCmd *exec.Cmd var getCmd *exec.Cmd
utils.Logger.Info("Request for package ", "package", pkgName, "use vendor", useVendor) utils.Logger.Info("Request for package ", "package", pkgName, "use vendor", c.Vendored)
if useVendor { if c.Vendored {
utils.Logger.Info("Using dependency manager to import package", "package", pkgName) utils.Logger.Info("Using dependency manager to import package", "package", pkgName)
if depPath == "" { if depPath == "" {
@@ -206,7 +211,15 @@ func (c *CommandConfig) InitPackageResolver() {
utils.Logger.Error("Missing package", "package", pkgName) utils.Logger.Error("Missing package", "package", pkgName)
return fmt.Errorf("Missing package %s", pkgName) return fmt.Errorf("Missing package %s", pkgName)
} }
// Check to see if the package exists locally
_, err := build.Import(pkgName, c.AppPath, build.FindOnly)
if err != nil {
getCmd = exec.Command(depPath, "ensure", "-add", pkgName) getCmd = exec.Command(depPath, "ensure", "-add", pkgName)
} else {
getCmd = exec.Command(depPath, "ensure", "-update", pkgName)
}
} else { } else {
utils.Logger.Info("No vendor folder detected, not using dependency manager to import package", "package", pkgName) utils.Logger.Info("No vendor folder detected, not using dependency manager to import package", "package", pkgName)
getCmd = exec.Command(c.GoCmd, "get", "-u", pkgName) getCmd = exec.Command(c.GoCmd, "get", "-u", pkgName)
@@ -225,6 +238,7 @@ func (c *CommandConfig) InitPackageResolver() {
// lookup and set Go related variables // lookup and set Go related variables
func (c *CommandConfig) InitGoPaths() { func (c *CommandConfig) InitGoPaths() {
utils.Logger.Info("InitGoPaths")
// lookup go path // lookup go path
c.GoPath = build.Default.GOPATH c.GoPath = build.Default.GOPATH
if c.GoPath == "" { if c.GoPath == "" {

View File

@@ -92,6 +92,7 @@ func (w *WrappedRevelCallback) PackageResolver(pkgName string) error {
// RevelImportPath Revel framework import path // RevelImportPath Revel framework import path
var RevelImportPath = "github.com/revel/revel" var RevelImportPath = "github.com/revel/revel"
var RevelModulesImportPath = "github.com/revel/modules"
// This function returns a container object describing the revel application // This function returns a container object describing the revel application
// eventually this type of function will replace the global variables. // eventually this type of function will replace the global variables.
@@ -226,7 +227,7 @@ func (rp *RevelContainer) loadModules(callback RevelCallback) (err error) {
modulePath, err := rp.ResolveImportPath(moduleImportPath) modulePath, err := rp.ResolveImportPath(moduleImportPath)
if err != nil { if err != nil {
utils.Logger.Info("Missing module ", "module", moduleImportPath, "error",err) utils.Logger.Info("Missing module ", "module_import_path", moduleImportPath, "error",err)
callback.PackageResolver(moduleImportPath) callback.PackageResolver(moduleImportPath)
modulePath, err = rp.ResolveImportPath(moduleImportPath) modulePath, err = rp.ResolveImportPath(moduleImportPath)
if err != nil { if err != nil {

View File

@@ -13,6 +13,8 @@ type Version struct {
Minor int Minor int
Maintenance int Maintenance int
Suffix string Suffix string
BuildDate string
MinGoVersion string
} }
// The compatibility list // The compatibility list
@@ -27,6 +29,13 @@ var versionRegExp = regexp.MustCompile(`([^\d]*)?([0-9]*)\.([0-9]*)(\.([0-9]*))?
// Parse the version and return it as a Version object // Parse the version and return it as a Version object
func ParseVersion(version string) (v *Version, err error) { func ParseVersion(version string) (v *Version, err error) {
v = &Version{}
return v, v.ParseVersion(version)
}
// Parse the version and return it as a Version object
func (v *Version)ParseVersion(version string) (err error) {
parsedResult := versionRegExp.FindAllStringSubmatch(version, -1) parsedResult := versionRegExp.FindAllStringSubmatch(version, -1)
if len(parsedResult) != 1 { if len(parsedResult) != 1 {
err = errors.Errorf("Invalid version %s", version) err = errors.Errorf("Invalid version %s", version)
@@ -36,7 +45,7 @@ func ParseVersion(version string) (v *Version, err error) {
err = errors.Errorf("Invalid version %s", version) err = errors.Errorf("Invalid version %s", version)
return return
} }
v = &Version{}
v.Prefix = parsedResult[0][1] v.Prefix = parsedResult[0][1]
v.Major = v.intOrZero(parsedResult[0][2]) v.Major = v.intOrZero(parsedResult[0][2])
v.Minor = v.intOrZero(parsedResult[0][3]) v.Minor = v.intOrZero(parsedResult[0][3])
@@ -45,7 +54,6 @@ func ParseVersion(version string) (v *Version, err error) {
return return
} }
// Returns 0 or an int value for the string, errors are returned as 0 // Returns 0 or an int value for the string, errors are returned as 0
func (v *Version) intOrZero(input string) (value int) { func (v *Version) intOrZero(input string) (value int) {
if input != "" { if input != "" {
@@ -105,6 +113,12 @@ func (v *Version) Newer(o *Version) bool {
} }
// Convert the version to a string // Convert the version to a string
func (v *Version) String() string { func (v *Version) VersionString() string {
return fmt.Sprintf("%s%d.%d.%d%s", v.Prefix, v.Major, v.Minor, v.Maintenance, v.Suffix) return fmt.Sprintf("%s%d.%d.%d%s", v.Prefix, v.Major, v.Minor, v.Maintenance, v.Suffix)
} }
// Convert the version build date and go version to a string
func (v *Version) String() string {
return fmt.Sprintf("Version: %s%d.%d.%d%s\nBuild Date: %s\n Minimium Go Version: %s",
v.Prefix, v.Major, v.Minor, v.Maintenance, v.Suffix, v.BuildDate, v.MinGoVersion)
}

View File

@@ -16,9 +16,6 @@ import (
"github.com/revel/cmd/model" "github.com/revel/cmd/model"
"github.com/revel/cmd/utils" "github.com/revel/cmd/utils"
"net/url" "net/url"
"github.com/kr/pty"
"io"
"bytes"
) )
var cmdNew = &Command{ var cmdNew = &Command{
@@ -117,16 +114,11 @@ func newApp(c *model.CommandConfig) (err error) {
getCmd := exec.Command("dep", "ensure", "-v") getCmd := exec.Command("dep", "ensure", "-v")
utils.CmdInit(getCmd, c.AppPath) utils.CmdInit(getCmd, c.AppPath)
f, err := pty.Start(getCmd);
stdout := new(bytes.Buffer)
io.Copy(io.MultiWriter(stdout, os.Stdout), f)
if err = getCmd.Wait(); err != nil {
}
utils.Logger.Info("Exec:", "args", getCmd.Args, "env", getCmd.Env, "workingdir",getCmd.Dir) utils.Logger.Info("Exec:", "args", getCmd.Args, "env", getCmd.Env, "workingdir",getCmd.Dir)
// getOutput, err := getCmd.CombinedOutput() getOutput, err := getCmd.CombinedOutput()
if err != nil { if err != nil {
return utils.NewBuildIfError(err, stdout.String()) return utils.NewBuildIfError(err, string(getOutput))
} }
} }
@@ -207,7 +199,7 @@ func setApplicationPath(c *model.CommandConfig) (err error) {
// Set the skeleton path // Set the skeleton path
func setSkeletonPath(c *model.CommandConfig) (err error) { func setSkeletonPath(c *model.CommandConfig) (err error) {
if len(c.New.SkeletonPath) == 0 { if len(c.New.SkeletonPath) == 0 {
c.New.SkeletonPath = "git://" + RevelSkeletonsImportPath + ":basic/bootstrap4" c.New.SkeletonPath = "https://" + RevelSkeletonsImportPath + ":basic/bootstrap4"
} }
// First check to see the protocol of the string // First check to see the protocol of the string
@@ -216,7 +208,7 @@ func setSkeletonPath(c *model.CommandConfig) (err error) {
utils.Logger.Info("Detected skeleton path", "path", sp) utils.Logger.Info("Detected skeleton path", "path", sp)
switch strings.ToLower(sp.Scheme) { switch strings.ToLower(sp.Scheme) {
// TODO Add support for https, http, ftp // TODO Add support for ftp, sftp, scp ??
case "" : case "" :
sp.Scheme="file" sp.Scheme="file"
fallthrough fallthrough
@@ -234,14 +226,13 @@ func setSkeletonPath(c *model.CommandConfig) (err error) {
return fmt.Errorf("Failed to find skeleton in filepath %s %s", fullpath, sp.String()) return fmt.Errorf("Failed to find skeleton in filepath %s %s", fullpath, sp.String())
} }
case "git": case "git":
fallthrough
case "http":
fallthrough
case "https":
if err := newLoadFromGit(c, sp); err != nil { if err := newLoadFromGit(c, sp); err != nil {
return err return err
} }
//case "":
//if err := newLoadFromGo(c, sp); err != nil {
// return err
//}
default: default:
utils.Logger.Fatal("Unsupported skeleton schema ", "path", c.New.SkeletonPath) utils.Logger.Fatal("Unsupported skeleton schema ", "path", c.New.SkeletonPath)

View File

@@ -10,19 +10,30 @@ package main
import ( import (
"fmt" "fmt"
"runtime"
"github.com/revel/cmd" "github.com/revel/cmd"
"github.com/revel/cmd/model" "github.com/revel/cmd/model"
"github.com/revel/cmd/utils" "github.com/revel/cmd/utils"
"go/ast" "go/ast"
"go/build"
"go/parser" "go/parser"
"go/token" "go/token"
"io/ioutil" "io/ioutil"
"net/http"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strings"
"bytes"
)
type (
// The version container
VersionCommand struct {
Command *model.CommandConfig // The command
revelVersion *model.Version // The Revel framework version
modulesVersion *model.Version // The Revel modules version
cmdVersion *model.Version // The tool version
}
) )
var cmdVersion = &Command{ var cmdVersion = &Command{
@@ -38,12 +49,13 @@ For example:
} }
func init() { func init() {
cmdVersion.RunWith = versionApp v := &VersionCommand{}
cmdVersion.UpdateConfig = updateVersionConfig cmdVersion.UpdateConfig = v.UpdateConfig
cmdVersion.RunWith = v.RunWith
} }
// Update the version // Update the version
func updateVersionConfig(c *model.CommandConfig, args []string) bool { func (v *VersionCommand) UpdateConfig(c *model.CommandConfig, args []string) bool {
if len(args) > 0 { if len(args) > 0 {
c.Version.ImportPath = args[0] c.Version.ImportPath = args[0]
} }
@@ -51,35 +63,144 @@ func updateVersionConfig(c *model.CommandConfig, args []string) bool {
} }
// Displays the version of go and Revel // Displays the version of go and Revel
func versionApp(c *model.CommandConfig) (err error) { func (v *VersionCommand) RunWith(c *model.CommandConfig) (err error) {
utils.Logger.Info("Requesting version information", "config", c)
v.Command = c
var revelPath, appPath string // Update the versions with the local values
v.updateLocalVersions()
needsUpdates := true
appPath, revelPath, err = utils.FindSrcPaths(c.ImportPath, model.RevelImportPath, c.PackageResolver) versionInfo := ""
if err != nil { for x := 0; x < 2 && needsUpdates; x++ {
return utils.NewBuildError("Failed to import "+c.ImportPath+" with error:", "error", err) needsUpdates = false
versionInfo, needsUpdates = v.doRepoCheck(x==0)
} }
revelPath = revelPath + model.RevelImportPath
fmt.Println("\nRevel Framework",revelPath, appPath ) fmt.Println(versionInfo)
if err != nil { cmd := exec.Command(c.GoCmd, "version")
utils.Logger.Info("Failed to find Revel in GOPATH with error:", "error", err, "gopath", build.Default.GOPATH) cmd.Stdout = os.Stdout
fmt.Println("Information not available (not on GOPATH)") if e := cmd.Start(); e != nil {
fmt.Println("Go command error ", e)
} else { } else {
utils.Logger.Info("Fullpath to revel", "dir", revelPath) cmd.Wait()
}
return
}
// Checks the Revel repos for the latest version
func (v *VersionCommand) doRepoCheck(updateLibs bool) (versionInfo string, needsUpdate bool) {
var (
title string
localVersion *model.Version
)
for _, repo := range []string{"revel", "cmd", "modules"} {
versonFromRepo, err := v.versionFromRepo(repo, "", "version.go")
if err != nil {
utils.Logger.Info("Failed to get version from repo", "repo", repo, "error", err)
}
switch repo {
case "revel":
title, repo, localVersion = "Revel Framework", "github.com/revel/revel", v.revelVersion
case "cmd":
title, repo, localVersion = "Revel Cmd", "github.com/revel/cmd/revel", v.cmdVersion
case "modules":
title, repo, localVersion = "Revel Modules", "github.com/revel/modules", v.modulesVersion
}
// Only do an update on the first loop, and if specified to update
shouldUpdate := updateLibs && v.Command.Version.Update
if v.Command.Version.Update {
if localVersion == nil || (versonFromRepo != nil && versonFromRepo.Newer(localVersion)) {
needsUpdate = true
if shouldUpdate {
v.doUpdate(title, repo, localVersion, versonFromRepo)
v.updateLocalVersions()
}
}
}
versionInfo = versionInfo + v.outputVersion(title, repo, localVersion, versonFromRepo)
}
return
}
// Checks for updates if needed
func (v *VersionCommand) doUpdate(title, repo string, local, remote *model.Version) {
utils.Logger.Info("Updating package", "package", title, "repo",repo)
fmt.Println("Attempting to update package", title)
if err := v.Command.PackageResolver(repo); err != nil {
utils.Logger.Error("Unable to update repo", "repo", repo, "error", err)
} else if repo == "github.com/revel/cmd/revel" {
// One extra step required here to run the install for the command
utils.Logger.Fatal("Revel command tool was updated, you must manually run the following command before continuing\ngo install github.com/revel/cmd/revel")
}
return
}
// Prints out the local and remote versions, calls update if needed
func (v *VersionCommand) outputVersion(title, repo string, local, remote *model.Version) (output string) {
buffer := &bytes.Buffer{}
remoteVersion := "Unknown"
if remote != nil {
remoteVersion = remote.VersionString()
}
localVersion := "Unknown"
if local != nil {
localVersion = local.VersionString()
}
fmt.Fprintf(buffer, "%s\t:\t%s\t(%s remote master branch)\n", title, localVersion, remoteVersion)
return buffer.String()
}
// Returns the version from the repository
func (v *VersionCommand) versionFromRepo(repoName, branchName, fileName string) (version *model.Version, err error) {
if branchName == "" {
branchName = "master"
}
// Try to download the version of file from the repo, just use an http connection to retrieve the source
// Assuming that the repo is github
fullurl := "https://raw.githubusercontent.com/revel/" + repoName + "/" + branchName + "/" + fileName
resp, err := http.Get(fullurl)
if err != nil {
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
utils.Logger.Info("Got version file", "from", fullurl, "content", string(body))
return v.versionFromBytes(body)
}
// Returns version information from a file called version on the gopath
func (v *VersionCommand) compareAndUpdateVersion(remoteVersion *model.Version, localVersion *model.Version) (err error) {
return
}
func (v *VersionCommand) versionFromFilepath(sourcePath string) (version *model.Version, err error) {
utils.Logger.Info("Fullpath to revel", "dir", sourcePath)
sourceStream, err := ioutil.ReadFile(filepath.Join(sourcePath, "version.go"))
if err != nil {
return
}
return v.versionFromBytes(sourceStream)
}
// Returns version information from a file called version on the gopath
func (v *VersionCommand) versionFromBytes(sourceStream []byte) (version *model.Version, err error) {
fset := token.NewFileSet() // positions are relative to fset fset := token.NewFileSet() // positions are relative to fset
version, err := ioutil.ReadFile(filepath.Join(revelPath, "version.go"))
if err != nil {
utils.Logger.Error("Failed to find Revel version:", "error", err, "path", revelPath)
}
// Parse src but stop after processing the imports. // Parse src but stop after processing the imports.
f, err := parser.ParseFile(fset, "", version, parser.ParseComments) f, err := parser.ParseFile(fset, "", sourceStream, parser.ParseComments)
if err != nil { if err != nil {
return utils.NewBuildError("Failed to parse Revel version error:", "error", err) err = utils.NewBuildError("Failed to parse Revel version error:", "error", err)
return
} }
version = &model.Version{}
// Print the imports from the file's AST. // Print the imports from the file's AST.
for _, s := range f.Decls { for _, s := range f.Decls {
@@ -93,29 +214,49 @@ func versionApp(c *model.CommandConfig) (err error) {
for _, a := range genDecl.Specs { for _, a := range genDecl.Specs {
spec := a.(*ast.ValueSpec) spec := a.(*ast.ValueSpec)
r := spec.Values[0].(*ast.BasicLit) r := spec.Values[0].(*ast.BasicLit)
fmt.Printf("Revel %s = %s\n", spec.Names[0].Name, r.Value) switch spec.Names[0].Name {
case "Version":
version.ParseVersion(strings.Replace(r.Value, `"`, "", -1))
case "BuildDate":
version.BuildDate = r.Value
case "MinimumGoVersion":
version.MinGoVersion = r.Value
} }
} }
} }
fmt.Println("\nRevel Command Utility Tool") return
fmt.Println("Version", cmd.Version) }
fmt.Println("Build Date", cmd.BuildDate)
fmt.Println("Minimum Go Version", cmd.MinimumGoVersion)
fmt.Printf("Compiled By %s %s/%s\n\n", runtime.Version(), runtime.GOOS, runtime.GOARCH) // Fetch the local version of revel from the file system
// Extract the goversion detected func (v *VersionCommand) updateLocalVersions() {
if len(c.GoCmd) > 0 { v.cmdVersion = &model.Version{}
cmd := exec.Command(c.GoCmd, "version") v.cmdVersion.ParseVersion(cmd.Version)
cmd.Stdout = os.Stdout v.cmdVersion.BuildDate = cmd.BuildDate
if e := cmd.Start(); e != nil { v.cmdVersion.MinGoVersion = cmd.MinimumGoVersion
fmt.Println("Go command error ", e)
} else { var modulePath, revelPath string
cmd.Wait() _, revelPath, err := utils.FindSrcPaths(v.Command.ImportPath, model.RevelImportPath, v.Command.PackageResolver)
if err != nil {
utils.Logger.Warn("Unable to extract version information from Revel library", "error,err")
return
} }
} else { revelPath = revelPath + model.RevelImportPath
fmt.Println("Go command not found ") utils.Logger.Info("Fullpath to revel", "dir", revelPath)
v.revelVersion, err = v.versionFromFilepath(revelPath)
if err != nil {
utils.Logger.Warn("Unable to extract version information from Revel", "error,err")
}
_, modulePath, err = utils.FindSrcPaths(v.Command.ImportPath, model.RevelModulesImportPath, v.Command.PackageResolver)
if err != nil {
utils.Logger.Warn("Unable to extract version information from Revel library", "error,err")
return
}
modulePath = modulePath + model.RevelModulesImportPath
v.modulesVersion, err = v.versionFromFilepath(modulePath)
if err != nil {
utils.Logger.Warn("Unable to extract version information from Revel Modules", "error", err)
} }
return return
} }

View File

@@ -6,7 +6,7 @@ package cmd
const ( const (
// Version current Revel Command version // Version current Revel Command version
Version = "0.20.2" Version = "0.21.0-dev"
// BuildDate latest commit/release date // BuildDate latest commit/release date
BuildDate = "2018-10-02" BuildDate = "2018-10-02"