Merge branch 'develop' into develop

This commit is contained in:
Brenden Soares
2022-04-11 20:30:05 -07:00
committed by GitHub
38 changed files with 328 additions and 146 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,3 @@
.idea/
*.iml
.temp/

21
.vscode/launch.json vendored
View File

@@ -16,12 +16,12 @@
"name": "Create new",
"type": "go",
"request": "launch",
"preLaunchTask": "Clean",
"preLaunchTask": "Clean-Test-Project",
"mode": "auto",
"program": "${workspaceRoot}/revel",
"args": ["new", "-a", "/tmp/revel/aaa"],
"args": ["new", "-v","-a", "${workspaceRoot}/.temp/revel/reveltest", "-p","revel.com/testproject"],
"env": {
"GOPATH": "/tmp/revel/GOPATH"
"GOPATH": "${workspaceRoot}/.temp/revel/GOPATH"
},
},
{
@@ -30,9 +30,20 @@
"request": "launch",
"mode": "auto",
"program": "${workspaceRoot}/revel",
"args": ["run","-v", "-a", "/tmp/revel/aaa"],
"args": ["run","-v", "-v","-a", "${workspaceRoot}/.temp/revel/reveltest"],
"env": {
"GOPATH": "/tmp/revel/GOPATH"
"GOPATH": "${workspaceRoot}/.temp/revel/GOPATH"
},
},
{
"name": "Run program Directly",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceRoot}/.temp/revel/reveltest/app/tmp/main.go",
"args": ["-port=9000","-importPath=revel.com/testproject/reveltest", "-runMode={\"mode\":\"dev\", \"specialUseFlag\":true,\"packagePathMap\":{\"github.com/revel/modules/static\":\"/home/notzippy/go/pkg/mod/github.com/revel/modules@v1.0.0/static\",\"github.com/revel/modules/testrunner\":\"/home/notzippy/go/pkg/mod/github.com/revel/modules@v1.0.0/testrunner\",\"github.com/revel/revel\":\"/home/notzippy/go/pkg/mod/github.com/revel/revel@v1.0.0\",\"revel.com/testproject/reveltest\":\"/mnt/DevSystem/Work/Workareas/revel/revel3/cmd/.temp/revel/reveltest\"}}"],
"env": {
"GOPATH": "${workspaceRoot}/.temp/revel/GOPATH"
},
}
]

1
.vscode/load.sh vendored Executable file
View File

@@ -0,0 +1 @@
http_load -rate 5 -seconds 10 load.web

2
.vscode/load.web vendored Normal file
View File

@@ -0,0 +1,2 @@
http://localhost:9000/
http://localhost:9000/miss

14
.vscode/tasks.json vendored
View File

@@ -4,9 +4,17 @@
"version": "2.0.0",
"tasks": [
{
"label": "Clean",
"label": "Clean-Test-Project",
"type": "shell",
"command": "rm -rf /tmp/revel/aaa"
}
"command": "rm -rf ${workspaceRoot}/.temp/revel/testproject"
},
{
"label": "Update Go Mod",
"type": "shell",
"options": {
"cwd": "${workspaceRoot}/.temp/revel/testproject"
},
"command": "go mod tidy && go mod edit -replace github.com/revel/revel => ../../../revel"
},
]
}

12
go.mod
View File

