mirror of
https://github.com/kevin-DL/revel-cmd.git
synced 2026-01-11 18:54:31 +00:00
Revel tool enhancements
* run Command will choose CWD if no additional arguments are supplied * Added Revel version check, compatible lists are in model/version
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"GOLANG": {
|
||||
"ABC":[25, 35, 50, 70],
|
||||
"BLOCK_NESTING":[5, 6, 7, 8],
|
||||
"CYCLO":[20, 30, 45, 60],
|
||||
"TOO_MANY_IVARS": [15, 18, 20, 25],
|
||||
"ABC":[25, 35, 50, 70],
|
||||
"BLOCK_NESTING":[7, 9, 11, 13],
|
||||
"CYCLO":[20, 30, 45, 60],
|
||||
"TOO_MANY_IVARS": [20, 25, 40, 45],
|
||||
"TOO_MANY_FUNCTIONS": [20, 30, 40, 50],
|
||||
"TOTAL_COMPLEXITY": [150, 250, 400, 500],
|
||||
"LOC": [50, 75, 90, 120]
|
||||
"LOC": [100, 175, 250, 320],
|
||||
"TOTAL_LOC": [300, 400, 500, 600]
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,22 @@
|
||||
package model
|
||||
|
||||
// The constants
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/revel/cmd"
|
||||
"github.com/revel/cmd/logger"
|
||||
"github.com/revel/cmd/utils"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The constants
|
||||
const (
|
||||
NEW COMMAND = iota + 1
|
||||
RUN
|
||||
@@ -28,17 +33,19 @@ type (
|
||||
|
||||
// The Command config for the line input
|
||||
CommandConfig struct {
|
||||
Index COMMAND // The index
|
||||
Verbose []bool `short:"v" long:"debug" description:"If set the logger is set to verbose"` // True if debug is active
|
||||
HistoricMode bool `long:"historic-run-mode" description:"If set the runmode is passed a string not json"` // True if debug is active
|
||||
ImportPath string // The import path (relative to a GOPATH)
|
||||
GoPath string // The GoPath
|
||||
GoCmd string // The full path to the go executable
|
||||
SrcRoot string // The source root
|
||||
AppPath string // The application path (absolute)
|
||||
AppName string // The application name
|
||||
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"`
|
||||
Index COMMAND // The index
|
||||
Verbose []bool `short:"v" long:"debug" description:"If set the logger is set to verbose"` // True if debug is active
|
||||
FrameworkVersion *Version // The framework version
|
||||
CommandVersion *Version // The command version
|
||||
HistoricMode bool `long:"historic-run-mode" description:"If set the runmode is passed a string not json"` // True if debug is active
|
||||
ImportPath string // The import path (relative to a GOPATH)
|
||||
GoPath string // The GoPath
|
||||
GoCmd string // The full path to the go executable
|
||||
SrcRoot string // The source root
|
||||
AppPath string // The application path (absolute)
|
||||
AppName string // The application name
|
||||
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"`
|
||||
// The new command
|
||||
New struct {
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"`
|
||||
@@ -57,7 +64,7 @@ type (
|
||||
Run struct {
|
||||
ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"`
|
||||
Mode string `short:"m" long:"run-mode" description:"The mode to run the application in"`
|
||||
Port int `short:"p" long:"port" default:"-1" description:"The port to listen" `
|
||||
Port int `short:"p" long:"port" default:"-1" description:"The port to listen" `
|
||||
NoProxy bool `short:"n" long:"no-proxy" description:"True if proxy server should not be started. This will only update the main and routes files on change"`
|
||||
} `command:"run"`
|
||||
// The package command
|
||||
@@ -138,6 +145,16 @@ func (c *CommandConfig) UpdateImportPath() bool {
|
||||
|
||||
c.ImportPath = importPath
|
||||
utils.Logger.Info("Returned import path", "path", importPath, "buildpath", build.Default.GOPATH)
|
||||
if required && c.Index != NEW {
|
||||
if err := c.SetVersions(); err != nil {
|
||||
utils.Logger.Panic("Failed to fetch revel versions", "error", err)
|
||||
}
|
||||
if err:=c.FrameworkVersion.CompatibleFramework(c);err!=nil {
|
||||
utils.Logger.Fatal("Compatibility Error", "message", err,
|
||||
"Revel framework version", c.FrameworkVersion.String(), "Revel tool version", c.CommandVersion.String())
|
||||
}
|
||||
utils.Logger.Info("Revel versions", "revel-tool", c.CommandVersion.String(), "Revel Framework", c.FrameworkVersion.String())
|
||||
}
|
||||
return (len(importPath) > 0 || !required)
|
||||
}
|
||||
|
||||
@@ -185,7 +202,7 @@ func (c *CommandConfig) InitPackageResolver() {
|
||||
getCmd = exec.Command(depPath, "ensure", "-add", pkgName)
|
||||
} else {
|
||||
utils.Logger.Info("No vendor folder detected, not using dependency manager to import package", "package", pkgName)
|
||||
getCmd = exec.Command(c.GoCmd, "get", pkgName)
|
||||
getCmd = exec.Command(c.GoCmd, "get", "-u", pkgName)
|
||||
}
|
||||
|
||||
utils.CmdInit(getCmd, c.AppPath)
|
||||
@@ -237,7 +254,7 @@ func (c *CommandConfig) InitGoPaths() {
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.SrcRoot)==0 && len(bestpath) > 0 {
|
||||
if len(c.SrcRoot) == 0 && len(bestpath) > 0 {
|
||||
c.SrcRoot = bestpath
|
||||
}
|
||||
utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath)
|
||||
@@ -256,3 +273,48 @@ func (c *CommandConfig) InitGoPaths() {
|
||||
c.AppPath = filepath.Join(c.SrcRoot, filepath.FromSlash(c.ImportPath))
|
||||
utils.Logger.Info("Set application path", "path", c.AppPath)
|
||||
}
|
||||
|
||||
// Sets the versions on the command config
|
||||
func (c *CommandConfig) SetVersions() (err error) {
|
||||
c.CommandVersion, _ = ParseVersion(cmd.Version)
|
||||
_, revelPath, err := utils.FindSrcPaths(c.ImportPath, RevelImportPath, c.PackageResolver)
|
||||
if err == nil {
|
||||
utils.Logger.Info("Fullpath to revel", "dir", revelPath)
|
||||
fset := token.NewFileSet() // positions are relative to fset
|
||||
|
||||
versionData, err := ioutil.ReadFile(filepath.Join(revelPath, RevelImportPath, "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.
|
||||
f, err := parser.ParseFile(fset, "", versionData, parser.ParseComments)
|
||||
if err != nil {
|
||||
return utils.NewBuildError("Failed to parse Revel version error:", "error", err)
|
||||
}
|
||||
|
||||
// Print the imports from the file's AST.
|
||||
for _, s := range f.Decls {
|
||||
genDecl, ok := s.(*ast.GenDecl)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if genDecl.Tok != token.CONST {
|
||||
continue
|
||||
}
|
||||
for _, a := range genDecl.Specs {
|
||||
spec := a.(*ast.ValueSpec)
|
||||
r := spec.Values[0].(*ast.BasicLit)
|
||||
if spec.Names[0].Name == "Version" {
|
||||
c.FrameworkVersion, err = ParseVersion(strings.Replace(r.Value, `"`, ``, -1))
|
||||
if err != nil {
|
||||
utils.Logger.Errorf("Failed to parse version")
|
||||
} else {
|
||||
utils.Logger.Info("Parsed revel version", "version", c.FrameworkVersion.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@ import (
|
||||
func TestEventHandler(t *testing.T) {
|
||||
counter := 0
|
||||
newListener := func(typeOf revel.Event, value interface{}) (responseOf revel.EventResponse) {
|
||||
if typeOf == revel.REVEL_FAILURE {
|
||||
if typeOf == revel.ENGINE_SHUTDOWN_REQUEST {
|
||||
counter++
|
||||
}
|
||||
return
|
||||
}
|
||||
// Attach the same handlder twice so we expect to see the response twice as well
|
||||
// Attach the same handler twice so we expect to see the response twice as well
|
||||
revel.AddInitEventHandler(newListener)
|
||||
revel.AddInitEventHandler(newListener)
|
||||
revel.RaiseEvent(revel.REVEL_AFTER_MODULES_LOADED, nil)
|
||||
revel.RaiseEvent(revel.REVEL_FAILURE, nil)
|
||||
revel.StopServer(1)
|
||||
assert.Equal(t, counter, 2, "Expected event handler to have been called")
|
||||
}
|
||||
|
||||
|
||||
110
model/version.go
Normal file
110
model/version.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Version struct {
|
||||
Prefix string
|
||||
Major int
|
||||
Minor int
|
||||
Maintenance int
|
||||
Suffix string
|
||||
}
|
||||
|
||||
// The compatibility list
|
||||
var frameworkCompatibleList = [][]string{
|
||||
{"0.0.0", "0.20.0"}, // minimum Revel version to use with this version of the tool
|
||||
{"0.19.99", "0.30.0"}, // Compatible with Framework V 0.19.99 - 0.30.0
|
||||
}
|
||||
|
||||
// Parses a version like v1.2.3a or 1.2
|
||||
var versionRegExp = regexp.MustCompile(`([^\d]*)?([0-9]*)\.([0-9]*)(\.([0-9]*))?(.*)`)
|
||||
|
||||
// Parse the version and return it as a Version object
|
||||
func ParseVersion(version string) (v *Version, err error) {
|
||||
|
||||
parsedResult := versionRegExp.FindAllStringSubmatch(version, -1)
|
||||
if len(parsedResult) != 1 {
|
||||
err = errors.Errorf("Invalid version %s", version)
|
||||
return
|
||||
}
|
||||
if len(parsedResult[0]) != 7 {
|
||||
err = errors.Errorf("Invalid version %s", version)
|
||||
return
|
||||
}
|
||||
v = &Version{}
|
||||
v.Prefix = parsedResult[0][1]
|
||||
v.Major = v.intOrZero(parsedResult[0][2])
|
||||
v.Minor = v.intOrZero(parsedResult[0][3])
|
||||
v.Maintenance = v.intOrZero(parsedResult[0][5])
|
||||
v.Suffix = parsedResult[0][6]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Returns 0 or an int value for the string, errors are returned as 0
|
||||
func (v *Version) intOrZero(input string) (value int) {
|
||||
if input != "" {
|
||||
value, _ = strconv.Atoi(input)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// Returns true if this major revision is compatible
|
||||
func (v *Version) CompatibleFramework(c *CommandConfig) error {
|
||||
for i, rv := range frameworkCompatibleList {
|
||||
start, _ := ParseVersion(rv[0])
|
||||
end, _ := ParseVersion(rv[1])
|
||||
if !v.Newer(start) || v.Newer(end) {
|
||||
continue
|
||||
}
|
||||
// Framework is older then 0.20, turn on historic mode
|
||||
if i == 0 {
|
||||
c.HistoricMode = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return errors.New("Unknown versions - do a 'go get -u github.com/revel/cmd/revel github.com/revel/modules github.com/revel/revel'")
|
||||
}
|
||||
|
||||
// Returns true if this major revision is newer then the passed in
|
||||
func (v *Version) MajorNewer(o *Version) bool {
|
||||
if v.Major != o.Major {
|
||||
return v.Major > o.Major
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns true if this major or major and minor revision is newer then the value passed in
|
||||
func (v *Version) MinorNewer(o *Version) bool {
|
||||
if v.Major != o.Major {
|
||||
return v.Major > o.Major
|
||||
}
|
||||
if v.Minor != o.Minor {
|
||||
return v.Minor > o.Minor
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns true if the version is newer then the current on
|
||||
func (v *Version) Newer(o *Version) bool {
|
||||
if v.Major != o.Major {
|
||||
return v.Major > o.Major
|
||||
}
|
||||
if v.Minor != o.Minor {
|
||||
return v.Minor > o.Minor
|
||||
}
|
||||
if v.Maintenance != o.Maintenance {
|
||||
return v.Maintenance > o.Maintenance
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Convert the version to a string
|
||||
func (v *Version) String() string {
|
||||
return fmt.Sprintf("%s%d.%d.%d%s", v.Prefix, v.Major, v.Minor, v.Maintenance, v.Suffix)
|
||||
}
|
||||
33
model/version_test.go
Normal file
33
model/version_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package model_test
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
"github.com/revel/cmd/model"
|
||||
)
|
||||
|
||||
var versionTests = [][]string{
|
||||
{"v0.20.0-dev", "v0.20.0-dev"},
|
||||
{"v0.20-dev", "v0.20.0-dev"},
|
||||
{"v0.20.", "v0.20.0"},
|
||||
{"2.0", "2.0.0"},
|
||||
}
|
||||
// Test that the event handler can be attached and it dispatches the event received
|
||||
func TestVersion(t *testing.T) {
|
||||
for _, v:= range versionTests {
|
||||
p,e:=model.ParseVersion(v[0])
|
||||
assert.Nil(t,e,"Should have parsed %s",v)
|
||||
assert.Equal(t,p.String(),v[1], "Should be equal %s==%s",p.String(),v)
|
||||
}
|
||||
}
|
||||
|
||||
// test the ranges
|
||||
func TestVersionRange(t *testing.T) {
|
||||
a,_ := model.ParseVersion("0.1.2")
|
||||
b,_ := model.ParseVersion("0.2.1")
|
||||
c,_ := model.ParseVersion("1.0.1")
|
||||
assert.True(t, b.MinorNewer(a), "B is newer then A")
|
||||
assert.False(t, b.MajorNewer(a), "B is not major newer then A")
|
||||
assert.False(t, b.MajorNewer(c), "B is not major newer then A")
|
||||
assert.True(t, c.MajorNewer(b), "C is major newer then b")
|
||||
}
|
||||
12
revel/new.go
12
revel/new.go
@@ -119,6 +119,8 @@ func newApp(c *model.CommandConfig) (err error) {
|
||||
if err = setApplicationPath(c); err != nil {
|
||||
return err
|
||||
}
|
||||
// At this point the versions can be set
|
||||
c.SetVersions()
|
||||
|
||||
// checking and setting skeleton
|
||||
if err=setSkeletonPath(c);err!=nil {
|
||||
@@ -189,16 +191,6 @@ func setApplicationPath(c *model.CommandConfig) (err error) {
|
||||
|
||||
c.AppName = filepath.Base(c.AppPath)
|
||||
|
||||
//if c.BasePath == "." {
|
||||
// // we need to remove the a single '.' when
|
||||
// // the app is in the $GOROOT/src directory
|
||||
// c.BasePath = ""
|
||||
//} else {
|
||||
// // we need to append a '/' when the app is
|
||||
// // is a subdirectory such as $GOROOT/src/path/to/revelapp
|
||||
// c.BasePath += "/"
|
||||
//}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/revel/cmd/model"
|
||||
"github.com/revel/cmd/utils"
|
||||
"go/build"
|
||||
"os"
|
||||
)
|
||||
|
||||
var cmdRun = &Command{
|
||||
@@ -108,7 +109,8 @@ func updateRunConfig(c *model.CommandConfig, args []string) bool {
|
||||
c.Run.Mode = args[0]
|
||||
}
|
||||
case 0:
|
||||
return false
|
||||
// Attempt to set the import path to the current working director.
|
||||
c.Run.ImportPath,_ = os.Getwd()
|
||||
}
|
||||
c.Index = model.RUN
|
||||
return true
|
||||
|
||||
@@ -118,3 +118,4 @@ func versionApp(c *model.CommandConfig) (err error) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user