@@ -4,20 +4,20 @@ go 1.17
require (
github.com/agtorre/gocolorize v1.0.0
github.com/fsnotify/fsnotify v1.5.1
github.com/fsnotify/fsnotify v1.4.9
github.com/go-stack/stack v1.8.0 // indirect
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac // indirect
github.com/jessevdk/go-flags v1.4.0
github.com/mattn/go-colorable v0.1.12
github.com/mattn/go-colorable v0.1.8
github.com/myesui/uuid v1.0.0 // indirect
github.com/pkg/errors v0.9.1
github.com/revel/config v1.0.0
github.com/revel/log15 v2.11.20+incompatible
github.com/revel/revel v0.21.0
github.com/revel/revel v1.0.0
github.com/stretchr/testify v1.7.0
golang.org/x/tools v0.1.10
gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/stack.v0 v0.0.0-20141108040640-9b43fcefddd0
)
require (
github.com/BurntSushi/toml v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac // indirect

45
go.sum
View File

@@ -10,27 +10,33 @@ github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac h1:n1DqxAo4o
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/myesui/uuid v1.0.0 h1:xCBmH4l5KuvLYc5L7AS7SZg9/jKdIFubM7OVoLqaQUI=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/myesui/uuid v1.0.0/go.mod h1:2CDfNgU0LR8mIdO8vdWd8i9gWWxLlcoIGGpSNgafq84=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/revel/config v0.21.0 h1:Bw4iXLGAuD/Di2HEhPSOyDywrTlFIXUMbds91lXTtTU=
github.com/revel/config v0.21.0/go.mod h1:GT4a9px5kDGRqLizcw/md0QFErrhen76toz4qS3oIoI=
github.com/revel/config v1.0.0 h1:UAzLPQ+x9nJeP6a+H93G+AKEosg3OO2oVLBXK9oSN2U=
github.com/revel/config v1.0.0/go.mod h1:GT4a9px5kDGRqLizcw/md0QFErrhen76toz4qS3oIoI=
github.com/revel/log15 v2.11.20+incompatible h1:JkA4tbwIo/UGEMumY50zndKq816RQW3LQ0wIpRc+32U=
github.com/revel/log15 v2.11.20+incompatible/go.mod h1:l0WmLRs+IM1hBl4noJiBc2tZQiOgZyXzS1mdmFt+5Gc=
github.com/revel/modules v0.21.0/go.mod h1:UBlNmO9VGZo4j6Ptn2uC/26Iclefuic+V40jYRPBxQE=
github.com/revel/pathtree v0.0.0-20140121041023-41257a1839e9 h1:/d6kfjzjyx19ieWqMOXHSTLFuRxLOH15ZubtcAXExKw=
github.com/revel/pathtree v0.0.0-20140121041023-41257a1839e9/go.mod h1:TmlwoRLDvgRjoTe6rbsxIaka/CulzYrgfef7iNJcEWY=
github.com/revel/revel v0.21.0 h1:E6kDJmpJSDb0F8XwbyG5h4ayzpZ+8Wcw2IiPZW/2qSc=
github.com/revel/revel v0.21.0/go.mod h1:VZWJnHjpDEtuGUuZJ2NO42XryitrtwsdVaJxfDeo5yc=
github.com/revel/revel v1.0.0 h1:BsPFnKuuzXEkPtrjdjZHiDcvDmbBiBQvh7Z5c6kLb/Y=
github.com/revel/revel v1.0.0/go.mod h1:VZWJnHjpDEtuGUuZJ2NO42XryitrtwsdVaJxfDeo5yc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/twinj/uuid v1.0.0 h1:fzz7COZnDrXGTAOHGuUGYd6sG+JMq+AoE7+Jlu0przk=
github.com/twinj/uuid v1.0.0/go.mod h1:mMgcE1RHFUFqe5AfiwlINXisXfDGro23fWdPUfOMjRY=
github.com/xeonx/timeago v1.0.0-rc4 h1:9rRzv48GlJC0vm+iBpLcWAr8YbETyN9Vij+7h2ammz4=
@@ -41,24 +47,26 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 h1:5B6i6EAiSYyejWfvc5Rc9BbI3rzIsrrXfAQBWnYfn+w=
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
@@ -71,6 +79,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 h1:XNNYLJHt73EyYiCZi6+xjupS9CpvmiDgjPTAjrBlQbo=
gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/stack.v0 v0.0.0-20141108040640-9b43fcefddd0 h1:lMH45EKqD8Nf6LwoF+43YOKjOAEEHQRVgDyG8RCV4MU=

View File

@@ -6,18 +6,28 @@ package harness
import (
"bytes"
"errors"
"fmt"
"io"
"os"
"os/exec"
"sync"
"sync/atomic"
"time"
"github.com/revel/cmd/model"
"github.com/revel/cmd/utils"
)
// Error is used for constant errors.
type Error string
// Error implements the error interface.
func (e Error) Error() string {
return string(e)
}
const ErrTimedOut Error = "app timed out"
// App contains the configuration for running a Revel app. (Not for the app itself)
// Its only purpose is constructing the command to execute.
type App struct {
@@ -64,6 +74,7 @@ func NewAppCmd(binPath string, port int, runMode string, paths *model.RevelConta
func (cmd AppCmd) Start(c *model.CommandConfig) error {
listeningWriter := &startupListeningWriter{os.Stdout, make(chan bool), c, &bytes.Buffer{}}
cmd.Stdout = listeningWriter
cmd.Stderr = listeningWriter
utils.CmdInit(cmd.Cmd, !c.Vendored, c.AppPath)
utils.Logger.Info("Exec app:", "path", cmd.Path, "args", cmd.Args, "dir", cmd.Dir, "env", cmd.Env)
if err := cmd.Cmd.Start(); err != nil {
@@ -74,15 +85,17 @@ func (cmd AppCmd) Start(c *model.CommandConfig) error {
case exitState := <-cmd.waitChan():
fmt.Println("Startup failure view previous messages, \n Proxy is listening :", c.Run.Port)
err := utils.NewError("", "Revel Run Error", "starting your application there was an exception. See terminal output, "+exitState, "")
atomic.SwapInt32(&startupError, 1)
// TODO pretiffy command line output
// err.MetaError = listeningWriter.getLastOutput()
err.Stack = listeningWriter.buffer.String()
return err
case <-time.After(60 * time.Second):
println("Revel proxy is listening, point your browser to :", c.Run.Port)
utils.Logger.Error("Killing revel server process did not respond after wait timeout.", "processid", cmd.Process.Pid)
cmd.Kill()
return errors.New("revel/harness: app timed out")
return fmt.Errorf("revel/harness: %w", ErrTimedOut)
case <-listeningWriter.notifyReady:
println("Revel proxy is listening, point your browser to :", c.Run.Port)

View File

@@ -26,6 +26,7 @@ import (
var importErrorPattern = regexp.MustCompile("cannot find package \"([^\"]+)\"")
var importErrorPattern2 = regexp.MustCompile("no required module provides package ([^;]+)+")
var addPackagePattern = regexp.MustCompile(`to add:\n\tgo get (.*)\n`)
type ByString []*model.TypeInfo
@@ -214,6 +215,10 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err
if matches == nil {
matches = importErrorPattern2.FindAllStringSubmatch(stOutput, -1)
}
if matches == nil {
matches = addPackagePattern.FindAllStringSubmatch(stOutput, -1)
}
utils.Logger.Info("Build failed checking for missing imports", "message", stOutput, "missing_imports", len(matches))
if matches == nil {
utils.Logger.Info("Build failed no missing imports", "message", stOutput)

View File

@@ -16,6 +16,7 @@ package harness
import (
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"go/build"
"html/template"
@@ -42,6 +43,8 @@ var (
doNotWatch = []string{"tmp", "views", "routes"}
lastRequestHadError int32
startupError int32
startupErrorText error
)
// Harness reverse proxies requests to the application server.
@@ -69,6 +72,7 @@ func (h *Harness) renderError(iw http.ResponseWriter, ir *http.Request, err erro
if err == nil {
utils.Logger.Panic("Caller passed in a nil error")
}
templateSet := template.New("__root__")
seekViewOnPath := func(view string) (path string) {
path = filepath.Join(h.paths.ViewsPath, "errors", view)
@@ -86,26 +90,27 @@ func (h *Harness) renderError(iw http.ResponseWriter, ir *http.Request, err erro
}
return
}
target := []string{seekViewOnPath("500.html"), seekViewOnPath("500-dev.html")}
if !utils.Exists(target[0]) {
fmt.Fprintf(iw, "Target template not found not found %s<br />\n", target[0])
fmt.Fprintf(iw, "An error occurred %s", err.Error())
return
}
var revelError *utils.SourceError
switch e := err.(type) {
case *utils.SourceError:
revelError = e
case error:
if !errors.As(err, &revelError) {
revelError = &utils.SourceError{
Title: "Server Error",
Description: e.Error(),
Description: err.Error(),
}
}
if revelError == nil {
panic("no error provided")
}
viewArgs := map[string]interface{}{}
viewArgs["RunMode"] = h.paths.RunMode
viewArgs["DevMode"] = h.paths.DevMode
@@ -204,8 +209,8 @@ func NewHarness(c *model.CommandConfig, paths *model.RevelContainer, runMode str
// Refresh method rebuilds the Revel application and run it on the given port.
// called by the watcher.
func (h *Harness) Refresh() (err *utils.SourceError) {
t := time.Now()
fmt.Println("Changed detected, recompiling")
t := time.Now();
fmt.Println("Change detected, recompiling")
err = h.refresh()
if err != nil && !h.ranOnce && h.useProxy {
addr := fmt.Sprintf("%s:%d", h.paths.HTTPAddr, h.paths.HTTPPort)
@@ -236,32 +241,42 @@ func (h *Harness) refresh() (err *utils.SourceError) {
h.app, newErr = Build(h.config, h.paths)
if newErr != nil {
utils.Logger.Error("Build detected an error", "error", newErr)
if castErr, ok := newErr.(*utils.SourceError); ok {
var castErr *utils.SourceError
if errors.As(newErr, &castErr) {
return castErr
}
err = &utils.SourceError{
Title: "App failed to start up",
Description: err.Error(),
Description: newErr.Error(),
}
return
}
if h.useProxy {
h.app.Port = h.port
runMode := h.runMode
if !h.config.HistoricMode {
// Recalulate run mode based on the config
var paths []byte
if len(h.app.PackagePathMap) > 0 {
paths, _ = json.Marshal(h.app.PackagePathMap)
}
runMode = fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v,"packagePathMap":%s}`, h.app.Paths.RunMode, h.config.Verbose, string(paths))
runMode = fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v,"packagePathMap":%s}`, h.app.Paths.RunMode, h.config.Verbose[0], string(paths))
}
if err2 := h.app.Cmd(runMode).Start(h.config); err2 != nil {
utils.Logger.Error("Could not start application", "error", err2)
if err, k := err2.(*utils.SourceError); k {
var serr *utils.SourceError
if errors.As(err2, &serr) {
return err
}
return &utils.SourceError{
Title: "App failed to start up",
Description: err2.Error(),
@@ -297,8 +312,12 @@ func (h *Harness) Run() {
paths = append(paths, h.paths.CodePaths...)
h.watcher = watcher.NewWatcher(h.paths, false)
h.watcher.Listen(h, paths...)
go h.Refresh()
// h.watcher.Notify()
go func() {
if err := h.Refresh(); err != nil {
utils.Logger.Error("Failed to refresh", "error", err)
}
}()
if h.useProxy {
go func() {

View File

@@ -39,8 +39,11 @@ func (h *CompositeMultiHandler) Log(r *Record) (err error) {
// Embed the caller function in the context
if handler != nil {
handler.Log(r)
if err := handler.Log(r); err != nil {
panic(err)
}
}
return
}
@@ -91,8 +94,8 @@ func (h *CompositeMultiHandler) SetHandlers(handler LogHandler, options *LogOpti
}
}
func (h *CompositeMultiHandler) SetJson(writer io.Writer, options *LogOptions) {
handler := CallerFileHandler(StreamHandler(writer, JsonFormatEx(
func (h *CompositeMultiHandler) SetJSON(writer io.Writer, options *LogOptions) {
handler := CallerFileHandler(StreamHandler(writer, JSONFormatEx(
options.GetBoolDefault("pretty", false),
options.GetBoolDefault("lineSeparated", true),
)))
@@ -103,7 +106,7 @@ func (h *CompositeMultiHandler) SetJson(writer io.Writer, options *LogOptions) {
}
// Use built in rolling function.
func (h *CompositeMultiHandler) SetJsonFile(filePath string, options *LogOptions) {
func (h *CompositeMultiHandler) SetJSONFile(filePath string, options *LogOptions) {
writer := &lumberjack.Logger{
Filename: filePath,
MaxSize: options.GetIntDefault("maxSizeMB", 1024), // megabytes
@@ -111,7 +114,7 @@ func (h *CompositeMultiHandler) SetJsonFile(filePath string, options *LogOptions
MaxBackups: options.GetIntDefault("maxBackups", 7),
Compress: options.GetBoolDefault("compress", true),
}
h.SetJson(writer, options)
h.SetJSON(writer, options)
}
func (h *CompositeMultiHandler) SetTerminal(writer io.Writer, options *LogOptions) {

View File

@@ -50,6 +50,7 @@ func CallerFileHandler(h LogHandler) LogHandler {
// Adds in a context called `caller` to the record (contains file name and line number like `foo.go:12`)
// Uses the `log15.CallerFuncHandler` to perform this task.
func CallerFuncHandler(h LogHandler) LogHandler {
// TODO: infinite recursion
return CallerFuncHandler(h)
}
@@ -137,8 +138,9 @@ func NotMatchHandler(key string, value interface{}, h LogHandler) LogHandler {
func MultiHandler(hs ...LogHandler) LogHandler {
return FuncHandler(func(r *Record) error {
for _, h := range hs {
// what to do about failures?
h.Log(r)
if err := h.Log(r); err != nil {
panic(err)
}
}
return nil
})
@@ -189,6 +191,7 @@ func (ll *ListLogHandler) Log(r *Record) (err error) {
handler.Log(r)
}
}
return
}

View File

@@ -13,7 +13,7 @@ import (
func InitializeFromConfig(basePath string, config *config.Context) (c *CompositeMultiHandler) {
// If running in test mode suppress anything that is not an error
if config != nil && config.BoolDefault(TEST_MODE_FLAG, false) {
if config != nil && config.BoolDefault(TestModeFlag, false) {
// Preconfigure all the options
config.SetOption("log.info.output", "none")
config.SetOption("log.debug.output", "none")
@@ -26,14 +26,14 @@ func InitializeFromConfig(basePath string, config *config.Context) (c *Composite
c, _ = NewCompositeMultiHandler()
// Filters are assigned first, non filtered items override filters
if config != nil && !config.BoolDefault(TEST_MODE_FLAG, false) {
if config != nil && !config.BoolDefault(TestModeFlag, false) {
initAllLog(c, basePath, config)
}
initLogLevels(c, basePath, config)
if c.CriticalHandler == nil && c.ErrorHandler != nil {
c.CriticalHandler = c.ErrorHandler
}
if config != nil && !config.BoolDefault(TEST_MODE_FLAG, false) {
if config != nil && !config.BoolDefault(TestModeFlag, false) {
initFilterLog(c, basePath, config)
if c.CriticalHandler == nil && c.ErrorHandler != nil {
c.CriticalHandler = c.ErrorHandler
@@ -47,7 +47,7 @@ func InitializeFromConfig(basePath string, config *config.Context) (c *Composite
// Init the log.all configuration options.
func initAllLog(c *CompositeMultiHandler, basePath string, config *config.Context) {
if config != nil {
extraLogFlag := config.BoolDefault(SPECIAL_USE_FLAG, false)
extraLogFlag := config.BoolDefault(SpecialUseFlag, false)
if output, found := config.String("log.all.output"); found {
// Set all output for the specified handler
if extraLogFlag {
@@ -63,7 +63,7 @@ func initAllLog(c *CompositeMultiHandler, basePath string, config *config.Contex
// log.error.filter ....
func initFilterLog(c *CompositeMultiHandler, basePath string, config *config.Context) {
if config != nil {
extraLogFlag := config.BoolDefault(SPECIAL_USE_FLAG, false)
extraLogFlag := config.BoolDefault(SpecialUseFlag, false)
for _, logFilter := range logFilterList {
// Init for all filters
@@ -102,7 +102,7 @@ func initLogLevels(c *CompositeMultiHandler, basePath string, config *config.Con
"trace", // TODO trace is deprecated
} {
if config != nil {
extraLogFlag := config.BoolDefault(SPECIAL_USE_FLAG, false)
extraLogFlag := config.BoolDefault(SpecialUseFlag, false)
output, found := config.String("log." + name + ".output")
if found {
if extraLogFlag {
@@ -178,7 +178,7 @@ func initHandlerFor(c *CompositeMultiHandler, output, basePath string, options *
}
if strings.HasSuffix(output, "json") {
c.SetJsonFile(output, options)
c.SetJSONFile(output, options)
} else {
// Override defaults for a terminal file
options.SetExtendedOptions("noColor", true)

View File

@@ -59,7 +59,7 @@ var singleCases = []testData{
func TestSingleCases(t *testing.T) {
rootLog := logger.New()
for _, testCase := range singleCases {
testCase.logTest(rootLog, t)
testCase.logTest(t, rootLog)
testCase.validate(t)
}
}
@@ -112,7 +112,7 @@ var filterCases = []testData{
func TestFilterCases(t *testing.T) {
rootLog := logger.New("module", "app")
for _, testCase := range filterCases {
testCase.logTest(rootLog, t)
testCase.logTest(t, rootLog)
testCase.validate(t)
}
}
@@ -169,7 +169,7 @@ var nfilterCases = []testData{
func TestNotFilterCases(t *testing.T) {
rootLog := logger.New("module", "app")
for _, testCase := range nfilterCases {
testCase.logTest(rootLog, t)
testCase.logTest(t, rootLog)
testCase.validate(t)
}
}
@@ -186,7 +186,7 @@ var offCases = []testData{
func TestOffCases(t *testing.T) {
rootLog := logger.New("module", "app")
for _, testCase := range offCases {
testCase.logTest(rootLog, t)
testCase.logTest(t, rootLog)
testCase.validate(t)
}
}
@@ -203,7 +203,7 @@ var duplicateCases = []testData{
func TestDuplicateCases(t *testing.T) {
rootLog := logger.New("module", "app")
for _, testCase := range duplicateCases {
testCase.logTest(rootLog, t)
testCase.logTest(t, rootLog)
testCase.validate(t)
}
}
@@ -232,7 +232,7 @@ var contradictCases = []testData{
func TestContradictCases(t *testing.T) {
rootLog := logger.New("module", "app")
for _, testCase := range contradictCases {
testCase.logTest(rootLog, t)
testCase.logTest(t, rootLog)
testCase.validate(t)
}
}
@@ -253,12 +253,12 @@ var allCases = []testData{
func TestAllCases(t *testing.T) {
rootLog := logger.New("module", "app")
for i, testCase := range allCases {
testCase.logTest(rootLog, t)
testCase.logTest(t, rootLog)
allCases[i] = testCase
}
rootLog = logger.New()
for i, testCase := range allCases {
testCase.logTest(rootLog, t)
testCase.logTest(t, rootLog)
allCases[i] = testCase
}
for _, testCase := range allCases {
@@ -284,7 +284,9 @@ func (c *testCounter) Log(r *logger.Record) error {
return nil
}
func (td *testData) logTest(rootLog logger.MultiLogger, t *testing.T) {
func (td *testData) logTest(t *testing.T, rootLog logger.MultiLogger) {
t.Helper()
if td.tc == nil {
td.tc = &testCounter{}
counterInit(td.tc)
@@ -317,6 +319,8 @@ func (td *testData) runLogTest(log logger.MultiLogger) {
}
func (td *testData) validate(t *testing.T) {
t.Helper()
t.Logf("Test %#v expected %#v", td.tc, td.result)
assert.Equal(t, td.result.debug, td.tc.debug, "Debug failed "+strings.Join(td.config, " "))
assert.Equal(t, td.result.info, td.tc.info, "Info failed "+strings.Join(td.config, " "))

View File

@@ -197,10 +197,10 @@ func escapeString(s string) string {
return ret
}
// JsonFormatEx formats log records as JSON objects. If pretty is true,
// JSONFormatEx formats log records as JSON objects. If pretty is true,
// records will be pretty-printed. If lineSeparated is true, records
// will be logged with a new line between each record.
func JsonFormatEx(pretty, lineSeparated bool) LogFormat {
func JSONFormatEx(pretty, lineSeparated bool) LogFormat {
jsonMarshal := json.Marshal
if pretty {
jsonMarshal = func(v interface{}) ([]byte, error) {

View File

@@ -20,9 +20,9 @@ var (
const (
// The test mode flag overrides the default log level and shows only errors.
TEST_MODE_FLAG = "testModeFlag"
TestModeFlag = "testModeFlag"
// The special use flag enables showing messages when the logger is setup.
SPECIAL_USE_FLAG = "specialUseFlag"
SpecialUseFlag = "specialUseFlag"
)
// Returns the logger for the name.

View File

@@ -9,6 +9,20 @@ import (
"time"
)
// Error is used for constant errors.
type Error string
// Error implements the error interface.
func (e Error) Error() string {
return string(e)
}
const (
ErrNotFunc Error = "not a function"
ErrTakesArgs Error = "takes arguments"
ErrNoReturn Error = "no return value"
)
// Function handler wraps the declared function and returns the handler for it.
func FuncHandler(fn func(r *Record) error) LogHandler {
return funcHandler(fn)
@@ -71,15 +85,15 @@ func evaluateLazy(lz Lazy) (interface{}, error) {
t := reflect.TypeOf(lz.Fn)
if t.Kind() != reflect.Func {
return nil, fmt.Errorf("INVALID_LAZY, not func: %+v", lz.Fn)
return nil, fmt.Errorf("%w %+v", ErrNotFunc, lz.Fn)
}
if t.NumIn() > 0 {
return nil, fmt.Errorf("INVALID_LAZY, func takes args: %+v", lz.Fn)
return nil, fmt.Errorf("%w %+v", ErrTakesArgs, lz.Fn)
}
if t.NumOut() == 0 {
return nil, fmt.Errorf("INVALID_LAZY, no func return val: %+v", lz.Fn)
return nil, fmt.Errorf("%w %+v", ErrNoReturn, lz.Fn)
}
value := reflect.ValueOf(lz.Fn)

View File

@@ -28,6 +28,11 @@ const (
VERSION
)
const (
ErrImportInvalid Error = "invalid import path, working dir is in GOPATH root"
ErrUnableToImport Error = "unable to determine import path from"
)
type (
// The Revel command type.
COMMAND int
@@ -110,7 +115,7 @@ func (c *CommandConfig) UpdateImportPath() error {
importPath = importPath[4:]
} else if importPath == "src" {
if c.Index != VERSION {
return fmt.Errorf("invalid import path, working dir is in GOPATH root")
return ErrImportInvalid
}
importPath = ""
}
@@ -122,7 +127,10 @@ func (c *CommandConfig) UpdateImportPath() error {
c.ImportPath = importPath
// We need the source root determined at this point to check the setversions
c.initAppFolder()
if err := c.initAppFolder(); err != nil {
utils.Logger.Error("Error initing app folder", "error", err)
}
utils.Logger.Info("Returned import path", "path", importPath)
if required && c.Index != NEW {
if err := c.SetVersions(); err != nil {
@@ -138,7 +146,7 @@ func (c *CommandConfig) UpdateImportPath() error {
return nil
}
if len(importPath) == 0 {
return fmt.Errorf("unable to determine import path from : %s", importPath)
return fmt.Errorf("%w: %s", ErrUnableToImport, importPath)
}
return nil
}
@@ -165,8 +173,6 @@ func (c *CommandConfig) initAppFolder() (err error) {
} else {
appFolder = filepath.Join(wd, appFolder)
}
} else if strings.Contains(appFolder, ".") {
appFolder = filepath.Join(wd, filepath.Base(c.ImportPath))
} else if !filepath.IsAbs(appFolder) {
appFolder = filepath.Join(wd, appFolder)
}

View File

@@ -2,7 +2,6 @@
package model
import (
"errors"
"fmt"
"path/filepath"
"sort"
@@ -13,6 +12,24 @@ import (
"golang.org/x/tools/go/packages"
)
// Error is used for constant errors.
type Error string
// Error implements the error interface.
func (e Error) Error() string {
return string(e)
}
const (
ErrNoApp Error = "no app found at path"
ErrNoConfig Error = "no config found at path"
ErrNotFound Error = "not found"
ErrMissingCert Error = "no http.sslcert provided"
ErrMissingKey Error = "no http.sslkey provided"
ErrNoFiles Error = "no files found in import path"
ErrNoPackages Error = "no packages found for import"
)
type (
// The container object for describing all Revels variables.
RevelContainer struct {
@@ -123,10 +140,10 @@ func NewRevelPaths(mode, importPath, appSrcPath string, callback RevelCallback)
// Sanity check , ensure app and conf paths exist
if !utils.DirExists(rp.AppPath) {
return rp, fmt.Errorf("no application found at path %s", rp.AppPath)
return rp, fmt.Errorf("%w: %s", ErrNoApp, rp.AppPath)
}
if !utils.DirExists(filepath.Join(rp.BasePath, "conf")) {
return rp, fmt.Errorf("no configuration found at path %s", filepath.Join(rp.BasePath, "conf"))
return rp, fmt.Errorf("%w: %s", ErrNoConfig, filepath.Join(rp.BasePath, "conf"))
}
rp.ViewsPath = filepath.Join(rp.AppPath, "views")
@@ -150,7 +167,7 @@ func NewRevelPaths(mode, importPath, appSrcPath string, callback RevelCallback)
rp.Config, err = config.LoadContext("app.conf", rp.ConfPaths)
if err != nil {
return rp, fmt.Errorf("unable to load configuration file %s", err)
return rp, fmt.Errorf("unable to load configuration file %w", err)
}
// Ensure that the selected runmode appears in app.conf.
@@ -159,7 +176,7 @@ func NewRevelPaths(mode, importPath, appSrcPath string, callback RevelCallback)
mode = config.DefaultSection
}
if !rp.Config.HasSection(mode) {
return rp, fmt.Errorf("app.conf: No mode found: %s %s", "run-mode", mode)
return rp, fmt.Errorf("app.conf: %w %s %s", ErrNotFound, "run-mode", mode)
}
rp.Config.SetSection(mode)
@@ -172,13 +189,14 @@ func NewRevelPaths(mode, importPath, appSrcPath string, callback RevelCallback)
rp.HTTPSslKey = rp.Config.StringDefault("http.sslkey", "")
if rp.HTTPSsl {
if rp.HTTPSslCert == "" {
return rp, errors.New("no http.sslcert provided")
return rp, ErrMissingCert
}
if rp.HTTPSslKey == "" {
return rp, errors.New("no http.sslkey provided")
return rp, ErrMissingKey
}
}
//
rp.AppName = rp.Config.StringDefault("app.name", "(not set)")
rp.AppRoot = rp.Config.StringDefault("app.root", "")
rp.CookiePrefix = rp.Config.StringDefault("cookie.prefix", "REVEL")
@@ -201,7 +219,7 @@ func NewRevelPaths(mode, importPath, appSrcPath string, callback RevelCallback)
func (rp *RevelContainer) LoadMimeConfig() (err error) {
rp.MimeConfig, err = config.LoadContext("mime-types.conf", rp.ConfPaths)
if err != nil {
return fmt.Errorf("failed to load mime type config: %s %s", "error", err)
return fmt.Errorf("failed to load mime type config: %s %w", "error", err)
}
return
}
@@ -226,10 +244,14 @@ func (rp *RevelContainer) loadModules(callback RevelCallback) (err error) {
modulePath, err := rp.ResolveImportPath(moduleImportPath)
if err != nil {
utils.Logger.Info("Missing module ", "module_import_path", moduleImportPath, "error", err)
callback.PackageResolver(moduleImportPath)
if err := callback.PackageResolver(moduleImportPath); err != nil {
return fmt.Errorf("failed to resolve package %w", err)
}
modulePath, err = rp.ResolveImportPath(moduleImportPath)
if err != nil {
return fmt.Errorf("failed to load module. Import of path failed %s:%s %s:%s ", "modulePath", moduleImportPath, "error", err)
return fmt.Errorf("failed to load module. Import of path failed %s:%s %s:%w ", "modulePath", moduleImportPath, "error", err)
}
}
// Drop anything between module.???.<name of module>
@@ -280,7 +302,7 @@ func (rp *RevelContainer) ResolveImportPath(importPath string) (string, error) {
config.Env = utils.ReducedEnv(false)
pkgs, err := packages.Load(config, importPath)
if len(pkgs) == 0 {
return "", errors.New("No packages found for import " + importPath + " using app path " + rp.AppPath)
return "", fmt.Errorf("%w %s using app path %s", ErrNoPackages, importPath, rp.AppPath)
}
// modPkg, err := build.Import(importPath, rp.AppPath, build.FindOnly)
if err != nil {
@@ -289,5 +311,5 @@ func (rp *RevelContainer) ResolveImportPath(importPath string) (string, error) {
if len(pkgs[0].GoFiles) > 0 {
return filepath.Dir(pkgs[0].GoFiles[0]), nil
}
return pkgs[0].PkgPath, errors.New("No files found in import path " + importPath)
return pkgs[0].PkgPath, fmt.Errorf("%w: %s", ErrNoFiles, importPath)
}

View File

@@ -20,7 +20,7 @@ func NewTypeExprFromData(expr, pkgName string, pkgIndex int, valid bool) TypeExp
// NewTypeExpr returns the syntactic expression for referencing this type in Go.
func NewTypeExprFromAst(pkgName string, expr ast.Expr) TypeExpr {
error := ""
err := ""
switch t := expr.(type) {
case *ast.Ident:
if IsBuiltinType(t.Name) {
@@ -41,14 +41,14 @@ func NewTypeExprFromAst(pkgName string, expr ast.Expr) TypeExpr {
e := NewTypeExprFromAst(pkgName, t.Value)
return NewTypeExprFromData("map["+identKey.Name+"]"+e.Expr, e.PkgName, e.pkgIndex+len("map["+identKey.Name+"]"), e.Valid)
}
error = fmt.Sprintf("Failed to generate name for Map field :%v. Make sure the field name is valid.", t.Key)
err = fmt.Sprintf("Failed to generate name for Map field :%v. Make sure the field name is valid.", t.Key)
case *ast.Ellipsis:
e := NewTypeExprFromAst(pkgName, t.Elt)
return NewTypeExprFromData("[]"+e.Expr, e.PkgName, e.pkgIndex+2, e.Valid)
default:
error = fmt.Sprintf("Failed to generate name for field: %v Package: %v. Make sure the field name is valid.", expr, pkgName)
err = fmt.Sprintf("Failed to generate name for field: %v Package: %v. Make sure the field name is valid.", expr, pkgName)
}
return NewTypeExprFromData(error, "", 0, false)
return NewTypeExprFromData(err, "", 0, false)
}
// TypeName returns the fully-qualified type name for this expression.
@@ -61,7 +61,7 @@ func (e TypeExpr) TypeName(pkgOverride string) string {
return e.Expr[:e.pkgIndex] + pkgName + "." + e.Expr[e.pkgIndex:]
}
var builtInTypes = map[string]struct{}{
var builtInTypes = map[string]struct{}{ //nolint:gochecknoglobals
"bool": {},
"byte": {},
"complex128": {},

View File

@@ -8,6 +8,7 @@ package parser
// It catalogs the controllers, their methods, and their arguments.
import (
"errors"
"go/ast"
"go/parser"
"go/scanner"
@@ -83,7 +84,8 @@ func (pc *processContainer) processPath(path string, info os.FileInfo, err error
0)
if err != nil {
if errList, ok := err.(scanner.ErrorList); ok {
var errList scanner.ErrorList
if errors.As(err, &errList) {
pos := errList[0].Pos
newError := &utils.SourceError{
SourceType: ".go source",

View File

@@ -1,6 +1,7 @@
package parser2
import (
"errors"
"go/ast"
"go/parser"
"go/scanner"
@@ -151,7 +152,8 @@ func (s *SourceProcessor) processPath(path string, info os.FileInfo, err error)
0)
if err != nil {
if errList, ok := err.(scanner.ErrorList); ok {
var errList scanner.ErrorList
if errors.As(err, &errList) {
pos := errList[0].Pos
newError := &utils.SourceError{
SourceType: ".go source",

View File

@@ -19,7 +19,7 @@ func TestBuild(t *testing.T) {
t.Run("Build", func(t *testing.T) {
a := assert.New(t)
c := newApp("build-test", model.NEW, nil, a)
main.Commands[model.NEW].RunWith(c)
a.Nil(main.Commands[model.NEW].RunWith(c), "failed to run new")
c.Index = model.BUILD
c.Build.TargetPath = filepath.Join(gopath, "build-test", "target")
c.Build.ImportPath = c.ImportPath
@@ -34,7 +34,7 @@ func TestBuild(t *testing.T) {
"build-test-WithFlags/app.AppVersion=SomeValue",
"build-test-WithFlags/app.SomeOtherValue=SomeValue",
}
main.Commands[model.NEW].RunWith(c)
a.Nil(main.Commands[model.NEW].RunWith(c), "failed to run new")
c.Index = model.BUILD
c.Build.TargetPath = filepath.Join(gopath, "build-test", "target")
c.Build.ImportPath = c.ImportPath

View File

@@ -19,9 +19,12 @@ func TestClean(t *testing.T) {
t.Run("Clean", func(t *testing.T) {
a := assert.New(t)
c := newApp("clean-test", model.NEW, nil, a)
main.Commands[model.NEW].RunWith(c)
a.Nil(main.Commands[model.NEW].RunWith(c), "failed to run new")
c.Index = model.TEST
main.Commands[model.TEST].RunWith(c)
a.Nil(main.Commands[model.TEST].RunWith(c), "failed to run test")
a.True(utils.Exists(filepath.Join(gopath, "clean-test", "app", "tmp", "main.go")),
"Missing main from path "+filepath.Join(gopath, "clean-test", "app", "tmp", "main.go"))
c.Clean.ImportPath = c.ImportPath

View File

@@ -33,7 +33,10 @@ func setup(suffix string, a *assert.Assertions) string {
// But if you change into that directory and read the current folder it is
// /private/var/folders/nz/vv4_9tw56nv9k3tkvyszvwg80000gn/T/revel-test/revel-test-build
// So to make this work on darwin this code was added
os.Chdir(gopath)
if err := os.Chdir(gopath); err != nil {
panic(err)
}
newwd, _ := os.Getwd()
gopath = newwd
defaultBuild := build.Default

View File

@@ -18,8 +18,10 @@ import (
"github.com/revel/cmd/utils"
)
const ErrNoSkeleton Error = "failed to find skeleton in filepath"
var cmdNew = &Command{
UsageLine: "new -i [path] -s [skeleton]",
UsageLine: "new -i [path] -s [skeleton] -p [package name]",
Short: "create a skeleton Revel application",
Long: `
New creates a few files to get a new Revel application running quickly.
@@ -92,7 +94,9 @@ func newApp(c *model.CommandConfig) (err error) {
// This kicked off the download of the revel app, not needed for vendor
if !c.Vendored {
// At this point the versions can be set
c.SetVersions()
if err = c.SetVersions(); err != nil {
return
}
}
// copy files to new app directory
@@ -114,11 +118,18 @@ func newApp(c *model.CommandConfig) (err error) {
// Need to prep the run command
c.Run.ImportPath = c.ImportPath
updateRunConfig(c, nil)
c.UpdateImportPath()
runApp(c)
if err = c.UpdateImportPath(); err != nil {
return
}
if err = runApp(c); err != nil {
return
}
} else {
fmt.Fprintln(os.Stdout, "\nYou can run it with:\n revel run -a", c.ImportPath)
}
return
}
@@ -129,13 +140,16 @@ func createModVendor(c *model.CommandConfig) (err error) {
utils.CmdInit(goModCmd, !c.Vendored, c.AppPath)
utils.Logger.Info("Exec:", "args", goModCmd.Args, "env", goModCmd.Env, "workingdir", goModCmd.Dir)
getOutput, err := goModCmd.CombinedOutput()
if c.New.Callback != nil {
err = c.New.Callback()
}
if err != nil {
return utils.NewBuildIfError(err, string(getOutput))
}
return
}
@@ -206,7 +220,7 @@ func setSkeletonPath(c *model.CommandConfig) (err error) {
c.New.SkeletonPath = fullpath
utils.Logger.Info("Set skeleton path to ", fullpath)
if !utils.DirExists(fullpath) {
return fmt.Errorf("failed to find skeleton in filepath %s %s", fullpath, sp.String())
return fmt.Errorf("%w %s %s", ErrNoSkeleton, fullpath, sp.String())
}
case "git":
fallthrough

View File

@@ -17,7 +17,7 @@ func TestPackage(t *testing.T) {
t.Run("Package", func(t *testing.T) {
a := assert.New(t)
c := newApp("package-test", model.NEW, nil, a)
main.Commands[model.NEW].RunWith(c)
a.Nil(main.Commands[model.NEW].RunWith(c), "failed to run new")
c.Index = model.PACKAGE
c.Package.ImportPath = c.ImportPath
a.Nil(main.Commands[model.PACKAGE].RunWith(c), "Failed to run package-test")

View File

@@ -22,6 +22,16 @@ import (
"github.com/revel/cmd/utils"
)
// Error is used for constant errors.
type Error string
// Error implements the error interface.
func (e Error) Error() string {
return string(e)
}
const ErrInvalidCommandLine Error = "invalid command line arguments"
const (
// RevelCmdImportPath Revel framework cmd tool import path.
RevelSkeletonsImportPath = "github.com/revel/skeletons"
@@ -138,7 +148,7 @@ func ParseArgs(c *model.CommandConfig, parser *flags.Parser, args []string) (err
if !Commands[c.Index].UpdateConfig(c, extraArgs) {
buffer := &bytes.Buffer{}
parser.WriteHelp(buffer)
err = fmt.Errorf("invalid command line arguments %v\n%s", extraArgs, buffer.String())
err = fmt.Errorf("%w %v\n%s", ErrInvalidCommandLine, extraArgs, buffer.String())
}
return

View File

@@ -133,7 +133,7 @@ func runApp(c *model.CommandConfig) (err error) {
// If the app is run in "watched" mode, use the harness to run it.
if revelPath.Config.BoolDefault("watch", true) && revelPath.Config.BoolDefault("watch.code", true) {
utils.Logger.Info("Running in watched mode.")
runMode := fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v}`, revelPath.RunMode, c.Verbose)
runMode := fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v}`, revelPath.RunMode, c.Verbose[0])
if c.HistoricMode {
runMode = revelPath.RunMode
}
@@ -152,7 +152,7 @@ func runApp(c *model.CommandConfig) (err error) {
if len(app.PackagePathMap) > 0 {
paths, _ = json.Marshal(app.PackagePathMap)
}
runMode := fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v,"packagePathMap":%s}`, app.Paths.RunMode, c.Verbose, string(paths))
runMode := fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v,"packagePathMap":%s}`, app.Paths.RunMode, c.Verbose[0], string(paths))
if c.HistoricMode {
runMode = revelPath.RunMode
}

View File

@@ -112,7 +112,7 @@ func testApp(c *model.CommandConfig) (err error) {
if len(app.PackagePathMap) > 0 {
paths, _ = json.Marshal(app.PackagePathMap)
}
runMode := fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v,"packagePathMap":%s}`, app.Paths.RunMode, c.Verbose, string(paths))
runMode := fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v,"packagePathMap":%s}`, app.Paths.RunMode, c.Verbose[0], string(paths))
if c.HistoricMode {
runMode = app.Paths.RunMode
}

View File

@@ -82,7 +82,9 @@ func (v *VersionCommand) RunWith(c *model.CommandConfig) (err error) {
if e := cmd.Start(); e != nil {
fmt.Println("Go command error ", e)
} else {
cmd.Wait()
if err = cmd.Wait(); err != nil {
return
}
}
return
@@ -188,7 +190,9 @@ func (v *VersionCommand) versionFromBytes(sourceStream []byte) (version *model.V
r := spec.Values[0].(*ast.BasicLit)
switch spec.Names[0].Name {
case "Version":
version.ParseVersion(strings.ReplaceAll(r.Value, `"`, ""))
if err = version.ParseVersion(strings.ReplaceAll(r.Value, `"`, "")); err != nil {
return
}
case "BuildDate":
version.BuildDate = r.Value
case "MinimumGoVersion":
@@ -202,7 +206,12 @@ func (v *VersionCommand) versionFromBytes(sourceStream []byte) (version *model.V
// Fetch the local version of revel from the file system.
func (v *VersionCommand) updateLocalVersions() {
v.cmdVersion = &model.Version{}
v.cmdVersion.ParseVersion(cmd.Version)
if err := v.cmdVersion.ParseVersion(cmd.Version); err != nil {
utils.Logger.Warn("Error parsing version", "error", err, "version", cmd.Version)
return
}
v.cmdVersion.BuildDate = cmd.BuildDate
v.cmdVersion.MinGoVersion = cmd.MinimumGoVersion

View File

@@ -1,6 +1,7 @@
package main_test
import (
"errors"
"os"
"path/filepath"
"testing"
@@ -34,8 +35,9 @@ func TestVersion(t *testing.T) {
c.Version.ImportPath = c.ImportPath
a.Nil(main.Commands[model.VERSION].RunWith(c), "Failed to run version-test")
})
if !t.Failed() {
if err := os.RemoveAll(gopath); err != nil && err != os.ErrNotExist {
if err := os.RemoveAll(gopath); err != nil && !errors.Is(err, os.ErrNotExist) {
a.Fail("Failed to remove test path", err.Error())
}
}

View File

@@ -1,6 +1,7 @@
package utils
import (
"errors"
"fmt"
"regexp"
"strconv"
@@ -30,7 +31,8 @@ func NewBuildError(message string, args ...interface{}) (b *BuildError) {
// Returns a new BuildError if err is not nil.
func NewBuildIfError(err error, message string, args ...interface{}) (b error) {
if err != nil {
if berr, ok := err.(*BuildError); ok {
var berr *BuildError
if errors.As(err, &berr) {
// This is already a build error so just append the args
berr.Args = append(berr.Args, args...)
return berr
@@ -50,16 +52,16 @@ func (b *BuildError) Error() string {
// Parse the output of the "go build" command.
// Return a detailed Error.
func NewCompileError(importPath, errorLink string, error error) *SourceError {
func NewCompileError(importPath, errorLink string, err error) *SourceError {
// Get the stack from the error
errorMatch := regexp.MustCompile(`(?m)^([^:#]+):(\d+):(\d+:)? (.*)$`).
FindSubmatch([]byte(error.Error()))
FindSubmatch([]byte(err.Error()))
if errorMatch == nil {
errorMatch = regexp.MustCompile(`(?m)^(.*?):(\d+):\s(.*?)$`).FindSubmatch([]byte(error.Error()))
errorMatch = regexp.MustCompile(`(?m)^(.*?):(\d+):\s(.*?)$`).FindSubmatch([]byte(err.Error()))
if errorMatch == nil {
Logger.Error("Failed to parse build errors", "error", error)
Logger.Error("Failed to parse build errors", "error", err)
return &SourceError{
SourceType: "Go code",
Title: "Go Compilation Error",
@@ -69,7 +71,7 @@ func NewCompileError(importPath, errorLink string, error error) *SourceError {
errorMatch = append(errorMatch, errorMatch[3])
Logger.Error("Build errors", "errors", error)
Logger.Error("Build errors", "errors", err)
}
// Read the source for the offending file.

View File

@@ -17,6 +17,9 @@ func CmdInit(c *exec.Cmd, addGoPath bool, basePath string) {
c.Env = ReducedEnv(addGoPath)
}
// ReducedEnv returns a list of environment vairables by using os.Env
// it will remove the GOPATH, GOROOT if addGoPath is true
func ReducedEnv(addGoPath bool) []string {
realPath := &bytes.Buffer{}
env := []string{}
@@ -38,7 +41,7 @@ func ReducedEnv(addGoPath bool) []string {
if pair[0] == "GOMODCACHE" {
continue
} else if !addGoPath && (pair[0] == "GOPATH" || pair[0] == "GOROOT") {
continue
}
env = append(env, e)
}

View File

@@ -150,8 +150,9 @@ func MustChmod(filename string, mode os.FileMode) {
// Called if panic.
func PanicOnError(err error, msg string) {
if revErr, ok := err.(*SourceError); (ok && revErr != nil) || (!ok && err != nil) {
Logger.Panicf("Abort: %s: %s %s", msg, revErr, err)
var serr *SourceError
if (errors.As(err, &serr) && serr != nil) || err != nil {
Logger.Panicf("Abort: %s: %s %s", msg, serr, err)
}
}
@@ -348,9 +349,17 @@ func FindSrcPaths(appPath string, packageList []string, packageResolver func(pkg
return
}
// Error is used for constant errors.
type Error string
// Error implements the error interface.
func (e Error) Error() string {
return string(e)
}
var (
NO_APP_FOUND = errors.New("no app found")
NO_REVEL_FOUND = errors.New("no revel found")
ErrNoApp Error = "no app found"
ErrNoRevel Error = "no revel found"
)
// Find the full source dir for the import path, uses the build.Default.GOPATH to search for the directory.
@@ -388,9 +397,9 @@ func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[str
}
if !found {
if packageName == "github.com/revel/revel" {
err = NO_REVEL_FOUND
err = ErrNoRevel
} else {
err = NO_APP_FOUND
err = ErrNoApp
}
missingList = append(missingList, packageName)
}

View File

@@ -33,7 +33,7 @@ func InitLogger(basePath string, logLevel logger.LogLevel) {
// This function is to throw a panic that may be caught by the packger so it can perform the needed
// imports.
func Retry(format string, args ...interface{}) {
func Retryf(format string, args ...interface{}) {
// Ensure the user's command prompt starts on the next line.
if !strings.HasSuffix(format, "\n") {
format += "\n"

View File

@@ -5,7 +5,7 @@
package cmd
const (
// Version current Revel version
// Version current Revel version.
Version = "1.1.0-dev"
// BuildDate latest commit/release date.

View File

@@ -46,16 +46,16 @@ type Watcher struct {
timerMutex *sync.Mutex // A mutex to prevent concurrent updates
refreshChannel chan *utils.SourceError
refreshChannelCount int
refreshTimerMS time.Duration // The number of milliseconds between refreshing builds
refreshInterval time.Duration // The interval between refreshing builds
}
// Creates a new watched based on the container.
func NewWatcher(paths *model.RevelContainer, eagerRefresh bool) *Watcher {
return &Watcher{
forceRefresh: false,
lastError: -1,
paths: paths,
refreshTimerMS: time.Duration(paths.Config.IntDefault("watch.rebuild.delay", 1000)),
forceRefresh: true,
lastError: -1,
paths: paths,
refreshInterval: time.Duration(paths.Config.IntDefault("watch.rebuild.delay", 1000)) * time.Millisecond,
eagerRefresh: eagerRefresh ||
paths.DevMode &&
paths.Config.BoolDefault("watch", true) &&
@@ -163,7 +163,10 @@ func (w *Watcher) NotifyWhenUpdated(listener Listener, watcher *fsnotify.Watcher
} else {
// Run refresh in parallel
go func() {
w.notifyInProcess(listener)
if err := w.notifyInProcess(listener); err != nil {
utils.Logger.Error("failed to notify",
"error", err)
}
}()
}
}
@@ -238,11 +241,11 @@ func (w *Watcher) notifyInProcess(listener Listener) (err *utils.SourceError) {
w.forceRefresh = true
if w.refreshTimer != nil {
utils.Logger.Info("Found existing timer running, resetting")
w.refreshTimer.Reset(time.Millisecond * w.refreshTimerMS)
w.refreshTimer.Reset(w.refreshInterval)
shouldReturn = true
w.refreshChannelCount++
} else {
w.refreshTimer = time.NewTimer(time.Millisecond * w.refreshTimerMS)
w.refreshTimer = time.NewTimer(w.refreshInterval)
}
}()